summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/.gitignore2
l---------src/core/Makefile1
-rw-r--r--src/core/audit-fd.c73
-rw-r--r--src/core/audit-fd.h25
-rw-r--r--src/core/automount.c878
-rw-r--r--src/core/automount.h69
-rw-r--r--src/core/bus-endpoint.c134
-rw-r--r--src/core/bus-endpoint.h44
-rw-r--r--src/core/bus-policy.c174
-rw-r--r--src/core/bus-policy.h66
-rw-r--r--src/core/busname.c1066
-rw-r--r--src/core/busname.h84
-rw-r--r--src/core/cgroup.c1136
-rw-r--r--src/core/cgroup.h134
-rw-r--r--src/core/dbus-automount.c34
-rw-r--r--src/core/dbus-automount.h25
-rw-r--r--src/core/dbus-busname.c38
-rw-r--r--src/core/dbus-busname.h25
-rw-r--r--src/core/dbus-cgroup.c680
-rw-r--r--src/core/dbus-cgroup.h29
-rw-r--r--src/core/dbus-device.c30
-rw-r--r--src/core/dbus-device.h26
-rw-r--r--src/core/dbus-execute.c1006
-rw-r--r--src/core/dbus-execute.h46
-rw-r--r--src/core/dbus-job.c193
-rw-r--r--src/core/dbus-job.h32
-rw-r--r--src/core/dbus-kill.c123
-rw-r--r--src/core/dbus-kill.h30
-rw-r--r--src/core/dbus-manager.c2157
-rw-r--r--src/core/dbus-manager.h30
-rw-r--r--src/core/dbus-mount.c212
-rw-r--r--src/core/dbus-mount.h30
-rw-r--r--src/core/dbus-path.c87
-rw-r--r--src/core/dbus-path.h26
-rw-r--r--src/core/dbus-scope.c231
-rw-r--r--src/core/dbus-scope.h32
-rw-r--r--src/core/dbus-service.c266
-rw-r--r--src/core/dbus-service.h30
-rw-r--r--src/core/dbus-slice.c54
-rw-r--r--src/core/dbus-slice.h30
-rw-r--r--src/core/dbus-snapshot.c56
-rw-r--r--src/core/dbus-snapshot.h28
-rw-r--r--src/core/dbus-socket.c159
-rw-r--r--src/core/dbus-socket.h30
-rw-r--r--src/core/dbus-swap.c116
-rw-r--r--src/core/dbus-swap.h31
-rw-r--r--src/core/dbus-target.c28
-rw-r--r--src/core/dbus-target.h25
-rw-r--r--src/core/dbus-timer.c326
-rw-r--r--src/core/dbus-timer.h29
-rw-r--r--src/core/dbus-unit.c1109
-rw-r--r--src/core/dbus-unit.h39
-rw-r--r--src/core/dbus.c1214
-rw-r--r--src/core/dbus.h43
-rw-r--r--src/core/device.c813
-rw-r--r--src/core/device.h63
-rw-r--r--src/core/execute.c2912
-rw-r--r--src/core/execute.h267
-rw-r--r--src/core/failure-action.c139
-rw-r--r--src/core/failure-action.h43
-rw-r--r--src/core/hostname-setup.c88
-rw-r--r--src/core/hostname-setup.h24
-rw-r--r--src/core/ima-setup.c74
-rw-r--r--src/core/ima-setup.h26
-rw-r--r--src/core/job.c1238
-rw-r--r--src/core/job.h237
-rw-r--r--src/core/kill.c66
-rw-r--r--src/core/kill.h64
-rw-r--r--src/core/killall.c225
-rw-r--r--src/core/killall.h24
-rw-r--r--src/core/kmod-setup.c126
-rw-r--r--src/core/kmod-setup.h24
-rw-r--r--src/core/load-dropin.c82
-rw-r--r--src/core/load-dropin.h36
-rw-r--r--src/core/load-fragment-gperf.gperf.m4360
-rw-r--r--src/core/load-fragment.c3771
-rw-r--r--src/core/load-fragment.h116
-rw-r--r--src/core/locale-setup.c125
-rw-r--r--src/core/locale-setup.h24
-rw-r--r--src/core/loopback-setup.c91
-rw-r--r--src/core/loopback-setup.h24
-rw-r--r--src/core/machine-id-setup.c361
-rw-r--r--src/core/machine-id-setup.h25
-rw-r--r--src/core/macros.systemd.in109
-rw-r--r--src/core/main.c2036
-rw-r--r--src/core/manager.c3155
-rw-r--r--src/core/manager.h368
-rw-r--r--src/core/mount-setup.c399
-rw-r--r--src/core/mount-setup.h32
-rw-r--r--src/core/mount.c1947
-rw-r--r--src/core/mount.h132
-rw-r--r--src/core/namespace.c702
-rw-r--r--src/core/namespace.h65
-rw-r--r--src/core/org.freedesktop.systemd1.conf212
-rw-r--r--src/core/org.freedesktop.systemd1.policy.in.in70
-rw-r--r--src/core/org.freedesktop.systemd1.service11
-rw-r--r--src/core/path.c789
-rw-r--r--src/core/path.h106
-rw-r--r--src/core/scope.c561
-rw-r--r--src/core/scope.h71
-rw-r--r--src/core/selinux-access.c279
-rw-r--r--src/core/selinux-access.h50
-rw-r--r--src/core/selinux-setup.c123
-rw-r--r--src/core/selinux-setup.h26
-rw-r--r--src/core/service.c3212
-rw-r--r--src/core/service.h242
-rw-r--r--src/core/show-status.c42
-rw-r--r--src/core/show-status.h34
-rw-r--r--src/core/shutdown.c412
-rw-r--r--src/core/slice.c305
-rw-r--r--src/core/slice.h45
-rw-r--r--src/core/smack-setup.c167
-rw-r--r--src/core/smack-setup.h26
-rw-r--r--src/core/snapshot.c312
-rw-r--r--src/core/snapshot.h48
-rw-r--r--src/core/socket.c2740
-rw-r--r--src/core/socket.h194
-rw-r--r--src/core/swap.c1522
-rw-r--r--src/core/swap.h130
-rw-r--r--src/core/system.conf57
-rw-r--r--src/core/systemd.pc.in35
-rw-r--r--src/core/target.c236
-rw-r--r--src/core/target.h43
-rw-r--r--src/core/timer.c785
-rw-r--r--src/core/timer.h101
-rw-r--r--src/core/transaction.c1145
-rw-r--r--src/core/transaction.h54
-rw-r--r--src/core/umount.c594
-rw-r--r--src/core/umount.h30
-rw-r--r--src/core/unit-printf.c446
-rw-r--r--src/core/unit-printf.h28
-rw-r--r--src/core/unit.c3679
-rw-r--r--src/core/unit.h625
-rw-r--r--src/core/user.conf44
134 files changed, 0 insertions, 52665 deletions
diff --git a/src/core/.gitignore b/src/core/.gitignore
deleted file mode 100644
index f293bbdc9..000000000
--- a/src/core/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-/macros.systemd
-/systemd.pc
diff --git a/src/core/Makefile b/src/core/Makefile
deleted file mode 120000
index d0b0e8e00..000000000
--- a/src/core/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/core/audit-fd.c b/src/core/audit-fd.c
deleted file mode 100644
index 5a18e263a..000000000
--- a/src/core/audit-fd.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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>
-#include "audit-fd.h"
-
-#ifdef HAVE_AUDIT
-
-#include <stdbool.h>
-#include <libaudit.h>
-
-#include "log.h"
-#include "util.h"
-
-static bool initialized = false;
-static int audit_fd;
-
-int get_audit_fd(void) {
-
- if (!initialized) {
- audit_fd = audit_open();
-
- if (audit_fd < 0) {
- if (errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT)
- log_error_errno(errno, "Failed to connect to audit log: %m");
-
- audit_fd = errno ? -errno : -EINVAL;
- }
-
- initialized = true;
- }
-
- return audit_fd;
-}
-
-void close_audit_fd(void) {
-
- if (initialized && audit_fd >= 0)
- safe_close(audit_fd);
-
- initialized = true;
- audit_fd = -ECONNRESET;
-}
-
-#else
-
-int get_audit_fd(void) {
- return -EAFNOSUPPORT;
-}
-
-void close_audit_fd(void) {
-}
-
-#endif
diff --git a/src/core/audit-fd.h b/src/core/audit-fd.h
deleted file mode 100644
index 8b58289dc..000000000
--- a/src/core/audit-fd.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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
deleted file mode 100644
index cec90cbb3..000000000
--- a/src/core/automount.c
+++ /dev/null
@@ -1,878 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 <limits.h>
-#include <sys/mount.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/epoll.h>
-#include <sys/stat.h>
-#include <linux/auto_fs4.h>
-#include <linux/auto_dev-ioctl.h>
-
-#include "unit.h"
-#include "automount.h"
-#include "mount.h"
-#include "unit-name.h"
-#include "special.h"
-#include "label.h"
-#include "mkdir.h"
-#include "path-util.h"
-#include "dbus-automount.h"
-#include "bus-util.h"
-#include "bus-error.h"
-
-static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = {
- [AUTOMOUNT_DEAD] = UNIT_INACTIVE,
- [AUTOMOUNT_WAITING] = UNIT_ACTIVE,
- [AUTOMOUNT_RUNNING] = UNIT_ACTIVE,
- [AUTOMOUNT_FAILED] = UNIT_FAILED
-};
-
-static int open_dev_autofs(Manager *m);
-static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata);
-
-static void automount_init(Unit *u) {
- Automount *a = AUTOMOUNT(u);
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
-
- a->pipe_fd = -1;
- a->directory_mode = 0755;
- UNIT(a)->ignore_on_isolate = true;
-}
-
-static void repeat_unmount(const char *path) {
- assert(path);
-
- for (;;) {
- /* If there are multiple mounts on a mount point, this
- * removes them all */
-
- if (umount2(path, MNT_DETACH) >= 0)
- continue;
-
- if (errno != EINVAL)
- log_error_errno(errno, "Failed to unmount: %m");
-
- break;
- }
-}
-
-static void unmount_autofs(Automount *a) {
- assert(a);
-
- if (a->pipe_fd < 0)
- return;
-
- automount_send_ready(a, -EHOSTDOWN);
-
- a->pipe_event_source = sd_event_source_unref(a->pipe_event_source);
- a->pipe_fd = safe_close(a->pipe_fd);
-
- /* If we reload/reexecute things we keep the mount point
- * around */
- if (a->where &&
- (UNIT(a)->manager->exit_code != MANAGER_RELOAD &&
- UNIT(a)->manager->exit_code != MANAGER_REEXECUTE))
- repeat_unmount(a->where);
-}
-
-static void automount_done(Unit *u) {
- Automount *a = AUTOMOUNT(u);
-
- assert(a);
-
- unmount_autofs(a);
-
- free(a->where);
- a->where = NULL;
-
- set_free(a->tokens);
- a->tokens = NULL;
-}
-
-static int automount_add_mount_links(Automount *a) {
- _cleanup_free_ char *parent = NULL;
- int r;
-
- assert(a);
-
- r = path_get_parent(a->where, &parent);
- if (r < 0)
- return r;
-
- return unit_require_mounts_for(UNIT(a), parent);
-}
-
-static int automount_add_default_dependencies(Automount *a) {
- int r;
-
- assert(a);
-
- if (UNIT(a)->manager->running_as != SYSTEMD_SYSTEM)
- return 0;
-
- r = unit_add_two_dependencies_by_name(UNIT(a), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-static int automount_verify(Automount *a) {
- bool b;
- _cleanup_free_ char *e = NULL;
- assert(a);
-
- if (UNIT(a)->load_state != UNIT_LOADED)
- return 0;
-
- if (path_equal(a->where, "/")) {
- log_unit_error(UNIT(a)->id, "Cannot have an automount unit for the root directory. Refusing.");
- return -EINVAL;
- }
-
- e = unit_name_from_path(a->where, ".automount");
- if (!e)
- return -ENOMEM;
-
- b = unit_has_name(UNIT(a), e);
-
- if (!b) {
- log_unit_error(UNIT(a)->id, "%s's Where setting doesn't match unit name. Refusing.", UNIT(a)->id);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int automount_load(Unit *u) {
- Automount *a = AUTOMOUNT(u);
- int r;
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
-
- /* Load a .automount file */
- r = unit_load_fragment_and_dropin_optional(u);
- if (r < 0)
- return r;
-
- if (u->load_state == UNIT_LOADED) {
- Unit *x;
-
- if (!a->where) {
- a->where = unit_name_to_path(u->id);
- if (!a->where)
- return -ENOMEM;
- }
-
- path_kill_slashes(a->where);
-
- r = unit_load_related_unit(u, ".mount", &x);
- if (r < 0)
- return r;
-
- r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true);
- if (r < 0)
- return r;
-
- r = automount_add_mount_links(a);
- if (r < 0)
- return r;
-
- if (UNIT(a)->default_dependencies) {
- r = automount_add_default_dependencies(a);
- if (r < 0)
- return r;
- }
- }
-
- return automount_verify(a);
-}
-
-static void automount_set_state(Automount *a, AutomountState state) {
- AutomountState old_state;
- assert(a);
-
- old_state = a->state;
- a->state = state;
-
- if (state != AUTOMOUNT_WAITING &&
- state != AUTOMOUNT_RUNNING)
- unmount_autofs(a);
-
- if (state != old_state)
- log_unit_debug(UNIT(a)->id,
- "%s changed %s -> %s",
- UNIT(a)->id,
- 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);
-}
-
-static int automount_coldplug(Unit *u, Hashmap *deferred_work) {
- Automount *a = AUTOMOUNT(u);
- int r;
-
- assert(a);
- assert(a->state == AUTOMOUNT_DEAD);
-
- if (a->deserialized_state != a->state) {
-
- r = open_dev_autofs(u->manager);
- if (r < 0)
- return r;
-
- if (a->deserialized_state == AUTOMOUNT_WAITING ||
- a->deserialized_state == AUTOMOUNT_RUNNING) {
-
- assert(a->pipe_fd >= 0);
-
- r = sd_event_add_io(u->manager->event, &a->pipe_event_source, a->pipe_fd, EPOLLIN, automount_dispatch_io, u);
- if (r < 0)
- return r;
- }
-
- automount_set_state(a, a->deserialized_state);
- }
-
- return 0;
-}
-
-static void automount_dump(Unit *u, FILE *f, const char *prefix) {
- Automount *a = AUTOMOUNT(u);
-
- assert(a);
-
- fprintf(f,
- "%sAutomount State: %s\n"
- "%sResult: %s\n"
- "%sWhere: %s\n"
- "%sDirectoryMode: %04o\n",
- prefix, automount_state_to_string(a->state),
- prefix, automount_result_to_string(a->result),
- prefix, a->where,
- prefix, a->directory_mode);
-}
-
-static void automount_enter_dead(Automount *a, AutomountResult f) {
- assert(a);
-
- if (f != AUTOMOUNT_SUCCESS)
- a->result = f;
-
- automount_set_state(a, a->result != AUTOMOUNT_SUCCESS ? AUTOMOUNT_FAILED : AUTOMOUNT_DEAD);
-}
-
-static int open_dev_autofs(Manager *m) {
- struct autofs_dev_ioctl param;
-
- assert(m);
-
- if (m->dev_autofs_fd >= 0)
- return m->dev_autofs_fd;
-
- label_fix("/dev/autofs", false, false);
-
- m->dev_autofs_fd = open("/dev/autofs", O_CLOEXEC|O_RDONLY);
- if (m->dev_autofs_fd < 0)
- return log_error_errno(errno, "Failed to open /dev/autofs: %m");
-
- init_autofs_dev_ioctl(&param);
- if (ioctl(m->dev_autofs_fd, AUTOFS_DEV_IOCTL_VERSION, &param) < 0) {
- m->dev_autofs_fd = safe_close(m->dev_autofs_fd);
- return -errno;
- }
-
- log_debug("Autofs kernel version %i.%i", param.ver_major, param.ver_minor);
-
- return m->dev_autofs_fd;
-}
-
-static int open_ioctl_fd(int dev_autofs_fd, const char *where, dev_t devid) {
- struct autofs_dev_ioctl *param;
- size_t l;
-
- assert(dev_autofs_fd >= 0);
- assert(where);
-
- l = sizeof(struct autofs_dev_ioctl) + strlen(where) + 1;
- param = alloca(l);
-
- init_autofs_dev_ioctl(param);
- param->size = l;
- param->ioctlfd = -1;
- param->openmount.devid = devid;
- strcpy(param->path, where);
-
- if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_OPENMOUNT, param) < 0)
- return -errno;
-
- if (param->ioctlfd < 0)
- return -EIO;
-
- fd_cloexec(param->ioctlfd, true);
- return param->ioctlfd;
-}
-
-static int autofs_protocol(int dev_autofs_fd, int ioctl_fd) {
- uint32_t major, minor;
- struct autofs_dev_ioctl param;
-
- assert(dev_autofs_fd >= 0);
- assert(ioctl_fd >= 0);
-
- init_autofs_dev_ioctl(&param);
- param.ioctlfd = ioctl_fd;
-
- if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_PROTOVER, &param) < 0)
- return -errno;
-
- major = param.protover.version;
-
- init_autofs_dev_ioctl(&param);
- param.ioctlfd = ioctl_fd;
-
- if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_PROTOSUBVER, &param) < 0)
- return -errno;
-
- minor = param.protosubver.sub_version;
-
- log_debug("Autofs protocol version %i.%i", major, minor);
- return 0;
-}
-
-static int autofs_set_timeout(int dev_autofs_fd, int ioctl_fd, time_t sec) {
- struct autofs_dev_ioctl param;
-
- assert(dev_autofs_fd >= 0);
- assert(ioctl_fd >= 0);
-
- init_autofs_dev_ioctl(&param);
- param.ioctlfd = ioctl_fd;
- param.timeout.timeout = sec;
-
- if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_TIMEOUT, &param) < 0)
- return -errno;
-
- return 0;
-}
-
-static int autofs_send_ready(int dev_autofs_fd, int ioctl_fd, uint32_t token, int status) {
- struct autofs_dev_ioctl param;
-
- assert(dev_autofs_fd >= 0);
- assert(ioctl_fd >= 0);
-
- init_autofs_dev_ioctl(&param);
- param.ioctlfd = ioctl_fd;
-
- if (status) {
- param.fail.token = token;
- param.fail.status = status;
- } else
- param.ready.token = token;
-
- if (ioctl(dev_autofs_fd, status ? AUTOFS_DEV_IOCTL_FAIL : AUTOFS_DEV_IOCTL_READY, &param) < 0)
- return -errno;
-
- return 0;
-}
-
-int automount_send_ready(Automount *a, int status) {
- _cleanup_close_ int ioctl_fd = -1;
- unsigned token;
- int r;
-
- assert(a);
- assert(status <= 0);
-
- if (set_isempty(a->tokens))
- return 0;
-
- ioctl_fd = open_ioctl_fd(UNIT(a)->manager->dev_autofs_fd, a->where, a->dev_id);
- if (ioctl_fd < 0)
- return ioctl_fd;
-
- if (status)
- log_unit_debug_errno(UNIT(a)->id, status, "Sending failure: %m");
- else
- log_unit_debug(UNIT(a)->id, "Sending success.");
-
- r = 0;
-
- /* Autofs thankfully does not hand out 0 as a token */
- while ((token = PTR_TO_UINT(set_steal_first(a->tokens)))) {
- int k;
-
- /* Autofs fun fact II:
- *
- * if you pass a positive status code here, the kernel will
- * freeze! Yay! */
-
- k = autofs_send_ready(UNIT(a)->manager->dev_autofs_fd,
- ioctl_fd,
- token,
- status);
- if (k < 0)
- r = k;
- }
-
- return r;
-}
-
-static void automount_enter_waiting(Automount *a) {
- _cleanup_close_ int ioctl_fd = -1;
- int p[2] = { -1, -1 };
- char name[sizeof("systemd-")-1 + DECIMAL_STR_MAX(pid_t) + 1];
- char options[sizeof("fd=,pgrp=,minproto=5,maxproto=5,direct")-1
- + DECIMAL_STR_MAX(int) + DECIMAL_STR_MAX(gid_t) + 1];
- bool mounted = false;
- int r, dev_autofs_fd;
- struct stat st;
-
- assert(a);
- assert(a->pipe_fd < 0);
- assert(a->where);
-
- if (a->tokens)
- set_clear(a->tokens);
-
- dev_autofs_fd = open_dev_autofs(UNIT(a)->manager);
- if (dev_autofs_fd < 0) {
- r = dev_autofs_fd;
- goto fail;
- }
-
- /* We knowingly ignore the results of this call */
- mkdir_p_label(a->where, 0555);
-
- warn_if_dir_nonempty(a->meta.id, a->where);
-
- if (pipe2(p, O_NONBLOCK|O_CLOEXEC) < 0) {
- r = -errno;
- goto fail;
- }
-
- xsprintf(options, "fd=%i,pgrp="PID_FMT",minproto=5,maxproto=5,direct", p[1], getpgrp());
- xsprintf(name, "systemd-"PID_FMT, getpid());
- if (mount(name, a->where, "autofs", 0, options) < 0) {
- r = -errno;
- goto fail;
- }
-
- mounted = true;
-
- p[1] = safe_close(p[1]);
-
- if (stat(a->where, &st) < 0) {
- r = -errno;
- goto fail;
- }
-
- ioctl_fd = open_ioctl_fd(dev_autofs_fd, a->where, st.st_dev);
- if (ioctl_fd < 0) {
- r = ioctl_fd;
- goto fail;
- }
-
- r = autofs_protocol(dev_autofs_fd, ioctl_fd);
- if (r < 0)
- goto fail;
-
- r = autofs_set_timeout(dev_autofs_fd, ioctl_fd, 300);
- if (r < 0)
- goto fail;
-
- /* Autofs fun fact:
- *
- * Unless we close the ioctl fd here, for some weird reason
- * the direct mount will not receive events from the
- * kernel. */
-
- r = sd_event_add_io(UNIT(a)->manager->event, &a->pipe_event_source, p[0], EPOLLIN, automount_dispatch_io, a);
- if (r < 0)
- goto fail;
-
- a->pipe_fd = p[0];
- a->dev_id = st.st_dev;
-
- automount_set_state(a, AUTOMOUNT_WAITING);
-
- return;
-
-fail:
- safe_close_pair(p);
-
- if (mounted)
- repeat_unmount(a->where);
-
- log_unit_error(UNIT(a)->id,
- "Failed to initialize automounter: %s", strerror(-r));
- automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
-}
-
-static void automount_enter_runnning(Automount *a) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- struct stat st;
- int r;
-
- assert(a);
-
- /* We don't take mount requests anymore if we are supposed to
- * shut down anyway */
- if (unit_stop_pending(UNIT(a))) {
- log_unit_debug(UNIT(a)->id,
- "Suppressing automount request on %s since unit stop is scheduled.", UNIT(a)->id);
- automount_send_ready(a, -EHOSTDOWN);
- return;
- }
-
- mkdir_p_label(a->where, a->directory_mode);
-
- /* Before we do anything, let's see if somebody is playing games with us? */
- if (lstat(a->where, &st) < 0) {
- log_unit_warning(UNIT(a)->id,
- "%s failed to stat automount point: %m", UNIT(a)->id);
- goto fail;
- }
-
- if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id)
- log_unit_info(UNIT(a)->id,
- "%s's automount point already active?", UNIT(a)->id);
- else {
- r = manager_add_job(UNIT(a)->manager, JOB_START, UNIT_TRIGGER(UNIT(a)),
- JOB_REPLACE, true, &error, NULL);
- if (r < 0) {
- log_unit_warning(UNIT(a)->id,
- "%s failed to queue mount startup job: %s",
- UNIT(a)->id, bus_error_message(&error, r));
- goto fail;
- }
- }
-
- automount_set_state(a, AUTOMOUNT_RUNNING);
- return;
-
-fail:
- automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
-}
-
-static int automount_start(Unit *u) {
- Automount *a = AUTOMOUNT(u);
-
- assert(a);
- assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_FAILED);
-
- if (path_is_mount_point(a->where, false)) {
- log_unit_error(u->id,
- "Path %s is already a mount point, refusing start for %s",
- a->where, u->id);
- return -EEXIST;
- }
-
- if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED)
- return -ENOENT;
-
- a->result = AUTOMOUNT_SUCCESS;
- automount_enter_waiting(a);
- return 1;
-}
-
-static int automount_stop(Unit *u) {
- Automount *a = AUTOMOUNT(u);
-
- assert(a);
- assert(a->state == AUTOMOUNT_WAITING || a->state == AUTOMOUNT_RUNNING);
-
- automount_enter_dead(a, AUTOMOUNT_SUCCESS);
- return 1;
-}
-
-static int automount_serialize(Unit *u, FILE *f, FDSet *fds) {
- Automount *a = AUTOMOUNT(u);
- void *p;
- Iterator i;
-
- assert(a);
- assert(f);
- assert(fds);
-
- unit_serialize_item(u, f, "state", automount_state_to_string(a->state));
- unit_serialize_item(u, f, "result", automount_result_to_string(a->result));
- unit_serialize_item_format(u, f, "dev-id", "%u", (unsigned) a->dev_id);
-
- SET_FOREACH(p, a->tokens, i)
- unit_serialize_item_format(u, f, "token", "%u", PTR_TO_UINT(p));
-
- if (a->pipe_fd >= 0) {
- int copy;
-
- copy = fdset_put_dup(fds, a->pipe_fd);
- if (copy < 0)
- return copy;
-
- unit_serialize_item_format(u, f, "pipe-fd", "%i", copy);
- }
-
- return 0;
-}
-
-static int automount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Automount *a = AUTOMOUNT(u);
- int r;
-
- assert(a);
- assert(fds);
-
- if (streq(key, "state")) {
- AutomountState state;
-
- state = automount_state_from_string(value);
- if (state < 0)
- log_unit_debug(u->id, "Failed to parse state value %s", value);
- else
- a->deserialized_state = state;
- } else if (streq(key, "result")) {
- AutomountResult f;
-
- f = automount_result_from_string(value);
- if (f < 0)
- log_unit_debug(u->id, "Failed to parse result value %s", value);
- else if (f != AUTOMOUNT_SUCCESS)
- a->result = f;
-
- } else if (streq(key, "dev-id")) {
- unsigned d;
-
- if (safe_atou(value, &d) < 0)
- log_unit_debug(u->id, "Failed to parse dev-id value %s", value);
- else
- a->dev_id = (unsigned) d;
- } else if (streq(key, "token")) {
- unsigned token;
-
- if (safe_atou(value, &token) < 0)
- log_unit_debug(u->id, "Failed to parse token value %s", value);
- else {
- if (!a->tokens)
- if (!(a->tokens = set_new(NULL)))
- return -ENOMEM;
-
- r = set_put(a->tokens, UINT_TO_PTR(token));
- if (r < 0)
- return r;
- }
- } else if (streq(key, "pipe-fd")) {
- int fd;
-
- if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u->id, "Failed to parse pipe-fd value %s", value);
- else {
- safe_close(a->pipe_fd);
- a->pipe_fd = fdset_remove(fds, fd);
- }
- } else
- log_unit_debug(u->id, "Unknown serialization key '%s'", key);
-
- return 0;
-}
-
-static UnitActiveState automount_active_state(Unit *u) {
- assert(u);
-
- return state_translation_table[AUTOMOUNT(u)->state];
-}
-
-static const char *automount_sub_state_to_string(Unit *u) {
- assert(u);
-
- return automount_state_to_string(AUTOMOUNT(u)->state);
-}
-
-static bool automount_check_gc(Unit *u) {
- assert(u);
-
- if (!UNIT_TRIGGER(u))
- return false;
-
- return UNIT_VTABLE(UNIT_TRIGGER(u))->check_gc(UNIT_TRIGGER(u));
-}
-
-static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, void *userdata) {
- union autofs_v5_packet_union packet;
- Automount *a = AUTOMOUNT(userdata);
- int r;
-
- assert(a);
- assert(fd == a->pipe_fd);
-
- if (events != EPOLLIN) {
- log_unit_error(UNIT(a)->id, "Got invalid poll event on pipe.");
- goto fail;
- }
-
- r = loop_read_exact(a->pipe_fd, &packet, sizeof(packet), true);
- if (r < 0) {
- log_unit_error_errno(UNIT(a)->id, r, "Invalid read from pipe: %m");
- goto fail;
- }
-
- switch (packet.hdr.type) {
-
- case autofs_ptype_missing_direct:
-
- if (packet.v5_packet.pid > 0) {
- _cleanup_free_ char *p = NULL;
-
- get_process_comm(packet.v5_packet.pid, &p);
- log_unit_info(UNIT(a)->id,
- "Got automount request for %s, triggered by %"PRIu32" (%s)",
- a->where, packet.v5_packet.pid, strna(p));
- } else
- log_unit_debug(UNIT(a)->id, "Got direct mount request on %s", a->where);
-
- r = set_ensure_allocated(&a->tokens, NULL);
- if (r < 0) {
- log_unit_error(UNIT(a)->id, "Failed to allocate token set.");
- goto fail;
- }
-
- r = set_put(a->tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token));
- if (r < 0) {
- log_unit_error_errno(UNIT(a)->id, r, "Failed to remember token: %m");
- goto fail;
- }
-
- automount_enter_runnning(a);
- break;
-
- default:
- log_unit_error(UNIT(a)->id, "Received unknown automount request %i", packet.hdr.type);
- break;
- }
-
- return 0;
-
-fail:
- automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
- return 0;
-}
-
-static void automount_shutdown(Manager *m) {
- assert(m);
-
- m->dev_autofs_fd = safe_close(m->dev_autofs_fd);
-}
-
-static void automount_reset_failed(Unit *u) {
- Automount *a = AUTOMOUNT(u);
-
- assert(a);
-
- if (a->state == AUTOMOUNT_FAILED)
- automount_set_state(a, AUTOMOUNT_DEAD);
-
- a->result = AUTOMOUNT_SUCCESS;
-}
-
-static bool automount_supported(Manager *m) {
- static int supported = -1;
-
- assert(m);
-
- if (supported < 0)
- supported = access("/dev/autofs", F_OK) >= 0;
-
- return supported;
-}
-
-static const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = {
- [AUTOMOUNT_DEAD] = "dead",
- [AUTOMOUNT_WAITING] = "waiting",
- [AUTOMOUNT_RUNNING] = "running",
- [AUTOMOUNT_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState);
-
-static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = {
- [AUTOMOUNT_SUCCESS] = "success",
- [AUTOMOUNT_FAILURE_RESOURCES] = "resources"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(automount_result, AutomountResult);
-
-const UnitVTable automount_vtable = {
- .object_size = sizeof(Automount),
-
- .sections =
- "Unit\0"
- "Automount\0"
- "Install\0",
-
- .no_alias = true,
- .no_instances = true,
-
- .init = automount_init,
- .load = automount_load,
- .done = automount_done,
-
- .coldplug = automount_coldplug,
-
- .dump = automount_dump,
-
- .start = automount_start,
- .stop = automount_stop,
-
- .serialize = automount_serialize,
- .deserialize_item = automount_deserialize_item,
-
- .active_state = automount_active_state,
- .sub_state_to_string = automount_sub_state_to_string,
-
- .check_gc = automount_check_gc,
-
- .reset_failed = automount_reset_failed,
-
- .bus_interface = "org.freedesktop.systemd1.Automount",
- .bus_vtable = bus_automount_vtable,
-
- .shutdown = automount_shutdown,
- .supported = automount_supported,
-
- .status_message_formats = {
- .finished_start_job = {
- [JOB_DONE] = "Set up automount %s.",
- [JOB_FAILED] = "Failed to set up automount %s.",
- [JOB_DEPENDENCY] = "Dependency failed for %s.",
- },
- .finished_stop_job = {
- [JOB_DONE] = "Unset automount %s.",
- [JOB_FAILED] = "Failed to unset automount %s.",
- },
- },
-};
diff --git a/src/core/automount.h b/src/core/automount.h
deleted file mode 100644
index 60f552238..000000000
--- a/src/core/automount.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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"
-
-typedef enum AutomountState {
- AUTOMOUNT_DEAD,
- AUTOMOUNT_WAITING,
- AUTOMOUNT_RUNNING,
- AUTOMOUNT_FAILED,
- _AUTOMOUNT_STATE_MAX,
- _AUTOMOUNT_STATE_INVALID = -1
-} AutomountState;
-
-typedef enum AutomountResult {
- AUTOMOUNT_SUCCESS,
- AUTOMOUNT_FAILURE_RESOURCES,
- _AUTOMOUNT_RESULT_MAX,
- _AUTOMOUNT_RESULT_INVALID = -1
-} AutomountResult;
-
-struct Automount {
- Unit meta;
-
- AutomountState state, deserialized_state;
-
- char *where;
-
- int pipe_fd;
- sd_event_source *pipe_event_source;
- mode_t directory_mode;
- dev_t dev_id;
-
- Set *tokens;
-
- AutomountResult result;
-};
-
-extern const UnitVTable automount_vtable;
-
-int automount_send_ready(Automount *a, int status);
-
-const char* automount_state_to_string(AutomountState i) _const_;
-AutomountState automount_state_from_string(const char *s) _pure_;
-
-const char* automount_result_to_string(AutomountResult i) _const_;
-AutomountResult automount_result_from_string(const char *s) _pure_;
diff --git a/src/core/bus-endpoint.c b/src/core/bus-endpoint.c
deleted file mode 100644
index 0c4b3e7c8..000000000
--- a/src/core/bus-endpoint.c
+++ /dev/null
@@ -1,134 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2014 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 <stdlib.h>
-
-#include "kdbus.h"
-#include "bus-kernel.h"
-#include "bus-policy.h"
-#include "bus-endpoint.h"
-
-int bus_kernel_set_endpoint_policy(int fd, uid_t uid, BusEndpoint *ep) {
-
- struct kdbus_cmd *update;
- struct kdbus_item *n;
- BusEndpointPolicy *po;
- Iterator i;
- size_t size;
- int r;
-
- size = ALIGN8(offsetof(struct kdbus_cmd, items));
-
- HASHMAP_FOREACH(po, ep->policy_hash, i) {
- size += ALIGN8(offsetof(struct kdbus_item, str) + strlen(po->name) + 1);
- size += ALIGN8(offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access));
- }
-
- update = alloca0_align(size, 8);
- update->size = size;
-
- n = update->items;
-
- HASHMAP_FOREACH(po, ep->policy_hash, i) {
- n->type = KDBUS_ITEM_NAME;
- n->size = offsetof(struct kdbus_item, str) + strlen(po->name) + 1;
- strcpy(n->str, po->name);
- n = KDBUS_ITEM_NEXT(n);
-
- n->type = KDBUS_ITEM_POLICY_ACCESS;
- n->size = offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access);
-
- n->policy_access.type = KDBUS_POLICY_ACCESS_USER;
- n->policy_access.access = bus_kernel_translate_access(po->access);
- n->policy_access.id = uid;
-
- n = KDBUS_ITEM_NEXT(n);
- }
-
- r = ioctl(fd, KDBUS_CMD_ENDPOINT_UPDATE, update);
- if (r < 0)
- return -errno;
-
- return 0;
-}
-
-int bus_endpoint_new(BusEndpoint **ep) {
- assert(ep);
-
- *ep = new0(BusEndpoint, 1);
- if (!*ep)
- return -ENOMEM;
-
- return 0;
-}
-
-int bus_endpoint_add_policy(BusEndpoint *ep, const char *name, BusPolicyAccess access) {
- _cleanup_free_ BusEndpointPolicy *po = NULL;
- _cleanup_free_ char *key = NULL;
- int r;
-
- assert(ep);
- assert(name);
- assert(access > _BUS_POLICY_ACCESS_INVALID && access < _BUS_POLICY_ACCESS_MAX);
-
- /* check if we already have this name in the policy list. If we do, see if the new access level
- * is higher than the exising one, and upgrade the entry in that case. Otherwise, do nothing.
- */
-
- if (ep->policy_hash) {
- po = hashmap_get(ep->policy_hash, name);
- if (po) {
- if (po->access < access)
- po->access = access;
-
- return 0;
- }
- } else {
- ep->policy_hash = hashmap_new(&string_hash_ops);
- if (!ep->policy_hash)
- return -ENOMEM;
- }
-
- po = new0(BusEndpointPolicy, 1);
- if (!po)
- return -ENOMEM;
-
- key = strdup(name);
- if (!key)
- return -ENOMEM;
-
- po->name = key;
- po->access = access;
-
- r = hashmap_put(ep->policy_hash, key, po);
- if (r < 0)
- return r;
-
- po = NULL;
- key = NULL;
- return 0;
-}
-
-void bus_endpoint_free(BusEndpoint *endpoint) {
- if (!endpoint)
- return;
-
- hashmap_free_free_free(endpoint->policy_hash);
- free(endpoint);
-}
diff --git a/src/core/bus-endpoint.h b/src/core/bus-endpoint.h
deleted file mode 100644
index 4a31f4c4b..000000000
--- a/src/core/bus-endpoint.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2014 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/>.
-***/
-
-typedef struct BusEndpoint BusEndpoint;
-typedef struct BusEndpointPolicy BusEndpointPolicy;
-
-#include "hashmap.h"
-#include "bus-policy.h"
-
-struct BusEndpointPolicy {
- char *name;
- BusPolicyAccess access;
-};
-
-struct BusEndpoint {
- Hashmap *policy_hash;
-};
-
-int bus_endpoint_new(BusEndpoint **ep);
-void bus_endpoint_free(BusEndpoint *endpoint);
-
-int bus_endpoint_add_policy(BusEndpoint *ep, const char *name, BusPolicyAccess access);
-
-int bus_kernel_set_endpoint_policy(int fd, uid_t uid, BusEndpoint *ep);
diff --git a/src/core/bus-policy.c b/src/core/bus-policy.c
deleted file mode 100644
index 064eee1c8..000000000
--- a/src/core/bus-policy.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2014 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 <stdlib.h>
-
-#include "kdbus.h"
-#include "util.h"
-#include "bus-kernel.h"
-#include "bus-policy.h"
-
-int bus_kernel_translate_access(BusPolicyAccess access) {
- assert(access >= 0);
- assert(access < _BUS_POLICY_ACCESS_MAX);
-
- switch (access) {
-
- case BUS_POLICY_ACCESS_SEE:
- return KDBUS_POLICY_SEE;
-
- case BUS_POLICY_ACCESS_TALK:
- return KDBUS_POLICY_TALK;
-
- case BUS_POLICY_ACCESS_OWN:
- return KDBUS_POLICY_OWN;
-
- default:
- assert_not_reached("Unknown policy access");
- }
-}
-
-int bus_kernel_translate_policy(const BusNamePolicy *policy, struct kdbus_item *item) {
- int r;
-
- assert(policy);
- assert(item);
-
- switch (policy->type) {
-
- case BUSNAME_POLICY_TYPE_USER: {
- const char *user = policy->name;
- uid_t uid;
-
- r = get_user_creds(&user, &uid, NULL, NULL, NULL);
- if (r < 0)
- return r;
-
- item->policy_access.type = KDBUS_POLICY_ACCESS_USER;
- item->policy_access.id = uid;
- break;
- }
-
- case BUSNAME_POLICY_TYPE_GROUP: {
- const char *group = policy->name;
- gid_t gid;
-
- r = get_group_creds(&group, &gid);
- if (r < 0)
- return r;
-
- item->policy_access.type = KDBUS_POLICY_ACCESS_GROUP;
- item->policy_access.id = gid;
- break;
- }
-
- default:
- assert_not_reached("Unknown policy type");
- }
-
- item->policy_access.access = bus_kernel_translate_access(policy->access);
-
- return 0;
-}
-
-int bus_kernel_make_starter(
- int fd,
- const char *name,
- bool activating,
- bool accept_fd,
- BusNamePolicy *policy,
- BusPolicyAccess world_policy) {
-
- struct kdbus_cmd_free cmd_free = { .size = sizeof(cmd_free) };
- struct kdbus_cmd_hello *hello;
- struct kdbus_item *n;
- size_t policy_cnt = 0;
- BusNamePolicy *po;
- size_t size;
- int r;
-
- assert(fd >= 0);
- assert(name);
-
- LIST_FOREACH(policy, po, policy)
- policy_cnt++;
-
- if (world_policy >= 0)
- policy_cnt++;
-
- size = offsetof(struct kdbus_cmd_hello, items) +
- ALIGN8(offsetof(struct kdbus_item, str) + strlen(name) + 1) +
- policy_cnt * ALIGN8(offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access));
-
- hello = alloca0_align(size, 8);
-
- n = hello->items;
- strcpy(n->str, name);
- n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1;
- n->type = KDBUS_ITEM_NAME;
- n = KDBUS_ITEM_NEXT(n);
-
- LIST_FOREACH(policy, po, policy) {
- n->type = KDBUS_ITEM_POLICY_ACCESS;
- n->size = offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access);
-
- r = bus_kernel_translate_policy(po, n);
- if (r < 0)
- return r;
-
- n = KDBUS_ITEM_NEXT(n);
- }
-
- if (world_policy >= 0) {
- n->type = KDBUS_ITEM_POLICY_ACCESS;
- n->size = offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access);
- n->policy_access.type = KDBUS_POLICY_ACCESS_WORLD;
- n->policy_access.access = bus_kernel_translate_access(world_policy);
- }
-
- hello->size = size;
- hello->flags =
- (activating ? KDBUS_HELLO_ACTIVATOR : KDBUS_HELLO_POLICY_HOLDER) |
- (accept_fd ? KDBUS_HELLO_ACCEPT_FD : 0);
- hello->pool_size = KDBUS_POOL_SIZE;
- hello->attach_flags_send = _KDBUS_ATTACH_ANY;
- hello->attach_flags_recv = _KDBUS_ATTACH_ANY;
-
- if (ioctl(fd, KDBUS_CMD_HELLO, hello) < 0)
- return -errno;
-
- /* not interested in any output values */
- cmd_free.offset = hello->offset;
- (void) ioctl(fd, KDBUS_CMD_FREE, &cmd_free);
-
- /* The higher 32bit of the bus_flags fields are considered
- * 'incompatible flags'. Refuse them all for now. */
- if (hello->bus_flags > 0xFFFFFFFFULL)
- return -EOPNOTSUPP;
-
- return fd;
-}
-
-static const char* const bus_policy_access_table[_BUS_POLICY_ACCESS_MAX] = {
- [BUS_POLICY_ACCESS_SEE] = "see",
- [BUS_POLICY_ACCESS_TALK] = "talk",
- [BUS_POLICY_ACCESS_OWN] = "own",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(bus_policy_access, BusPolicyAccess);
diff --git a/src/core/bus-policy.h b/src/core/bus-policy.h
deleted file mode 100644
index 3b04f5457..000000000
--- a/src/core/bus-policy.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2014 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 "list.h"
-#include "macro.h"
-#include "kdbus.h"
-
-typedef struct BusNamePolicy BusNamePolicy;
-
-typedef enum BusPolicyAccess {
- BUS_POLICY_ACCESS_SEE,
- BUS_POLICY_ACCESS_TALK,
- BUS_POLICY_ACCESS_OWN,
- _BUS_POLICY_ACCESS_MAX,
- _BUS_POLICY_ACCESS_INVALID = -1
-} BusPolicyAccess;
-
-typedef enum BusNamePolicyType {
- BUSNAME_POLICY_TYPE_USER,
- BUSNAME_POLICY_TYPE_GROUP,
- _BUSNAME_POLICY_TYPE_MAX,
- _BUSNAME_POLICY_TYPE_INVALID = -1
-} BusNamePolicyType;
-
-struct BusNamePolicy {
- BusNamePolicyType type;
- BusPolicyAccess access;
-
- char *name;
-
- LIST_FIELDS(BusNamePolicy, policy);
-};
-
-int bus_kernel_translate_access(BusPolicyAccess access);
-int bus_kernel_translate_policy(const BusNamePolicy *policy, struct kdbus_item *item);
-
-const char* bus_policy_access_to_string(BusPolicyAccess i) _const_;
-BusPolicyAccess bus_policy_access_from_string(const char *s) _pure_;
-
-int bus_kernel_make_starter(
- int fd,
- const char *name,
- bool activating,
- bool accept_fd,
- BusNamePolicy *policy,
- BusPolicyAccess world_policy);
diff --git a/src/core/busname.c b/src/core/busname.c
deleted file mode 100644
index 43d7607a3..000000000
--- a/src/core/busname.c
+++ /dev/null
@@ -1,1066 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 <sys/mman.h>
-
-#include "special.h"
-#include "bus-kernel.h"
-#include "bus-internal.h"
-#include "bus-util.h"
-#include "service.h"
-#include "kdbus.h"
-#include "bus-policy.h"
-#include "dbus-busname.h"
-#include "busname.h"
-
-static const UnitActiveState state_translation_table[_BUSNAME_STATE_MAX] = {
- [BUSNAME_DEAD] = UNIT_INACTIVE,
- [BUSNAME_MAKING] = UNIT_ACTIVATING,
- [BUSNAME_REGISTERED] = UNIT_ACTIVE,
- [BUSNAME_LISTENING] = UNIT_ACTIVE,
- [BUSNAME_RUNNING] = UNIT_ACTIVE,
- [BUSNAME_SIGTERM] = UNIT_DEACTIVATING,
- [BUSNAME_SIGKILL] = UNIT_DEACTIVATING,
- [BUSNAME_FAILED] = UNIT_FAILED
-};
-
-static int busname_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
-static int busname_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
-
-static void busname_init(Unit *u) {
- BusName *n = BUSNAME(u);
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
-
- n->starter_fd = -1;
- n->accept_fd = true;
- n->activating = true;
-
- n->timeout_usec = u->manager->default_timeout_start_usec;
-}
-
-static void busname_unwatch_control_pid(BusName *n) {
- assert(n);
-
- if (n->control_pid <= 0)
- return;
-
- unit_unwatch_pid(UNIT(n), n->control_pid);
- n->control_pid = 0;
-}
-
-static void busname_free_policy(BusName *n) {
- BusNamePolicy *p;
-
- assert(n);
-
- while ((p = n->policy)) {
- LIST_REMOVE(policy, n->policy, p);
-
- free(p->name);
- free(p);
- }
-}
-
-static void busname_close_fd(BusName *n) {
- assert(n);
-
- n->starter_event_source = sd_event_source_unref(n->starter_event_source);
- n->starter_fd = safe_close(n->starter_fd);
-}
-
-static void busname_done(Unit *u) {
- BusName *n = BUSNAME(u);
-
- assert(n);
-
- free(n->name);
- n->name = NULL;
-
- busname_free_policy(n);
- busname_unwatch_control_pid(n);
- busname_close_fd(n);
-
- unit_ref_unset(&n->service);
-
- n->timer_event_source = sd_event_source_unref(n->timer_event_source);
-}
-
-static int busname_arm_timer(BusName *n) {
- int r;
-
- assert(n);
-
- if (n->timeout_usec <= 0) {
- n->timer_event_source = sd_event_source_unref(n->timer_event_source);
- return 0;
- }
-
- if (n->timer_event_source) {
- r = sd_event_source_set_time(n->timer_event_source, now(CLOCK_MONOTONIC) + n->timeout_usec);
- if (r < 0)
- return r;
-
- return sd_event_source_set_enabled(n->timer_event_source, SD_EVENT_ONESHOT);
- }
-
- return sd_event_add_time(
- UNIT(n)->manager->event,
- &n->timer_event_source,
- CLOCK_MONOTONIC,
- now(CLOCK_MONOTONIC) + n->timeout_usec, 0,
- busname_dispatch_timer, n);
-}
-
-static int busname_add_default_default_dependencies(BusName *n) {
- int r;
-
- assert(n);
-
- r = unit_add_dependency_by_name(UNIT(n), UNIT_BEFORE, SPECIAL_BUSNAMES_TARGET, NULL, true);
- if (r < 0)
- return r;
-
- if (UNIT(n)->manager->running_as == SYSTEMD_SYSTEM) {
- r = unit_add_two_dependencies_by_name(UNIT(n), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
- if (r < 0)
- return r;
- }
-
- return unit_add_two_dependencies_by_name(UNIT(n), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
-}
-
-static int busname_add_extras(BusName *n) {
- Unit *u = UNIT(n);
- int r;
-
- assert(n);
-
- if (!n->name) {
- n->name = unit_name_to_prefix(u->id);
- if (!n->name)
- return -ENOMEM;
- }
-
- if (!u->description) {
- r = unit_set_description(u, n->name);
- if (r < 0)
- return r;
- }
-
- if (n->activating) {
- if (!UNIT_DEREF(n->service)) {
- Unit *x;
-
- r = unit_load_related_unit(u, ".service", &x);
- if (r < 0)
- return r;
-
- unit_ref_set(&n->service, x);
- }
-
- r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(n->service), true);
- if (r < 0)
- return r;
- }
-
- if (u->default_dependencies) {
- r = busname_add_default_default_dependencies(n);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-static int busname_verify(BusName *n) {
- char *e;
-
- assert(n);
-
- if (UNIT(n)->load_state != UNIT_LOADED)
- return 0;
-
- if (!service_name_is_valid(n->name)) {
- log_unit_error(UNIT(n)->id, "%s's Name= setting is not a valid service name Refusing.", UNIT(n)->id);
- return -EINVAL;
- }
-
- e = strjoina(n->name, ".busname");
- if (!unit_has_name(UNIT(n), e)) {
- log_unit_error(UNIT(n)->id, "%s's Name= setting doesn't match unit name. Refusing.", UNIT(n)->id);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int busname_load(Unit *u) {
- BusName *n = BUSNAME(u);
- int r;
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
-
- r = unit_load_fragment_and_dropin(u);
- if (r < 0)
- return r;
-
- if (u->load_state == UNIT_LOADED) {
- /* This is a new unit? Then let's add in some extras */
- r = busname_add_extras(n);
- if (r < 0)
- return r;
- }
-
- return busname_verify(n);
-}
-
-static void busname_dump(Unit *u, FILE *f, const char *prefix) {
- BusName *n = BUSNAME(u);
-
- assert(n);
- assert(f);
-
- fprintf(f,
- "%sBus Name State: %s\n"
- "%sResult: %s\n"
- "%sName: %s\n"
- "%sActivating: %s\n"
- "%sAccept FD: %s\n",
- prefix, busname_state_to_string(n->state),
- prefix, busname_result_to_string(n->result),
- prefix, n->name,
- prefix, yes_no(n->activating),
- prefix, yes_no(n->accept_fd));
-
- if (n->control_pid > 0)
- fprintf(f,
- "%sControl PID: "PID_FMT"\n",
- prefix, n->control_pid);
-}
-
-static void busname_unwatch_fd(BusName *n) {
- int r;
-
- assert(n);
-
- if (!n->starter_event_source)
- return;
-
- r = sd_event_source_set_enabled(n->starter_event_source, SD_EVENT_OFF);
- if (r < 0)
- log_unit_debug(UNIT(n)->id, "Failed to disable event source.");
-}
-
-static int busname_watch_fd(BusName *n) {
- int r;
-
- assert(n);
-
- if (n->starter_fd < 0)
- return 0;
-
- if (n->starter_event_source)
- r = sd_event_source_set_enabled(n->starter_event_source, SD_EVENT_ON);
- else
- r = sd_event_add_io(UNIT(n)->manager->event, &n->starter_event_source, n->starter_fd, EPOLLIN, busname_dispatch_io, n);
- if (r < 0) {
- log_unit_warning_errno(UNIT(n)->id, r, "Failed to watch starter fd: %m");
- busname_unwatch_fd(n);
- return r;
- }
-
- return 0;
-}
-
-static int busname_open_fd(BusName *n) {
- _cleanup_free_ char *path = NULL;
- const char *mode;
-
- assert(n);
-
- if (n->starter_fd >= 0)
- return 0;
-
- mode = UNIT(n)->manager->running_as == SYSTEMD_SYSTEM ? "system" : "user";
- n->starter_fd = bus_kernel_open_bus_fd(mode, &path);
- if (n->starter_fd < 0)
- return log_unit_warning_errno(UNIT(n)->id, n->starter_fd, "Failed to open %s: %m", path ?: "kdbus");
-
- return 0;
-}
-
-static void busname_set_state(BusName *n, BusNameState state) {
- BusNameState old_state;
- assert(n);
-
- old_state = n->state;
- n->state = state;
-
- if (!IN_SET(state, BUSNAME_MAKING, BUSNAME_SIGTERM, BUSNAME_SIGKILL)) {
- n->timer_event_source = sd_event_source_unref(n->timer_event_source);
- busname_unwatch_control_pid(n);
- }
-
- if (state != BUSNAME_LISTENING)
- busname_unwatch_fd(n);
-
- if (!IN_SET(state, BUSNAME_LISTENING, BUSNAME_MAKING, BUSNAME_REGISTERED, BUSNAME_RUNNING))
- busname_close_fd(n);
-
- if (state != old_state)
- log_unit_debug(UNIT(n)->id, "%s changed %s -> %s",
- UNIT(n)->id, busname_state_to_string(old_state), busname_state_to_string(state));
-
- unit_notify(UNIT(n), state_translation_table[old_state], state_translation_table[state], true);
-}
-
-static int busname_coldplug(Unit *u, Hashmap *deferred_work) {
- BusName *n = BUSNAME(u);
- int r;
-
- assert(n);
- assert(n->state == BUSNAME_DEAD);
-
- if (n->deserialized_state == n->state)
- return 0;
-
- if (IN_SET(n->deserialized_state, BUSNAME_MAKING, BUSNAME_SIGTERM, BUSNAME_SIGKILL)) {
-
- if (n->control_pid <= 0)
- return -EBADMSG;
-
- r = unit_watch_pid(UNIT(n), n->control_pid);
- if (r < 0)
- return r;
-
- r = busname_arm_timer(n);
- if (r < 0)
- return r;
- }
-
- if (IN_SET(n->deserialized_state, BUSNAME_MAKING, BUSNAME_LISTENING, BUSNAME_REGISTERED, BUSNAME_RUNNING)) {
- r = busname_open_fd(n);
- if (r < 0)
- return r;
- }
-
- if (n->deserialized_state == BUSNAME_LISTENING) {
- r = busname_watch_fd(n);
- if (r < 0)
- return r;
- }
-
- busname_set_state(n, n->deserialized_state);
- return 0;
-}
-
-static int busname_make_starter(BusName *n, pid_t *_pid) {
- pid_t pid;
- int r;
-
- r = busname_arm_timer(n);
- if (r < 0)
- goto fail;
-
- /* We have to resolve the user/group names out-of-process,
- * hence let's fork here. It's messy, but well, what can we
- * do? */
-
- pid = fork();
- if (pid < 0)
- return -errno;
-
- if (pid == 0) {
- int ret;
-
- default_signals(SIGNALS_CRASH_HANDLER, SIGNALS_IGNORE, -1);
- ignore_signals(SIGPIPE, -1);
- log_forget_fds();
-
- r = bus_kernel_make_starter(n->starter_fd, n->name, n->activating, n->accept_fd, n->policy, n->policy_world);
- if (r < 0) {
- ret = EXIT_MAKE_STARTER;
- goto fail_child;
- }
-
- _exit(0);
-
- fail_child:
- log_open();
- log_error_errno(r, "Failed to create starter connection at step %s: %m", exit_status_to_string(ret, EXIT_STATUS_SYSTEMD));
-
- _exit(ret);
- }
-
- r = unit_watch_pid(UNIT(n), pid);
- if (r < 0)
- goto fail;
-
- *_pid = pid;
- return 0;
-
-fail:
- n->timer_event_source = sd_event_source_unref(n->timer_event_source);
- return r;
-}
-
-static void busname_enter_dead(BusName *n, BusNameResult f) {
- assert(n);
-
- if (f != BUSNAME_SUCCESS)
- n->result = f;
-
- busname_set_state(n, n->result != BUSNAME_SUCCESS ? BUSNAME_FAILED : BUSNAME_DEAD);
-}
-
-static void busname_enter_signal(BusName *n, BusNameState state, BusNameResult f) {
- KillContext kill_context = {};
- int r;
-
- assert(n);
-
- if (f != BUSNAME_SUCCESS)
- n->result = f;
-
- kill_context_init(&kill_context);
-
- r = unit_kill_context(UNIT(n),
- &kill_context,
- state != BUSNAME_SIGTERM ? KILL_KILL : KILL_TERMINATE,
- -1,
- n->control_pid,
- false);
- if (r < 0) {
- log_unit_warning_errno(UNIT(n)->id, r, "%s failed to kill control process: %m", UNIT(n)->id);
- goto fail;
- }
-
- if (r > 0) {
- r = busname_arm_timer(n);
- if (r < 0) {
- log_unit_warning_errno(UNIT(n)->id, r, "%s failed to arm timer: %m", UNIT(n)->id);
- goto fail;
- }
-
- busname_set_state(n, state);
- } else if (state == BUSNAME_SIGTERM)
- busname_enter_signal(n, BUSNAME_SIGKILL, BUSNAME_SUCCESS);
- else
- busname_enter_dead(n, BUSNAME_SUCCESS);
-
- return;
-
-fail:
- busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
-}
-
-static void busname_enter_listening(BusName *n) {
- int r;
-
- assert(n);
-
- if (n->activating) {
- r = busname_watch_fd(n);
- if (r < 0) {
- log_unit_warning_errno(UNIT(n)->id, r, "%s failed to watch names: %m", UNIT(n)->id);
- goto fail;
- }
-
- busname_set_state(n, BUSNAME_LISTENING);
- } else
- busname_set_state(n, BUSNAME_REGISTERED);
-
- return;
-
-fail:
- busname_enter_signal(n, BUSNAME_SIGTERM, BUSNAME_FAILURE_RESOURCES);
-}
-
-static void busname_enter_making(BusName *n) {
- int r;
-
- assert(n);
-
- r = busname_open_fd(n);
- if (r < 0)
- goto fail;
-
- if (n->policy) {
- /* If there is a policy, we need to resolve user/group
- * names, which we can't do from PID1, hence let's
- * fork. */
- busname_unwatch_control_pid(n);
-
- r = busname_make_starter(n, &n->control_pid);
- if (r < 0) {
- log_unit_warning_errno(UNIT(n)->id, r, "%s failed to fork 'making' task: %m", UNIT(n)->id);
- goto fail;
- }
-
- busname_set_state(n, BUSNAME_MAKING);
- } else {
- /* If there is no policy, we can do everything
- * directly from PID 1, hence do so. */
-
- r = bus_kernel_make_starter(n->starter_fd, n->name, n->activating, n->accept_fd, NULL, n->policy_world);
- if (r < 0) {
- log_unit_warning_errno(UNIT(n)->id, r, "%s failed to make starter: %m", UNIT(n)->id);
- goto fail;
- }
-
- busname_enter_listening(n);
- }
-
- return;
-
-fail:
- busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
-}
-
-static void busname_enter_running(BusName *n) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- bool pending = false;
- Unit *other;
- Iterator i;
- int r;
-
- assert(n);
-
- if (!n->activating)
- return;
-
- /* We don't take conenctions anymore if we are supposed to
- * shut down anyway */
-
- if (unit_stop_pending(UNIT(n))) {
- log_unit_debug(UNIT(n)->id, "Suppressing activation request on %s since unit stop is scheduled.", UNIT(n)->id);
-
- /* Flush all queued activation reqeuest by closing and reopening the connection */
- bus_kernel_drop_one(n->starter_fd);
-
- busname_enter_listening(n);
- return;
- }
-
- /* If there's already a start pending don't bother to do
- * anything */
- SET_FOREACH(other, UNIT(n)->dependencies[UNIT_TRIGGERS], i)
- if (unit_active_or_pending(other)) {
- pending = true;
- break;
- }
-
- if (!pending) {
- r = manager_add_job(UNIT(n)->manager, JOB_START, UNIT_DEREF(n->service), JOB_REPLACE, true, &error, NULL);
- if (r < 0)
- goto fail;
- }
-
- busname_set_state(n, BUSNAME_RUNNING);
- return;
-
-fail:
- log_unit_warning(UNIT(n)->id, "%s failed to queue service startup job: %s", UNIT(n)->id, bus_error_message(&error, r));
- busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
-}
-
-static int busname_start(Unit *u) {
- BusName *n = BUSNAME(u);
-
- assert(n);
-
- /* We cannot fulfill this request right now, try again later
- * please! */
- if (IN_SET(n->state, BUSNAME_SIGTERM, BUSNAME_SIGKILL))
- return -EAGAIN;
-
- /* Already on it! */
- if (n->state == BUSNAME_MAKING)
- return 0;
-
- if (n->activating && UNIT_ISSET(n->service)) {
- Service *service;
-
- service = SERVICE(UNIT_DEREF(n->service));
-
- if (UNIT(service)->load_state != UNIT_LOADED) {
- log_unit_error(u->id, "Bus service %s not loaded, refusing.", UNIT(service)->id);
- return -ENOENT;
- }
- }
-
- assert(IN_SET(n->state, BUSNAME_DEAD, BUSNAME_FAILED));
-
- n->result = BUSNAME_SUCCESS;
- busname_enter_making(n);
-
- return 1;
-}
-
-static int busname_stop(Unit *u) {
- BusName *n = BUSNAME(u);
-
- assert(n);
-
- /* Already on it */
- if (IN_SET(n->state, BUSNAME_SIGTERM, BUSNAME_SIGKILL))
- return 0;
-
- /* If there's already something running, we go directly into
- * kill mode. */
-
- if (n->state == BUSNAME_MAKING) {
- busname_enter_signal(n, BUSNAME_SIGTERM, BUSNAME_SUCCESS);
- return -EAGAIN;
- }
-
- assert(IN_SET(n->state, BUSNAME_REGISTERED, BUSNAME_LISTENING, BUSNAME_RUNNING));
-
- busname_enter_dead(n, BUSNAME_SUCCESS);
- return 1;
-}
-
-static int busname_serialize(Unit *u, FILE *f, FDSet *fds) {
- BusName *n = BUSNAME(u);
-
- assert(n);
- assert(f);
- assert(fds);
-
- unit_serialize_item(u, f, "state", busname_state_to_string(n->state));
- unit_serialize_item(u, f, "result", busname_result_to_string(n->result));
-
- if (n->control_pid > 0)
- unit_serialize_item_format(u, f, "control-pid", PID_FMT, n->control_pid);
-
- if (n->starter_fd >= 0) {
- int copy;
-
- copy = fdset_put_dup(fds, n->starter_fd);
- if (copy < 0)
- return copy;
-
- unit_serialize_item_format(u, f, "starter-fd", "%i", copy);
- }
-
- return 0;
-}
-
-static int busname_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- BusName *n = BUSNAME(u);
-
- assert(n);
- assert(key);
- assert(value);
-
- if (streq(key, "state")) {
- BusNameState state;
-
- state = busname_state_from_string(value);
- if (state < 0)
- log_unit_debug(u->id, "Failed to parse state value %s", value);
- else
- n->deserialized_state = state;
-
- } else if (streq(key, "result")) {
- BusNameResult f;
-
- f = busname_result_from_string(value);
- if (f < 0)
- log_unit_debug(u->id, "Failed to parse result value %s", value);
- else if (f != BUSNAME_SUCCESS)
- n->result = f;
-
- } else if (streq(key, "control-pid")) {
- pid_t pid;
-
- if (parse_pid(value, &pid) < 0)
- log_unit_debug(u->id, "Failed to parse control-pid value %s", value);
- else
- n->control_pid = pid;
- } else if (streq(key, "starter-fd")) {
- int fd;
-
- if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u->id, "Failed to parse starter fd value %s", value);
- else {
- safe_close(n->starter_fd);
- n->starter_fd = fdset_remove(fds, fd);
- }
- } else
- log_unit_debug(u->id, "Unknown serialization key '%s'", key);
-
- return 0;
-}
-
-_pure_ static UnitActiveState busname_active_state(Unit *u) {
- assert(u);
-
- return state_translation_table[BUSNAME(u)->state];
-}
-
-_pure_ static const char *busname_sub_state_to_string(Unit *u) {
- assert(u);
-
- return busname_state_to_string(BUSNAME(u)->state);
-}
-
-static int busname_peek_message(BusName *n) {
- struct kdbus_cmd_recv cmd_recv = {
- .size = sizeof(cmd_recv),
- .flags = KDBUS_RECV_PEEK,
- };
- struct kdbus_cmd_free cmd_free = {
- .size = sizeof(cmd_free),
- };
- const char *comm = NULL;
- struct kdbus_item *d;
- struct kdbus_msg *k;
- size_t start, ps, sz, delta;
- void *p = NULL;
- pid_t pid = 0;
- int r;
-
- /* Generate a friendly debug log message about which process
- * caused triggering of this bus name. This simply peeks the
- * metadata of the first queued message and logs it. */
-
- assert(n);
-
- /* Let's shortcut things a bit, if debug logging is turned off
- * anyway. */
-
- if (log_get_max_level() < LOG_DEBUG)
- return 0;
-
- r = ioctl(n->starter_fd, KDBUS_CMD_RECV, &cmd_recv);
- if (r < 0) {
- if (errno == EINTR || errno == EAGAIN)
- return 0;
-
- log_unit_error(UNIT(n)->id, "%s: Failed to query activation message: %m", UNIT(n)->id);
- return -errno;
- }
-
- /* We map as late as possible, and unmap imemdiately after
- * use. On 32bit address space is scarce and we want to be
- * able to handle a lot of activator connections at the same
- * time, and hence shouldn't keep the mmap()s around for
- * longer than necessary. */
-
- ps = page_size();
- start = (cmd_recv.msg.offset / ps) * ps;
- delta = cmd_recv.msg.offset - start;
- sz = PAGE_ALIGN(delta + cmd_recv.msg.msg_size);
-
- p = mmap(NULL, sz, PROT_READ, MAP_SHARED, n->starter_fd, start);
- if (p == MAP_FAILED) {
- log_unit_error(UNIT(n)->id, "%s: Failed to map activation message: %m", UNIT(n)->id);
- r = -errno;
- goto finish;
- }
-
- k = (struct kdbus_msg *) ((uint8_t *) p + delta);
- KDBUS_ITEM_FOREACH(d, k, items) {
- switch (d->type) {
-
- case KDBUS_ITEM_PIDS:
- pid = d->pids.pid;
- break;
-
- case KDBUS_ITEM_PID_COMM:
- comm = d->str;
- break;
- }
- }
-
- if (pid > 0)
- log_unit_debug(UNIT(n)->id, "%s: Activation triggered by process " PID_FMT " (%s)", UNIT(n)->id, pid, strna(comm));
-
- r = 0;
-
-finish:
- if (p)
- (void) munmap(p, sz);
-
- cmd_free.offset = cmd_recv.msg.offset;
- if (ioctl(n->starter_fd, KDBUS_CMD_FREE, &cmd_free) < 0)
- log_unit_warning(UNIT(n)->id, "Failed to free peeked message, ignoring: %m");
-
- return r;
-}
-
-static int busname_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
- BusName *n = userdata;
-
- assert(n);
- assert(fd >= 0);
-
- if (n->state != BUSNAME_LISTENING)
- return 0;
-
- log_unit_debug(UNIT(n)->id, "Activation request on %s", UNIT(n)->id);
-
- if (revents != EPOLLIN) {
- log_unit_error(UNIT(n)->id, "%s: Got unexpected poll event (0x%x) on starter fd.",
- UNIT(n)->id, revents);
- goto fail;
- }
-
- busname_peek_message(n);
- busname_enter_running(n);
- return 0;
-fail:
-
- busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
- return 0;
-}
-
-static void busname_sigchld_event(Unit *u, pid_t pid, int code, int status) {
- BusName *n = BUSNAME(u);
- BusNameResult f;
-
- assert(n);
- assert(pid >= 0);
-
- if (pid != n->control_pid)
- return;
-
- n->control_pid = 0;
-
- if (is_clean_exit(code, status, NULL))
- f = BUSNAME_SUCCESS;
- else if (code == CLD_EXITED)
- f = BUSNAME_FAILURE_EXIT_CODE;
- else if (code == CLD_KILLED)
- f = BUSNAME_FAILURE_SIGNAL;
- else if (code == CLD_DUMPED)
- f = BUSNAME_FAILURE_CORE_DUMP;
- else
- assert_not_reached("Unknown sigchld code");
-
- log_unit_full(u->id,
- f == BUSNAME_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
- "%s control process exited, code=%s status=%i",
- u->id, sigchld_code_to_string(code), status);
-
- if (f != BUSNAME_SUCCESS)
- n->result = f;
-
- switch (n->state) {
-
- case BUSNAME_MAKING:
- if (f == BUSNAME_SUCCESS)
- busname_enter_listening(n);
- else
- busname_enter_signal(n, BUSNAME_SIGTERM, f);
- break;
-
- case BUSNAME_SIGTERM:
- case BUSNAME_SIGKILL:
- busname_enter_dead(n, f);
- break;
-
- default:
- assert_not_reached("Uh, control process died at wrong time.");
- }
-
- /* Notify clients about changed exit status */
- unit_add_to_dbus_queue(u);
-}
-
-static int busname_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
- BusName *n = BUSNAME(userdata);
-
- assert(n);
- assert(n->timer_event_source == source);
-
- switch (n->state) {
-
- case BUSNAME_MAKING:
- log_unit_warning(UNIT(n)->id, "%s making timed out. Terminating.", UNIT(n)->id);
- busname_enter_signal(n, BUSNAME_SIGTERM, BUSNAME_FAILURE_TIMEOUT);
- break;
-
- case BUSNAME_SIGTERM:
- log_unit_warning(UNIT(n)->id, "%s stopping timed out. Killing.", UNIT(n)->id);
- busname_enter_signal(n, BUSNAME_SIGKILL, BUSNAME_FAILURE_TIMEOUT);
- break;
-
- case BUSNAME_SIGKILL:
- log_unit_warning(UNIT(n)->id, "%s still around after SIGKILL. Ignoring.", UNIT(n)->id);
- busname_enter_dead(n, BUSNAME_FAILURE_TIMEOUT);
- break;
-
- default:
- assert_not_reached("Timeout at wrong time.");
- }
-
- return 0;
-}
-
-static void busname_reset_failed(Unit *u) {
- BusName *n = BUSNAME(u);
-
- assert(n);
-
- if (n->state == BUSNAME_FAILED)
- busname_set_state(n, BUSNAME_DEAD);
-
- n->result = BUSNAME_SUCCESS;
-}
-
-static void busname_trigger_notify(Unit *u, Unit *other) {
- BusName *n = BUSNAME(u);
- Service *s;
-
- assert(n);
- assert(other);
-
- if (!IN_SET(n->state, BUSNAME_RUNNING, BUSNAME_LISTENING))
- return;
-
- if (other->load_state != UNIT_LOADED || other->type != UNIT_SERVICE)
- return;
-
- s = SERVICE(other);
-
- if (s->state == SERVICE_FAILED && s->result == SERVICE_FAILURE_START_LIMIT)
- busname_enter_dead(n, BUSNAME_FAILURE_SERVICE_FAILED_PERMANENT);
- else if (IN_SET(s->state,
- SERVICE_DEAD, SERVICE_FAILED,
- SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL,
- SERVICE_STOP_POST, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
- SERVICE_AUTO_RESTART))
- busname_enter_listening(n);
-}
-
-static int busname_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
- return unit_kill_common(u, who, signo, -1, BUSNAME(u)->control_pid, error);
-}
-
-static int busname_get_timeout(Unit *u, uint64_t *timeout) {
- BusName *n = BUSNAME(u);
- int r;
-
- if (!n->timer_event_source)
- return 0;
-
- r = sd_event_source_get_time(n->timer_event_source, timeout);
- if (r < 0)
- return r;
-
- return 1;
-}
-
-static bool busname_supported(Manager *m) {
- static int supported = -1;
- assert(m);
-
- if (supported < 0)
- supported = access("/sys/fs/kdbus", F_OK) >= 0;
-
- return supported;
-}
-
-static const char* const busname_state_table[_BUSNAME_STATE_MAX] = {
- [BUSNAME_DEAD] = "dead",
- [BUSNAME_MAKING] = "making",
- [BUSNAME_REGISTERED] = "registered",
- [BUSNAME_LISTENING] = "listening",
- [BUSNAME_RUNNING] = "running",
- [BUSNAME_SIGTERM] = "sigterm",
- [BUSNAME_SIGKILL] = "sigkill",
- [BUSNAME_FAILED] = "failed",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(busname_state, BusNameState);
-
-static const char* const busname_result_table[_BUSNAME_RESULT_MAX] = {
- [BUSNAME_SUCCESS] = "success",
- [BUSNAME_FAILURE_RESOURCES] = "resources",
- [BUSNAME_FAILURE_TIMEOUT] = "timeout",
- [BUSNAME_FAILURE_EXIT_CODE] = "exit-code",
- [BUSNAME_FAILURE_SIGNAL] = "signal",
- [BUSNAME_FAILURE_CORE_DUMP] = "core-dump",
- [BUSNAME_FAILURE_SERVICE_FAILED_PERMANENT] = "service-failed-permanent",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(busname_result, BusNameResult);
-
-const UnitVTable busname_vtable = {
- .object_size = sizeof(BusName),
-
- .sections =
- "Unit\0"
- "BusName\0"
- "Install\0",
- .private_section = "BusName",
-
- .init = busname_init,
- .done = busname_done,
- .load = busname_load,
-
- .coldplug = busname_coldplug,
-
- .dump = busname_dump,
-
- .start = busname_start,
- .stop = busname_stop,
-
- .kill = busname_kill,
-
- .get_timeout = busname_get_timeout,
-
- .serialize = busname_serialize,
- .deserialize_item = busname_deserialize_item,
-
- .active_state = busname_active_state,
- .sub_state_to_string = busname_sub_state_to_string,
-
- .sigchld_event = busname_sigchld_event,
-
- .trigger_notify = busname_trigger_notify,
-
- .reset_failed = busname_reset_failed,
-
- .supported = busname_supported,
-
- .bus_interface = "org.freedesktop.systemd1.BusName",
- .bus_vtable = bus_busname_vtable,
-
- .status_message_formats = {
- .finished_start_job = {
- [JOB_DONE] = "Listening on %s.",
- [JOB_FAILED] = "Failed to listen on %s.",
- [JOB_DEPENDENCY] = "Dependency failed for %s.",
- [JOB_TIMEOUT] = "Timed out starting %s.",
- },
- .finished_stop_job = {
- [JOB_DONE] = "Closed %s.",
- [JOB_FAILED] = "Failed stopping %s.",
- [JOB_TIMEOUT] = "Timed out stopping %s.",
- },
- },
-};
diff --git a/src/core/busname.h b/src/core/busname.h
deleted file mode 100644
index 69528a2ae..000000000
--- a/src/core/busname.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 BusName BusName;
-typedef struct BusNamePolicy BusNamePolicy;
-
-
-typedef enum BusNameState {
- BUSNAME_DEAD,
- BUSNAME_MAKING,
- BUSNAME_REGISTERED,
- BUSNAME_LISTENING,
- BUSNAME_RUNNING,
- BUSNAME_SIGTERM,
- BUSNAME_SIGKILL,
- BUSNAME_FAILED,
- _BUSNAME_STATE_MAX,
- _BUSNAME_STATE_INVALID = -1
-} BusNameState;
-
-typedef enum BusNameResult {
- BUSNAME_SUCCESS,
- BUSNAME_FAILURE_RESOURCES,
- BUSNAME_FAILURE_TIMEOUT,
- BUSNAME_FAILURE_EXIT_CODE,
- BUSNAME_FAILURE_SIGNAL,
- BUSNAME_FAILURE_CORE_DUMP,
- BUSNAME_FAILURE_SERVICE_FAILED_PERMANENT,
- _BUSNAME_RESULT_MAX,
- _BUSNAME_RESULT_INVALID = -1
-} BusNameResult;
-
-struct BusName {
- Unit meta;
-
- char *name;
- int starter_fd;
-
- bool activating;
- bool accept_fd;
-
- UnitRef service;
-
- BusNameState state, deserialized_state;
- BusNameResult result;
-
- usec_t timeout_usec;
-
- sd_event_source *starter_event_source;
- sd_event_source *timer_event_source;
-
- pid_t control_pid;
-
- LIST_HEAD(BusNamePolicy, policy);
- BusPolicyAccess policy_world;
-};
-
-extern const UnitVTable busname_vtable;
-
-const char* busname_state_to_string(BusNameState i) _const_;
-BusNameState busname_state_from_string(const char *s) _pure_;
-
-const char* busname_result_to_string(BusNameResult i) _const_;
-BusNameResult busname_result_from_string(const char *s) _pure_;
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
deleted file mode 100644
index b28137789..000000000
--- a/src/core/cgroup.c
+++ /dev/null
@@ -1,1136 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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>
-
-#include "path-util.h"
-#include "special.h"
-#include "cgroup-util.h"
-#include "cgroup.h"
-
-#define CGROUP_CPU_QUOTA_PERIOD_USEC ((usec_t) 100 * USEC_PER_MSEC)
-
-void cgroup_context_init(CGroupContext *c) {
- assert(c);
-
- /* Initialize everything to the kernel defaults, assuming the
- * structure is preinitialized to 0 */
-
- c->cpu_shares = (unsigned long) -1;
- c->startup_cpu_shares = (unsigned long) -1;
- c->memory_limit = (uint64_t) -1;
- c->blockio_weight = (unsigned long) -1;
- c->startup_blockio_weight = (unsigned long) -1;
-
- c->cpu_quota_per_sec_usec = USEC_INFINITY;
-}
-
-void cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a) {
- assert(c);
- assert(a);
-
- LIST_REMOVE(device_allow, c->device_allow, a);
- free(a->path);
- free(a);
-}
-
-void cgroup_context_free_blockio_device_weight(CGroupContext *c, CGroupBlockIODeviceWeight *w) {
- assert(c);
- assert(w);
-
- LIST_REMOVE(device_weights, c->blockio_device_weights, w);
- free(w->path);
- free(w);
-}
-
-void cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockIODeviceBandwidth *b) {
- assert(c);
- assert(b);
-
- LIST_REMOVE(device_bandwidths, c->blockio_device_bandwidths, b);
- free(b->path);
- free(b);
-}
-
-void cgroup_context_done(CGroupContext *c) {
- assert(c);
-
- while (c->blockio_device_weights)
- cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
-
- while (c->blockio_device_bandwidths)
- cgroup_context_free_blockio_device_bandwidth(c, c->blockio_device_bandwidths);
-
- while (c->device_allow)
- cgroup_context_free_device_allow(c, c->device_allow);
-}
-
-void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
- CGroupBlockIODeviceBandwidth *b;
- CGroupBlockIODeviceWeight *w;
- CGroupDeviceAllow *a;
- char u[FORMAT_TIMESPAN_MAX];
-
- assert(c);
- assert(f);
-
- prefix = strempty(prefix);
-
- fprintf(f,
- "%sCPUAccounting=%s\n"
- "%sBlockIOAccounting=%s\n"
- "%sMemoryAccounting=%s\n"
- "%sCPUShares=%lu\n"
- "%sStartupCPUShares=%lu\n"
- "%sCPUQuotaPerSecSec=%s\n"
- "%sBlockIOWeight=%lu\n"
- "%sStartupBlockIOWeight=%lu\n"
- "%sMemoryLimit=%" PRIu64 "\n"
- "%sDevicePolicy=%s\n"
- "%sDelegate=%s\n",
- prefix, yes_no(c->cpu_accounting),
- prefix, yes_no(c->blockio_accounting),
- prefix, yes_no(c->memory_accounting),
- prefix, c->cpu_shares,
- prefix, c->startup_cpu_shares,
- prefix, format_timespan(u, sizeof(u), c->cpu_quota_per_sec_usec, 1),
- prefix, c->blockio_weight,
- prefix, c->startup_blockio_weight,
- prefix, c->memory_limit,
- prefix, cgroup_device_policy_to_string(c->device_policy),
- prefix, yes_no(c->delegate));
-
- LIST_FOREACH(device_allow, a, c->device_allow)
- fprintf(f,
- "%sDeviceAllow=%s %s%s%s\n",
- prefix,
- a->path,
- a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
-
- LIST_FOREACH(device_weights, w, c->blockio_device_weights)
- fprintf(f,
- "%sBlockIODeviceWeight=%s %lu",
- prefix,
- w->path,
- w->weight);
-
- LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
- char buf[FORMAT_BYTES_MAX];
-
- fprintf(f,
- "%s%s=%s %s\n",
- prefix,
- b->read ? "BlockIOReadBandwidth" : "BlockIOWriteBandwidth",
- b->path,
- format_bytes(buf, sizeof(buf), b->bandwidth));
- }
-}
-
-static int lookup_blkio_device(const char *p, dev_t *dev) {
- struct stat st;
- int r;
-
- assert(p);
- assert(dev);
-
- r = stat(p, &st);
- if (r < 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 */
- 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;
- }
-
- return 0;
-}
-
-static int whitelist_device(const char *path, const char *node, const char *acc) {
- char buf[2+DECIMAL_STR_MAX(dev_t)*2+2+4];
- struct stat st;
- int r;
-
- assert(path);
- assert(acc);
-
- if (stat(node, &st) < 0) {
- log_warning("Couldn't stat device %s", node);
- return -errno;
- }
-
- if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
- log_warning("%s is not a device.", node);
- return -ENODEV;
- }
-
- sprintf(buf,
- "%c %u:%u %s",
- S_ISCHR(st.st_mode) ? 'c' : 'b',
- major(st.st_rdev), minor(st.st_rdev),
- acc);
-
- r = cg_set_attribute("devices", path, "devices.allow", buf);
- if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set devices.allow on %s: %m", path);
-
- return r;
-}
-
-static int whitelist_major(const char *path, const char *name, char type, const char *acc) {
- _cleanup_fclose_ FILE *f = NULL;
- char line[LINE_MAX];
- bool good = false;
- int r;
-
- assert(path);
- assert(acc);
- assert(type == 'b' || type == 'c');
-
- f = fopen("/proc/devices", "re");
- if (!f)
- return log_warning_errno(errno, "Cannot open /proc/devices to resolve %s (%c): %m", name, type);
-
- FOREACH_LINE(line, f, goto fail) {
- char buf[2+DECIMAL_STR_MAX(unsigned)+3+4], *p, *w;
- unsigned maj;
-
- truncate_nl(line);
-
- if (type == 'c' && streq(line, "Character devices:")) {
- good = true;
- continue;
- }
-
- if (type == 'b' && streq(line, "Block devices:")) {
- good = true;
- continue;
- }
-
- if (isempty(line)) {
- good = false;
- continue;
- }
-
- if (!good)
- continue;
-
- p = strstrip(line);
-
- w = strpbrk(p, WHITESPACE);
- if (!w)
- continue;
- *w = 0;
-
- r = safe_atou(p, &maj);
- if (r < 0)
- continue;
- if (maj <= 0)
- continue;
-
- w++;
- w += strspn(w, WHITESPACE);
-
- if (fnmatch(name, w, 0) != 0)
- continue;
-
- sprintf(buf,
- "%c %u:* %s",
- type,
- maj,
- acc);
-
- r = cg_set_attribute("devices", path, "devices.allow", buf);
- if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set devices.allow on %s: %m", path);
- }
-
- return 0;
-
-fail:
- log_warning_errno(errno, "Failed to read /proc/devices: %m");
- return -errno;
-}
-
-void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const char *path, ManagerState state) {
- bool is_root;
- int r;
-
- assert(c);
- assert(path);
-
- if (mask == 0)
- return;
-
- /* Some cgroup attributes are not supported on the root cgroup,
- * hence silently ignore */
- is_root = isempty(path) || path_equal(path, "/");
- if (is_root)
- /* Make sure we don't try to display messages with an empty path. */
- path = "/";
-
- /* We generally ignore errors caused by read-only mounted
- * cgroup trees (assuming we are running in a container then),
- * and missing cgroups, i.e. EROFS and ENOENT. */
-
- if ((mask & CGROUP_CPU) && !is_root) {
- char buf[MAX(DECIMAL_STR_MAX(unsigned long), DECIMAL_STR_MAX(usec_t)) + 1];
-
- sprintf(buf, "%lu\n",
- IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_cpu_shares != (unsigned long) -1 ? c->startup_cpu_shares :
- c->cpu_shares != (unsigned long) -1 ? c->cpu_shares : 1024);
- r = cg_set_attribute("cpu", path, "cpu.shares", buf);
- if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set cpu.shares on %s: %m", path);
-
- sprintf(buf, USEC_FMT "\n", CGROUP_CPU_QUOTA_PERIOD_USEC);
- r = cg_set_attribute("cpu", path, "cpu.cfs_period_us", buf);
- if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set cpu.cfs_period_us on %s: %m", path);
-
- if (c->cpu_quota_per_sec_usec != USEC_INFINITY) {
- sprintf(buf, USEC_FMT "\n", c->cpu_quota_per_sec_usec * CGROUP_CPU_QUOTA_PERIOD_USEC / USEC_PER_SEC);
- r = cg_set_attribute("cpu", path, "cpu.cfs_quota_us", buf);
- } else
- r = cg_set_attribute("cpu", path, "cpu.cfs_quota_us", "-1");
- if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set cpu.cfs_quota_us on %s: %m", path);
- }
-
- if (mask & CGROUP_BLKIO) {
- char buf[MAX3(DECIMAL_STR_MAX(unsigned long)+1,
- DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(unsigned long)*1,
- DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1)];
- CGroupBlockIODeviceWeight *w;
- CGroupBlockIODeviceBandwidth *b;
-
- if (!is_root) {
- sprintf(buf, "%lu\n", IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_blockio_weight != (unsigned long) -1 ? c->startup_blockio_weight :
- c->blockio_weight != (unsigned long) -1 ? c->blockio_weight : 1000);
- r = cg_set_attribute("blkio", path, "blkio.weight", buf);
- if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set blkio.weight on %s: %m", path);
-
- /* FIXME: no way to reset this list */
- LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
- dev_t dev;
-
- r = lookup_blkio_device(w->path, &dev);
- if (r < 0)
- continue;
-
- sprintf(buf, "%u:%u %lu", major(dev), minor(dev), w->weight);
- r = cg_set_attribute("blkio", path, "blkio.weight_device", buf);
- if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set blkio.weight_device on %s: %m", path);
- }
- }
-
- /* FIXME: no way to reset this list */
- LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
- const char *a;
- dev_t dev;
-
- r = lookup_blkio_device(b->path, &dev);
- if (r < 0)
- continue;
-
- a = b->read ? "blkio.throttle.read_bps_device" : "blkio.throttle.write_bps_device";
-
- sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), b->bandwidth);
- r = cg_set_attribute("blkio", path, a, buf);
- if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set %s on %s: %m", a, path);
- }
- }
-
- if ((mask & CGROUP_MEMORY) && !is_root) {
- if (c->memory_limit != (uint64_t) -1) {
- char buf[DECIMAL_STR_MAX(uint64_t) + 1];
-
- sprintf(buf, "%" PRIu64 "\n", c->memory_limit);
- r = cg_set_attribute("memory", path, "memory.limit_in_bytes", buf);
- } else
- r = cg_set_attribute("memory", path, "memory.limit_in_bytes", "-1");
-
- if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set memory.limit_in_bytes on %s: %m", path);
- }
-
- if ((mask & CGROUP_DEVICE) && !is_root) {
- CGroupDeviceAllow *a;
-
- /* Changing the devices list of a populated cgroup
- * might result in EINVAL, hence ignore EINVAL
- * here. */
-
- if (c->device_allow || c->device_policy != CGROUP_AUTO)
- r = cg_set_attribute("devices", path, "devices.deny", "a");
- else
- r = cg_set_attribute("devices", path, "devices.allow", "a");
- if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to reset devices.list on %s: %m", path);
-
- if (c->device_policy == CGROUP_CLOSED ||
- (c->device_policy == CGROUP_AUTO && c->device_allow)) {
- static const char auto_devices[] =
- "/dev/null\0" "rwm\0"
- "/dev/zero\0" "rwm\0"
- "/dev/full\0" "rwm\0"
- "/dev/random\0" "rwm\0"
- "/dev/urandom\0" "rwm\0"
- "/dev/tty\0" "rwm\0"
- "/dev/pts/ptmx\0" "rw\0"; /* /dev/pts/ptmx may not be duplicated, but accessed */
-
- const char *x, *y;
-
- NULSTR_FOREACH_PAIR(x, y, auto_devices)
- whitelist_device(path, x, y);
-
- whitelist_major(path, "pts", 'c', "rw");
- whitelist_major(path, "kdbus", 'c', "rw");
- whitelist_major(path, "kdbus/*", 'c', "rw");
- }
-
- LIST_FOREACH(device_allow, a, c->device_allow) {
- char acc[4];
- unsigned k = 0;
-
- if (a->r)
- acc[k++] = 'r';
- if (a->w)
- acc[k++] = 'w';
- if (a->m)
- acc[k++] = 'm';
-
- if (k == 0)
- continue;
-
- acc[k++] = 0;
-
- if (startswith(a->path, "/dev/"))
- whitelist_device(path, a->path, acc);
- else if (startswith(a->path, "block-"))
- whitelist_major(path, a->path + 6, 'b', acc);
- else if (startswith(a->path, "char-"))
- whitelist_major(path, a->path + 5, 'c', acc);
- else
- log_debug("Ignoring device %s while writing cgroup attribute.", a->path);
- }
- }
-}
-
-CGroupControllerMask cgroup_context_get_mask(CGroupContext *c) {
- CGroupControllerMask mask = 0;
-
- /* Figure out which controllers we need */
-
- if (c->cpu_accounting ||
- c->cpu_shares != (unsigned long) -1 ||
- c->startup_cpu_shares != (unsigned long) -1 ||
- c->cpu_quota_per_sec_usec != USEC_INFINITY)
- mask |= CGROUP_CPUACCT | CGROUP_CPU;
-
- if (c->blockio_accounting ||
- c->blockio_weight != (unsigned long) -1 ||
- c->startup_blockio_weight != (unsigned long) -1 ||
- c->blockio_device_weights ||
- c->blockio_device_bandwidths)
- mask |= CGROUP_BLKIO;
-
- if (c->memory_accounting ||
- c->memory_limit != (uint64_t) -1)
- mask |= CGROUP_MEMORY;
-
- if (c->device_allow ||
- c->device_policy != CGROUP_AUTO)
- mask |= CGROUP_DEVICE;
-
- return mask;
-}
-
-CGroupControllerMask unit_get_cgroup_mask(Unit *u) {
- CGroupContext *c;
-
- c = unit_get_cgroup_context(u);
- if (!c)
- return 0;
-
- /* If delegation is turned on, then turn on all cgroups,
- * unless the process we fork into it is known to drop
- * privileges anyway, and shouldn't get access to the
- * controllers anyway. */
-
- if (c->delegate) {
- ExecContext *e;
-
- e = unit_get_exec_context(u);
- if (!e || exec_context_maintains_privileges(e))
- return _CGROUP_CONTROLLER_MASK_ALL;
- }
-
- return cgroup_context_get_mask(c);
-}
-
-CGroupControllerMask unit_get_members_mask(Unit *u) {
- assert(u);
-
- if (u->cgroup_members_mask_valid)
- return u->cgroup_members_mask;
-
- u->cgroup_members_mask = 0;
-
- if (u->type == UNIT_SLICE) {
- Unit *member;
- Iterator i;
-
- SET_FOREACH(member, u->dependencies[UNIT_BEFORE], i) {
-
- if (member == u)
- continue;
-
- if (UNIT_DEREF(member->slice) != u)
- continue;
-
- u->cgroup_members_mask |=
- unit_get_cgroup_mask(member) |
- unit_get_members_mask(member);
- }
- }
-
- u->cgroup_members_mask_valid = true;
- return u->cgroup_members_mask;
-}
-
-CGroupControllerMask unit_get_siblings_mask(Unit *u) {
- assert(u);
-
- if (UNIT_ISSET(u->slice))
- return unit_get_members_mask(UNIT_DEREF(u->slice));
-
- return unit_get_cgroup_mask(u) | unit_get_members_mask(u);
-}
-
-CGroupControllerMask unit_get_target_mask(Unit *u) {
- CGroupControllerMask mask;
-
- mask = unit_get_cgroup_mask(u) | unit_get_members_mask(u) | unit_get_siblings_mask(u);
- mask &= u->manager->cgroup_supported;
-
- return mask;
-}
-
-/* Recurse from a unit up through its containing slices, propagating
- * mask bits upward. A unit is also member of itself. */
-void unit_update_cgroup_members_masks(Unit *u) {
- CGroupControllerMask m;
- bool more;
-
- assert(u);
-
- /* Calculate subtree mask */
- m = unit_get_cgroup_mask(u) | unit_get_members_mask(u);
-
- /* See if anything changed from the previous invocation. If
- * not, we're done. */
- if (u->cgroup_subtree_mask_valid && m == u->cgroup_subtree_mask)
- return;
-
- more =
- u->cgroup_subtree_mask_valid &&
- ((m & ~u->cgroup_subtree_mask) != 0) &&
- ((~m & u->cgroup_subtree_mask) == 0);
-
- u->cgroup_subtree_mask = m;
- u->cgroup_subtree_mask_valid = true;
-
- if (UNIT_ISSET(u->slice)) {
- Unit *s = UNIT_DEREF(u->slice);
-
- if (more)
- /* There's more set now than before. We
- * propagate the new mask to the parent's mask
- * (not caring if it actually was valid or
- * not). */
-
- s->cgroup_members_mask |= m;
-
- else
- /* There's less set now than before (or we
- * don't know), we need to recalculate
- * everything, so let's invalidate the
- * parent's members mask */
-
- s->cgroup_members_mask_valid = false;
-
- /* And now make sure that this change also hits our
- * grandparents */
- unit_update_cgroup_members_masks(s);
- }
-}
-
-static const char *migrate_callback(CGroupControllerMask mask, void *userdata) {
- Unit *u = userdata;
-
- assert(mask != 0);
- assert(u);
-
- while (u) {
- if (u->cgroup_path &&
- u->cgroup_realized &&
- (u->cgroup_realized_mask & mask) == mask)
- return u->cgroup_path;
-
- u = UNIT_DEREF(u->slice);
- }
-
- return NULL;
-}
-
-static int unit_create_cgroups(Unit *u, CGroupControllerMask mask) {
- CGroupContext *c;
- int r;
-
- assert(u);
-
- c = unit_get_cgroup_context(u);
- if (!c)
- return 0;
-
- if (!u->cgroup_path) {
- _cleanup_free_ char *path = NULL;
-
- path = unit_default_cgroup_path(u);
- if (!path)
- return log_oom();
-
- r = hashmap_put(u->manager->cgroup_unit, path, u);
- if (r < 0) {
- log_error(r == -EEXIST ? "cgroup %s exists already: %s" : "hashmap_put failed for %s: %s", path, strerror(-r));
- return r;
- }
- if (r > 0) {
- u->cgroup_path = path;
- path = NULL;
- }
- }
-
- /* First, create our own group */
- r = cg_create_everywhere(u->manager->cgroup_supported, mask, u->cgroup_path);
- if (r < 0)
- return log_error_errno(r, "Failed to create cgroup %s: %m", u->cgroup_path);
-
- /* Keep track that this is now realized */
- u->cgroup_realized = true;
- u->cgroup_realized_mask = mask;
-
- if (u->type != UNIT_SLICE && !c->delegate) {
-
- /* Then, possibly move things over, but not if
- * subgroups may contain processes, which is the case
- * for slice and delegation units. */
- r = cg_migrate_everywhere(u->manager->cgroup_supported, u->cgroup_path, u->cgroup_path, migrate_callback, u);
- if (r < 0)
- log_warning_errno(r, "Failed to migrate cgroup from to %s: %m", u->cgroup_path);
- }
-
- return 0;
-}
-
-int unit_attach_pids_to_cgroup(Unit *u) {
- int r;
- assert(u);
-
- r = unit_realize_cgroup(u);
- if (r < 0)
- return r;
-
- r = cg_attach_many_everywhere(u->manager->cgroup_supported, u->cgroup_path, u->pids, migrate_callback, u);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-static bool unit_has_mask_realized(Unit *u, CGroupControllerMask mask) {
- assert(u);
-
- return u->cgroup_realized && u->cgroup_realized_mask == mask;
-}
-
-/* Check if necessary controllers and attributes for a unit are in place.
- *
- * If so, do nothing.
- * If not, create paths, move processes over, and set attributes.
- *
- * Returns 0 on success and < 0 on failure. */
-static int unit_realize_cgroup_now(Unit *u, ManagerState state) {
- CGroupControllerMask mask;
- int r;
-
- assert(u);
-
- if (u->in_cgroup_queue) {
- LIST_REMOVE(cgroup_queue, u->manager->cgroup_queue, u);
- u->in_cgroup_queue = false;
- }
-
- mask = unit_get_target_mask(u);
-
- if (unit_has_mask_realized(u, mask))
- return 0;
-
- /* First, realize parents */
- if (UNIT_ISSET(u->slice)) {
- r = unit_realize_cgroup_now(UNIT_DEREF(u->slice), state);
- if (r < 0)
- return r;
- }
-
- /* And then do the real work */
- r = unit_create_cgroups(u, mask);
- if (r < 0)
- return r;
-
- /* Finally, apply the necessary attributes. */
- cgroup_context_apply(unit_get_cgroup_context(u), mask, u->cgroup_path, state);
-
- return 0;
-}
-
-static void unit_add_to_cgroup_queue(Unit *u) {
-
- if (u->in_cgroup_queue)
- return;
-
- LIST_PREPEND(cgroup_queue, u->manager->cgroup_queue, u);
- u->in_cgroup_queue = true;
-}
-
-unsigned manager_dispatch_cgroup_queue(Manager *m) {
- ManagerState state;
- unsigned n = 0;
- Unit *i;
- int r;
-
- state = manager_state(m);
-
- while ((i = m->cgroup_queue)) {
- assert(i->in_cgroup_queue);
-
- r = unit_realize_cgroup_now(i, state);
- if (r < 0)
- log_warning_errno(r, "Failed to realize cgroups for queued unit %s: %m", i->id);
-
- n++;
- }
-
- return n;
-}
-
-static void unit_queue_siblings(Unit *u) {
- Unit *slice;
-
- /* This adds the siblings of the specified unit and the
- * siblings of all parent units to the cgroup queue. (But
- * neither the specified unit itself nor the parents.) */
-
- while ((slice = UNIT_DEREF(u->slice))) {
- Iterator i;
- Unit *m;
-
- SET_FOREACH(m, slice->dependencies[UNIT_BEFORE], i) {
- if (m == u)
- continue;
-
- /* Skip units that have a dependency on the slice
- * but aren't actually in it. */
- if (UNIT_DEREF(m->slice) != slice)
- continue;
-
- /* No point in doing cgroup application for units
- * without active processes. */
- if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(m)))
- continue;
-
- /* If the unit doesn't need any new controllers
- * and has current ones realized, it doesn't need
- * any changes. */
- if (unit_has_mask_realized(m, unit_get_target_mask(m)))
- continue;
-
- unit_add_to_cgroup_queue(m);
- }
-
- u = slice;
- }
-}
-
-int unit_realize_cgroup(Unit *u) {
- CGroupContext *c;
-
- assert(u);
-
- c = unit_get_cgroup_context(u);
- if (!c)
- return 0;
-
- /* So, here's the deal: when realizing the cgroups for this
- * unit, we need to first create all parents, but there's more
- * actually: for the weight-based controllers we also need to
- * make sure that all our siblings (i.e. units that are in the
- * same slice as we are) have cgroups, too. Otherwise, things
- * would become very uneven as each of their processes would
- * get as much resources as all our group together. This call
- * will synchronously create the parent cgroups, but will
- * defer work on the siblings to the next event loop
- * iteration. */
-
- /* Add all sibling slices to the cgroup queue. */
- unit_queue_siblings(u);
-
- /* And realize this one now (and apply the values) */
- return unit_realize_cgroup_now(u, manager_state(u->manager));
-}
-
-void unit_destroy_cgroup_if_empty(Unit *u) {
- int r;
-
- assert(u);
-
- if (!u->cgroup_path)
- return;
-
- r = cg_trim_everywhere(u->manager->cgroup_supported, u->cgroup_path, !unit_has_name(u, SPECIAL_ROOT_SLICE));
- if (r < 0) {
- log_debug_errno(r, "Failed to destroy cgroup %s: %m", u->cgroup_path);
- return;
- }
-
- hashmap_remove(u->manager->cgroup_unit, u->cgroup_path);
-
- free(u->cgroup_path);
- u->cgroup_path = NULL;
- u->cgroup_realized = false;
- u->cgroup_realized_mask = 0;
-}
-
-pid_t unit_search_main_pid(Unit *u) {
- _cleanup_fclose_ FILE *f = NULL;
- pid_t pid = 0, npid, mypid;
-
- assert(u);
-
- if (!u->cgroup_path)
- return 0;
-
- if (cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, &f) < 0)
- return 0;
-
- mypid = getpid();
- while (cg_read_pid(f, &npid) > 0) {
- pid_t ppid;
-
- if (npid == pid)
- continue;
-
- /* Ignore processes that aren't our kids */
- if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid)
- continue;
-
- if (pid != 0) {
- /* Dang, there's more than one daemonized PID
- in this group, so we don't know what process
- is the main process. */
- pid = 0;
- break;
- }
-
- pid = npid;
- }
-
- return pid;
-}
-
-int manager_setup_cgroup(Manager *m) {
- _cleanup_free_ char *path = NULL;
- int r;
-
- assert(m);
-
- /* 1. Determine hierarchy */
- free(m->cgroup_root);
- m->cgroup_root = NULL;
-
- r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, 0, &m->cgroup_root);
- if (r < 0)
- return log_error_errno(r, "Cannot determine cgroup we are running in: %m");
-
- /* LEGACY: Already in /system.slice? If so, let's cut this
- * off. This is to support live upgrades from older systemd
- * versions where PID 1 was moved there. */
- if (m->running_as == SYSTEMD_SYSTEM) {
- char *e;
-
- e = endswith(m->cgroup_root, "/" SPECIAL_SYSTEM_SLICE);
- if (!e)
- e = endswith(m->cgroup_root, "/system");
- if (e)
- *e = 0;
- }
-
- /* And make sure to store away the root value without trailing
- * slash, even for the root dir, so that we can easily prepend
- * it everywhere. */
- if (streq(m->cgroup_root, "/"))
- m->cgroup_root[0] = 0;
-
- /* 2. Show data */
- r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, NULL, &path);
- if (r < 0)
- return log_error_errno(r, "Cannot find cgroup mount point: %m");
-
- log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
- if (!m->test_run) {
-
- /* 3. Install agent */
- if (m->running_as == SYSTEMD_SYSTEM) {
- r = -EINVAL;
- // cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH);
- if (r < 0)
- log_warning_errno(r, "Failed to install release agent, ignoring: %m");
- else if (r > 0)
- log_debug("Installed release agent.");
- else
- log_debug("Release agent already installed.");
- }
-
- /* 4. Make sure we are in the root cgroup */
- r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, 0);
- if (r < 0)
- return log_error_errno(r, "Failed to create root cgroup hierarchy: %m");
-
- /* 5. 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. Always enable hierarchical support if it exists... */
- cg_set_attribute("memory", "/", "memory.use_hierarchy", "1");
- }
-
- /* 7. Figure out which controllers are supported */
- m->cgroup_supported = cg_mask_supported();
-
- return 0;
-}
-
-void manager_shutdown_cgroup(Manager *m, bool delete) {
- assert(m);
-
- /* We can't really delete the group, since we are in it. But
- * let's trim it. */
- if (delete && m->cgroup_root)
- cg_trim(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, false);
-
- m->pin_cgroupfs_fd = safe_close(m->pin_cgroupfs_fd);
-
- free(m->cgroup_root);
- m->cgroup_root = NULL;
-}
-
-Unit* manager_get_unit_by_cgroup(Manager *m, const char *cgroup) {
- char *p;
- Unit *u;
-
- assert(m);
- assert(cgroup);
-
- u = hashmap_get(m->cgroup_unit, cgroup);
- if (u)
- return u;
-
- p = strdupa(cgroup);
- for (;;) {
- char *e;
-
- e = strrchr(p, '/');
- if (e == p || !e)
- return NULL;
-
- *e = 0;
-
- u = hashmap_get(m->cgroup_unit, p);
- if (u)
- return u;
- }
-}
-
-Unit *manager_get_unit_by_pid(Manager *m, pid_t pid) {
- _cleanup_free_ char *cgroup = NULL;
- int r;
-
- assert(m);
-
- if (pid <= 1)
- return NULL;
-
- r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &cgroup);
- if (r < 0)
- return NULL;
-
- return manager_get_unit_by_cgroup(m, cgroup);
-}
-
-int manager_notify_cgroup_empty(Manager *m, const char *cgroup) {
- Unit *u;
- int r;
-
- assert(m);
- assert(cgroup);
-
- u = manager_get_unit_by_cgroup(m, cgroup);
- if (!u)
- return 0;
-
- r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
- if (r <= 0)
- return r;
-
- if (UNIT_VTABLE(u)->notify_cgroup_empty)
- UNIT_VTABLE(u)->notify_cgroup_empty(u);
-
- unit_add_to_gc_queue(u);
- return 0;
-}
-
-int unit_get_memory_current(Unit *u, uint64_t *ret) {
- _cleanup_free_ char *v = NULL;
- int r;
-
- assert(u);
- assert(ret);
-
- if (!u->cgroup_path)
- return -ENODATA;
-
- if ((u->cgroup_realized_mask & CGROUP_MEMORY) == 0)
- return -ENODATA;
-
- r = cg_get_attribute("memory", u->cgroup_path, "memory.usage_in_bytes", &v);
- if (r == -ENOENT)
- return -ENODATA;
- if (r < 0)
- return r;
-
- return safe_atou64(v, ret);
-}
-
-static int unit_get_cpu_usage_raw(Unit *u, nsec_t *ret) {
- _cleanup_free_ char *v = NULL;
- uint64_t ns;
- int r;
-
- assert(u);
- assert(ret);
-
- if (!u->cgroup_path)
- return -ENODATA;
-
- if ((u->cgroup_realized_mask & CGROUP_CPUACCT) == 0)
- return -ENODATA;
-
- r = cg_get_attribute("cpuacct", u->cgroup_path, "cpuacct.usage", &v);
- if (r == -ENOENT)
- return -ENODATA;
- if (r < 0)
- return r;
-
- r = safe_atou64(v, &ns);
- if (r < 0)
- return r;
-
- *ret = ns;
- return 0;
-}
-
-int unit_get_cpu_usage(Unit *u, nsec_t *ret) {
- nsec_t ns;
- int r;
-
- r = unit_get_cpu_usage_raw(u, &ns);
- if (r < 0)
- return r;
-
- if (ns > u->cpuacct_usage_base)
- ns -= u->cpuacct_usage_base;
- else
- ns = 0;
-
- *ret = ns;
- return 0;
-}
-
-int unit_reset_cpu_usage(Unit *u) {
- nsec_t ns;
- int r;
-
- assert(u);
-
- r = unit_get_cpu_usage_raw(u, &ns);
- if (r < 0) {
- u->cpuacct_usage_base = 0;
- return r;
- }
-
- u->cpuacct_usage_base = ns;
- return 0;
-}
-
-static const char* const cgroup_device_policy_table[_CGROUP_DEVICE_POLICY_MAX] = {
- [CGROUP_AUTO] = "auto",
- [CGROUP_CLOSED] = "closed",
- [CGROUP_STRICT] = "strict",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(cgroup_device_policy, CGroupDevicePolicy);
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
deleted file mode 100644
index 869ddae8c..000000000
--- a/src/core/cgroup.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 "list.h"
-#include "time-util.h"
-
-typedef struct CGroupContext CGroupContext;
-typedef struct CGroupDeviceAllow CGroupDeviceAllow;
-typedef struct CGroupBlockIODeviceWeight CGroupBlockIODeviceWeight;
-typedef struct CGroupBlockIODeviceBandwidth CGroupBlockIODeviceBandwidth;
-
-typedef enum CGroupDevicePolicy {
-
- /* When devices listed, will allow those, plus built-in ones,
- if none are listed will allow everything. */
- CGROUP_AUTO,
-
- /* Everything forbidden, except built-in ones and listed ones. */
- CGROUP_CLOSED,
-
- /* Everythings forbidden, except for the listed devices */
- CGROUP_STRICT,
-
- _CGROUP_DEVICE_POLICY_MAX,
- _CGROUP_DEVICE_POLICY_INVALID = -1
-} CGroupDevicePolicy;
-
-struct CGroupDeviceAllow {
- LIST_FIELDS(CGroupDeviceAllow, device_allow);
- char *path;
- bool r:1;
- bool w:1;
- bool m:1;
-};
-
-struct CGroupBlockIODeviceWeight {
- LIST_FIELDS(CGroupBlockIODeviceWeight, device_weights);
- char *path;
- unsigned long weight;
-};
-
-struct CGroupBlockIODeviceBandwidth {
- LIST_FIELDS(CGroupBlockIODeviceBandwidth, device_bandwidths);
- char *path;
- uint64_t bandwidth;
- bool read;
-};
-
-struct CGroupContext {
- bool cpu_accounting;
- bool blockio_accounting;
- bool memory_accounting;
-
- unsigned long cpu_shares;
- unsigned long startup_cpu_shares;
- usec_t cpu_quota_per_sec_usec;
-
- unsigned long blockio_weight;
- unsigned long startup_blockio_weight;
- LIST_HEAD(CGroupBlockIODeviceWeight, blockio_device_weights);
- LIST_HEAD(CGroupBlockIODeviceBandwidth, blockio_device_bandwidths);
-
- uint64_t memory_limit;
-
- CGroupDevicePolicy device_policy;
- LIST_HEAD(CGroupDeviceAllow, device_allow);
-
- bool delegate;
-};
-
-#include "unit.h"
-#include "cgroup-util.h"
-
-void cgroup_context_init(CGroupContext *c);
-void cgroup_context_done(CGroupContext *c);
-void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix);
-void cgroup_context_apply(CGroupContext *c, CGroupControllerMask mask, const char *path, ManagerState state);
-
-CGroupControllerMask cgroup_context_get_mask(CGroupContext *c);
-
-void cgroup_context_free_device_allow(CGroupContext *c, CGroupDeviceAllow *a);
-void cgroup_context_free_blockio_device_weight(CGroupContext *c, CGroupBlockIODeviceWeight *w);
-void cgroup_context_free_blockio_device_bandwidth(CGroupContext *c, CGroupBlockIODeviceBandwidth *b);
-
-CGroupControllerMask unit_get_cgroup_mask(Unit *u);
-CGroupControllerMask unit_get_siblings_mask(Unit *u);
-CGroupControllerMask unit_get_members_mask(Unit *u);
-CGroupControllerMask unit_get_target_mask(Unit *u);
-
-void unit_update_cgroup_members_masks(Unit *u);
-int unit_realize_cgroup(Unit *u);
-void unit_destroy_cgroup_if_empty(Unit *u);
-int unit_attach_pids_to_cgroup(Unit *u);
-
-int manager_setup_cgroup(Manager *m);
-void manager_shutdown_cgroup(Manager *m, bool delete);
-
-unsigned manager_dispatch_cgroup_queue(Manager *m);
-
-Unit *manager_get_unit_by_cgroup(Manager *m, const char *cgroup);
-Unit* manager_get_unit_by_pid(Manager *m, pid_t pid);
-
-pid_t unit_search_main_pid(Unit *u);
-
-int manager_notify_cgroup_empty(Manager *m, const char *group);
-
-int unit_get_memory_current(Unit *u, uint64_t *ret);
-int unit_get_cpu_usage(Unit *u, nsec_t *ret);
-int unit_reset_cpu_usage(Unit *u);
-
-const char* cgroup_device_policy_to_string(CGroupDevicePolicy i) _const_;
-CGroupDevicePolicy cgroup_device_policy_from_string(const char *s) _pure_;
diff --git a/src/core/dbus-automount.c b/src/core/dbus-automount.c
deleted file mode 100644
index 38acbd0c2..000000000
--- a/src/core/dbus-automount.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 "dbus-automount.h"
-#include "bus-util.h"
-
-static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, automount_result, AutomountResult);
-
-const sd_bus_vtable bus_automount_vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_PROPERTY("Where", "s", NULL, offsetof(Automount, where), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Automount, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Automount, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_VTABLE_END
-};
diff --git a/src/core/dbus-automount.h b/src/core/dbus-automount.h
deleted file mode 100644
index a2b124d75..000000000
--- a/src/core/dbus-automount.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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/>.
-***/
-
-
-extern const sd_bus_vtable bus_automount_vtable[];
diff --git a/src/core/dbus-busname.c b/src/core/dbus-busname.c
deleted file mode 100644
index b1ceb05b1..000000000
--- a/src/core/dbus-busname.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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"
-#include "busname.h"
-#include "dbus-busname.h"
-#include "bus-util.h"
-
-static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, busname_result, BusNameResult);
-
-const sd_bus_vtable bus_busname_vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_PROPERTY("Name", "s", NULL, offsetof(BusName, name), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("TimeoutUSec", "t", bus_property_get_usec, offsetof(BusName, timeout_usec), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(BusName, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(BusName, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("Activating", "b", bus_property_get_bool, offsetof(BusName, activating), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("AcceptFileDescriptors", "b", bus_property_get_bool, offsetof(BusName, accept_fd), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_VTABLE_END
-};
diff --git a/src/core/dbus-busname.h b/src/core/dbus-busname.h
deleted file mode 100644
index ea55b6c8c..000000000
--- a/src/core/dbus-busname.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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/>.
-***/
-
-
-extern const sd_bus_vtable bus_busname_vtable[];
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
deleted file mode 100644
index 4a9df0601..000000000
--- a/src/core/dbus-cgroup.c
+++ /dev/null
@@ -1,680 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 "bus-util.h"
-#include "path-util.h"
-#include "cgroup-util.h"
-#include "cgroup.h"
-#include "dbus-cgroup.h"
-
-static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy);
-
-static int property_get_blockio_device_weight(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- CGroupContext *c = userdata;
- CGroupBlockIODeviceWeight *w;
- int r;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- r = sd_bus_message_open_container(reply, 'a', "(st)");
- if (r < 0)
- return r;
-
- LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
- r = sd_bus_message_append(reply, "(st)", w->path, w->weight);
- if (r < 0)
- return r;
- }
-
- return sd_bus_message_close_container(reply);
-}
-
-static int property_get_blockio_device_bandwidths(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- CGroupContext *c = userdata;
- CGroupBlockIODeviceBandwidth *b;
- int r;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- r = sd_bus_message_open_container(reply, 'a', "(st)");
- if (r < 0)
- return r;
-
- LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
-
- if (streq(property, "BlockIOReadBandwidth") != b->read)
- continue;
-
- r = sd_bus_message_append(reply, "(st)", b->path, b->bandwidth);
- if (r < 0)
- return r;
- }
-
- return sd_bus_message_close_container(reply);
-}
-
-static int property_get_device_allow(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- CGroupContext *c = userdata;
- CGroupDeviceAllow *a;
- int r;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- r = sd_bus_message_open_container(reply, 'a', "(ss)");
- if (r < 0)
- return r;
-
- LIST_FOREACH(device_allow, a, c->device_allow) {
- unsigned k = 0;
- char rwm[4];
-
- if (a->r)
- rwm[k++] = 'r';
- if (a->w)
- rwm[k++] = 'w';
- if (a->m)
- rwm[k++] = 'm';
-
- rwm[k] = 0;
-
- r = sd_bus_message_append(reply, "(ss)", a->path, rwm);
- if (r < 0)
- return r;
- }
-
- return sd_bus_message_close_container(reply);
-}
-
-static int property_get_ulong_as_u64(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- unsigned long *ul = userdata;
-
- assert(bus);
- assert(reply);
- assert(ul);
-
- return sd_bus_message_append(reply, "t", *ul == (unsigned long) -1 ? (uint64_t) -1 : (uint64_t) *ul);
-}
-
-const sd_bus_vtable bus_cgroup_vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_PROPERTY("Delegate", "b", bus_property_get_bool, offsetof(CGroupContext, delegate), 0),
- SD_BUS_PROPERTY("CPUAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, cpu_accounting), 0),
- SD_BUS_PROPERTY("CPUShares", "t", property_get_ulong_as_u64, offsetof(CGroupContext, cpu_shares), 0),
- SD_BUS_PROPERTY("StartupCPUShares", "t", property_get_ulong_as_u64, offsetof(CGroupContext, startup_cpu_shares), 0),
- SD_BUS_PROPERTY("CPUQuotaPerSecUSec", "t", bus_property_get_usec, offsetof(CGroupContext, cpu_quota_per_sec_usec), 0),
- SD_BUS_PROPERTY("BlockIOAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, blockio_accounting), 0),
- SD_BUS_PROPERTY("BlockIOWeight", "t", property_get_ulong_as_u64, offsetof(CGroupContext, blockio_weight), 0),
- SD_BUS_PROPERTY("StartupBlockIOWeight", "t", property_get_ulong_as_u64, offsetof(CGroupContext, startup_blockio_weight), 0),
- SD_BUS_PROPERTY("BlockIODeviceWeight", "a(st)", property_get_blockio_device_weight, 0, 0),
- SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
- SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
- SD_BUS_PROPERTY("MemoryAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, memory_accounting), 0),
- SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0),
- SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0),
- SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0),
- SD_BUS_VTABLE_END
-};
-
-static int bus_cgroup_set_transient_property(
- Unit *u,
- CGroupContext *c,
- const char *name,
- sd_bus_message *message,
- UnitSetPropertiesMode mode,
- sd_bus_error *error) {
-
- int r;
-
- assert(u);
- assert(c);
- assert(name);
- assert(message);
-
- if (streq(name, "Delegate")) {
- int b;
-
- r = sd_bus_message_read(message, "b", &b);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- c->delegate = b;
- unit_write_drop_in_private(u, mode, name, b ? "Delegate=yes" : "Delegate=no");
- }
-
- return 1;
- }
-
- return 0;
-}
-
-int bus_cgroup_set_property(
- Unit *u,
- CGroupContext *c,
- const char *name,
- sd_bus_message *message,
- UnitSetPropertiesMode mode,
- sd_bus_error *error) {
-
- int r;
-
- assert(u);
- assert(c);
- assert(name);
- assert(message);
-
- if (streq(name, "CPUAccounting")) {
- int b;
-
- r = sd_bus_message_read(message, "b", &b);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- c->cpu_accounting = b;
- u->cgroup_realized_mask &= ~CGROUP_CPUACCT;
- unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no");
- }
-
- return 1;
-
- } else if (streq(name, "CPUShares")) {
- uint64_t u64;
- unsigned long ul;
-
- r = sd_bus_message_read(message, "t", &u64);
- if (r < 0)
- return r;
-
- if (u64 == (uint64_t) -1)
- ul = (unsigned long) -1;
- else {
- ul = (unsigned long) u64;
- if (ul <= 0 || (uint64_t) ul != u64)
- return sd_bus_error_set_errnof(error, EINVAL, "CPUShares value out of range");
- }
-
- if (mode != UNIT_CHECK) {
- c->cpu_shares = ul;
- u->cgroup_realized_mask &= ~CGROUP_CPU;
- unit_write_drop_in_private_format(u, mode, name, "CPUShares=%lu", ul);
- }
-
- return 1;
-
- } else if (streq(name, "StartupCPUShares")) {
- uint64_t u64;
- unsigned long ul;
-
- r = sd_bus_message_read(message, "t", &u64);
- if (r < 0)
- return r;
-
- if (u64 == (uint64_t) -1)
- ul = (unsigned long) -1;
- else {
- ul = (unsigned long) u64;
- if (ul <= 0 || (uint64_t) ul != u64)
- return sd_bus_error_set_errnof(error, EINVAL, "StartupCPUShares value out of range");
- }
-
- if (mode != UNIT_CHECK) {
- c->startup_cpu_shares = ul;
- u->cgroup_realized_mask &= ~CGROUP_CPU;
- unit_write_drop_in_private_format(u, mode, name, "StartupCPUShares=%lu", ul);
- }
-
- return 1;
-
- } else if (streq(name, "CPUQuotaPerSecUSec")) {
- uint64_t u64;
-
- r = sd_bus_message_read(message, "t", &u64);
- if (r < 0)
- return r;
-
- if (u64 <= 0)
- return sd_bus_error_set_errnof(error, EINVAL, "CPUQuotaPerSecUSec value out of range");
-
- if (mode != UNIT_CHECK) {
- c->cpu_quota_per_sec_usec = u64;
- u->cgroup_realized_mask &= ~CGROUP_CPU;
- unit_write_drop_in_private_format(u, mode, "CPUQuota", "CPUQuota=%0.f%%", (double) (c->cpu_quota_per_sec_usec / 10000));
- }
-
- return 1;
-
- } else if (streq(name, "BlockIOAccounting")) {
- int b;
-
- r = sd_bus_message_read(message, "b", &b);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- c->blockio_accounting = b;
- u->cgroup_realized_mask &= ~CGROUP_BLKIO;
- unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no");
- }
-
- return 1;
-
- } else if (streq(name, "BlockIOWeight")) {
- uint64_t u64;
- unsigned long ul;
-
- r = sd_bus_message_read(message, "t", &u64);
- if (r < 0)
- return r;
-
- if (u64 == (uint64_t) -1)
- ul = (unsigned long) -1;
- else {
- ul = (unsigned long) u64;
- if (ul < 10 || ul > 1000)
- return sd_bus_error_set_errnof(error, EINVAL, "BlockIOWeight value out of range");
- }
-
- if (mode != UNIT_CHECK) {
- c->blockio_weight = ul;
- u->cgroup_realized_mask &= ~CGROUP_BLKIO;
- unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%lu", ul);
- }
-
- return 1;
-
- } else if (streq(name, "StartupBlockIOWeight")) {
- uint64_t u64;
- unsigned long ul;
-
- r = sd_bus_message_read(message, "t", &u64);
- if (r < 0)
- return r;
-
- if (u64 == (uint64_t) -1)
- ul = (unsigned long) -1;
- else {
- ul = (unsigned long) u64;
- if (ul < 10 || ul > 1000)
- return sd_bus_error_set_errnof(error, EINVAL, "StartupBlockIOWeight value out of range");
- }
-
- if (mode != UNIT_CHECK) {
- c->startup_blockio_weight = ul;
- u->cgroup_realized_mask &= ~CGROUP_BLKIO;
- unit_write_drop_in_private_format(u, mode, name, "StartupBlockIOWeight=%lu", ul);
- }
-
- return 1;
-
- } else if (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth")) {
- const char *path;
- bool read = true;
- unsigned n = 0;
- uint64_t u64;
-
- if (streq(name, "BlockIOWriteBandwidth"))
- read = false;
-
- r = sd_bus_message_enter_container(message, 'a', "(st)");
- if (r < 0)
- return r;
-
- while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
-
- if (mode != UNIT_CHECK) {
- CGroupBlockIODeviceBandwidth *a = NULL, *b;
-
- LIST_FOREACH(device_bandwidths, b, c->blockio_device_bandwidths) {
- if (path_equal(path, b->path) && read == b->read) {
- a = b;
- break;
- }
- }
-
- if (!a) {
- a = new0(CGroupBlockIODeviceBandwidth, 1);
- if (!a)
- return -ENOMEM;
-
- a->read = read;
- a->path = strdup(path);
- if (!a->path) {
- free(a);
- return -ENOMEM;
- }
-
- LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, a);
- }
-
- a->bandwidth = u64;
- }
-
- n++;
- }
- if (r < 0)
- return r;
-
- r = sd_bus_message_exit_container(message);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- CGroupBlockIODeviceBandwidth *a, *next;
- _cleanup_free_ char *buf = NULL;
- _cleanup_fclose_ FILE *f = NULL;
- size_t size = 0;
-
- if (n == 0) {
- LIST_FOREACH_SAFE(device_bandwidths, a, next, c->blockio_device_bandwidths)
- if (a->read == read)
- cgroup_context_free_blockio_device_bandwidth(c, a);
- }
-
- u->cgroup_realized_mask &= ~CGROUP_BLKIO;
-
- f = open_memstream(&buf, &size);
- if (!f)
- return -ENOMEM;
-
- if (read) {
- fputs("BlockIOReadBandwidth=\n", f);
- LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
- if (a->read)
- fprintf(f, "BlockIOReadBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
- } else {
- fputs("BlockIOWriteBandwidth=\n", f);
- LIST_FOREACH(device_bandwidths, a, c->blockio_device_bandwidths)
- if (!a->read)
- fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
- }
-
- fflush(f);
- unit_write_drop_in_private(u, mode, name, buf);
- }
-
- return 1;
-
- } else if (streq(name, "BlockIODeviceWeight")) {
- const char *path;
- uint64_t u64;
- unsigned n = 0;
-
- r = sd_bus_message_enter_container(message, 'a', "(st)");
- if (r < 0)
- return r;
-
- while ((r = sd_bus_message_read(message, "(st)", &path, &u64)) > 0) {
- unsigned long ul = u64;
-
- if (ul < 10 || ul > 1000)
- return sd_bus_error_set_errnof(error, EINVAL, "BlockIODeviceWeight out of range");
-
- if (mode != UNIT_CHECK) {
- CGroupBlockIODeviceWeight *a = NULL, *b;
-
- LIST_FOREACH(device_weights, b, c->blockio_device_weights) {
- if (path_equal(b->path, path)) {
- a = b;
- break;
- }
- }
-
- if (!a) {
- a = new0(CGroupBlockIODeviceWeight, 1);
- if (!a)
- return -ENOMEM;
-
- a->path = strdup(path);
- if (!a->path) {
- free(a);
- return -ENOMEM;
- }
- LIST_PREPEND(device_weights,c->blockio_device_weights, a);
- }
-
- a->weight = ul;
- }
-
- n++;
- }
-
- r = sd_bus_message_exit_container(message);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- _cleanup_free_ char *buf = NULL;
- _cleanup_fclose_ FILE *f = NULL;
- CGroupBlockIODeviceWeight *a;
- size_t size = 0;
-
- if (n == 0) {
- while (c->blockio_device_weights)
- cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
- }
-
- u->cgroup_realized_mask &= ~CGROUP_BLKIO;
-
- f = open_memstream(&buf, &size);
- if (!f)
- return -ENOMEM;
-
- fputs("BlockIODeviceWeight=\n", f);
- LIST_FOREACH(device_weights, a, c->blockio_device_weights)
- fprintf(f, "BlockIODeviceWeight=%s %lu\n", a->path, a->weight);
-
- fflush(f);
- unit_write_drop_in_private(u, mode, name, buf);
- }
-
- return 1;
-
- } else if (streq(name, "MemoryAccounting")) {
- int b;
-
- r = sd_bus_message_read(message, "b", &b);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- c->memory_accounting = b;
- u->cgroup_realized_mask &= ~CGROUP_MEMORY;
- unit_write_drop_in_private(u, mode, name, b ? "MemoryAccounting=yes" : "MemoryAccounting=no");
- }
-
- return 1;
-
- } else if (streq(name, "MemoryLimit")) {
- uint64_t limit;
-
- r = sd_bus_message_read(message, "t", &limit);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- c->memory_limit = limit;
- u->cgroup_realized_mask &= ~CGROUP_MEMORY;
- unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, limit);
- }
-
- return 1;
-
- } else if (streq(name, "DevicePolicy")) {
- const char *policy;
- CGroupDevicePolicy p;
-
- r = sd_bus_message_read(message, "s", &policy);
- if (r < 0)
- return r;
-
- p = cgroup_device_policy_from_string(policy);
- if (p < 0)
- return -EINVAL;
-
- if (mode != UNIT_CHECK) {
- char *buf;
-
- c->device_policy = p;
- u->cgroup_realized_mask &= ~CGROUP_DEVICE;
-
- buf = strjoina("DevicePolicy=", policy);
- unit_write_drop_in_private(u, mode, name, buf);
- }
-
- return 1;
-
- } else if (streq(name, "DeviceAllow")) {
- const char *path, *rwm;
- unsigned n = 0;
-
- r = sd_bus_message_enter_container(message, 'a', "(ss)");
- if (r < 0)
- return r;
-
- while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
-
- if ((!startswith(path, "/dev/") &&
- !startswith(path, "block-") &&
- !startswith(path, "char-")) ||
- strpbrk(path, WHITESPACE))
- return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires device node");
-
- if (isempty(rwm))
- rwm = "rwm";
-
- if (!in_charset(rwm, "rwm"))
- return sd_bus_error_set_errnof(error, EINVAL, "DeviceAllow= requires combination of rwm flags");
-
- if (mode != UNIT_CHECK) {
- CGroupDeviceAllow *a = NULL, *b;
-
- LIST_FOREACH(device_allow, b, c->device_allow) {
- if (path_equal(b->path, path)) {
- a = b;
- break;
- }
- }
-
- if (!a) {
- a = new0(CGroupDeviceAllow, 1);
- if (!a)
- return -ENOMEM;
-
- a->path = strdup(path);
- if (!a->path) {
- free(a);
- return -ENOMEM;
- }
-
- LIST_PREPEND(device_allow, c->device_allow, a);
- }
-
- a->r = !!strchr(rwm, 'r');
- a->w = !!strchr(rwm, 'w');
- a->m = !!strchr(rwm, 'm');
- }
-
- n++;
- }
- if (r < 0)
- return r;
-
- r = sd_bus_message_exit_container(message);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- _cleanup_free_ char *buf = NULL;
- _cleanup_fclose_ FILE *f = NULL;
- CGroupDeviceAllow *a;
- size_t size = 0;
-
- if (n == 0) {
- while (c->device_allow)
- cgroup_context_free_device_allow(c, c->device_allow);
- }
-
- u->cgroup_realized_mask &= ~CGROUP_DEVICE;
-
- f = open_memstream(&buf, &size);
- if (!f)
- return -ENOMEM;
-
- fputs("DeviceAllow=\n", f);
- LIST_FOREACH(device_allow, a, c->device_allow)
- fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
-
- fflush(f);
- unit_write_drop_in_private(u, mode, name, buf);
- }
-
- return 1;
-
- }
-
- if (u->transient && u->load_state == UNIT_STUB) {
- r = bus_cgroup_set_transient_property(u, c, name, message, mode, error);
- if (r != 0)
- return r;
-
- }
-
- return 0;
-}
diff --git a/src/core/dbus-cgroup.h b/src/core/dbus-cgroup.h
deleted file mode 100644
index c2a3910f3..000000000
--- a/src/core/dbus-cgroup.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 "cgroup.h"
-
-extern const sd_bus_vtable bus_cgroup_vtable[];
-
-int bus_cgroup_set_property(Unit *u, CGroupContext *c, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error);
diff --git a/src/core/dbus-device.c b/src/core/dbus-device.c
deleted file mode 100644
index cb156fd37..000000000
--- a/src/core/dbus-device.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 "device.h"
-#include "dbus-device.h"
-
-const sd_bus_vtable bus_device_vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_PROPERTY("SysFSPath", "s", NULL, offsetof(Device, sysfs), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_VTABLE_END
-};
diff --git a/src/core/dbus-device.h b/src/core/dbus-device.h
deleted file mode 100644
index 10e945e40..000000000
--- a/src/core/dbus-device.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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"
-
-extern const sd_bus_vtable bus_device_vtable[];
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
deleted file mode 100644
index a9f7971cd..000000000
--- a/src/core/dbus-execute.c
+++ /dev/null
@@ -1,1006 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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/prctl.h>
-
-#ifdef HAVE_SECCOMP
-#include <seccomp.h>
-#endif
-
-#include "bus-util.h"
-#include "missing.h"
-#include "ioprio.h"
-#include "strv.h"
-#include "fileio.h"
-#include "execute.h"
-#include "capability.h"
-#include "env-util.h"
-#include "af-list.h"
-#include "namespace.h"
-#include "path-util.h"
-#include "dbus-execute.h"
-
-#ifdef HAVE_SECCOMP
-#include "seccomp-util.h"
-#endif
-
-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(bus_property_get_protect_home, protect_home, ProtectHome);
-static BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_protect_system, protect_system, ProtectSystem);
-
-static int property_get_environment_files(
- 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;
- char **j;
- int r;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- r = sd_bus_message_open_container(reply, 'a', "(sb)");
- if (r < 0)
- return r;
-
- STRV_FOREACH(j, c->environment_files) {
- const char *fn = *j;
-
- r = sd_bus_message_append(reply, "(sb)", fn[0] == '-' ? fn + 1 : fn, fn[0] == '-');
- if (r < 0)
- return r;
- }
-
- return sd_bus_message_close_container(reply);
-}
-
-static int property_get_rlimit(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- struct rlimit *rl;
- uint64_t u;
- rlim_t x;
-
- assert(bus);
- assert(reply);
- assert(userdata);
-
- rl = *(struct rlimit**) userdata;
- if (rl)
- x = rl->rlim_max;
- else {
- struct rlimit buf = {};
- int z;
-
- z = rlimit_from_string(property);
- assert(z >= 0);
-
- getrlimit(z, &buf);
- x = buf.rlim_max;
- }
-
- /* rlim_t might have different sizes, let's map
- * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
- * all archs */
- u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
-
- return sd_bus_message_append(reply, "t", u);
-}
-
-static int property_get_oom_score_adjust(
- 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;
- int32_t n;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- if (c->oom_score_adjust_set)
- n = c->oom_score_adjust;
- else {
- _cleanup_free_ char *t = NULL;
-
- n = 0;
- if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0)
- safe_atoi(t, &n);
- }
-
- return sd_bus_message_append(reply, "i", n);
-}
-
-static int property_get_nice(
- 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;
- int32_t n;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- if (c->nice_set)
- n = c->nice;
- else {
- errno = 0;
- n = getpriority(PRIO_PROCESS, 0);
- if (errno != 0)
- n = 0;
- }
-
- 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;
- int32_t n;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- if (c->ioprio_set)
- n = c->ioprio;
- else {
- n = ioprio_get(IOPRIO_WHO_PROCESS, 0);
- if (n < 0)
- n = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 4);
- }
-
- return sd_bus_message_append(reply, "i", n);
-}
-
-static int property_get_cpu_sched_policy(
- 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;
- int32_t n;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- if (c->cpu_sched_set)
- n = c->cpu_sched_policy;
- else {
- n = sched_getscheduler(0);
- if (n < 0)
- n = SCHED_OTHER;
- }
-
- return sd_bus_message_append(reply, "i", n);
-}
-
-static int property_get_cpu_sched_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;
- int32_t n;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- if (c->cpu_sched_set)
- n = c->cpu_sched_priority;
- else {
- struct sched_param p = {};
-
- if (sched_getparam(0, &p) >= 0)
- n = p.sched_priority;
- else
- n = 0;
- }
-
- return sd_bus_message_append(reply, "i", n);
-}
-
-static int property_get_cpu_affinity(
- 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);
-
- 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);
-}
-
-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) {
-
- ExecContext *c = userdata;
- uint64_t u;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- if (c->timer_slack_nsec != NSEC_INFINITY)
- u = (uint64_t) c->timer_slack_nsec;
- else
- u = (uint64_t) prctl(PR_GET_TIMERSLACK);
-
- 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);
-
- /* We store this negated internally, to match the kernel, but
- * we expose it normalized. */
- return sd_bus_message_append(reply, "t", ~c->capability_bounding_set_drop);
-}
-
-static int property_get_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;
- _cleanup_cap_free_charp_ char *t = NULL;
- const char *s;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- if (c->capabilities)
- s = t = cap_to_text(c->capabilities, NULL);
- else
- s = "";
-
- if (!s)
- return -ENOMEM;
-
- return sd_bus_message_append(reply, "s", s);
-}
-
-static int property_get_syscall_filter(
- 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;
- _cleanup_strv_free_ char **l = NULL;
- int r;
-
-#ifdef HAVE_SECCOMP
- Iterator i;
- void *id;
-#endif
-
- assert(bus);
- assert(reply);
- assert(c);
-
- r = sd_bus_message_open_container(reply, 'r', "bas");
- if (r < 0)
- return r;
-
- r = sd_bus_message_append(reply, "b", c->syscall_whitelist);
- if (r < 0)
- return r;
-
-#ifdef HAVE_SECCOMP
- SET_FOREACH(id, c->syscall_filter, i) {
- char *name;
-
- name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
- if (!name)
- continue;
-
- r = strv_consume(&l, name);
- if (r < 0)
- return r;
- }
-#endif
-
- strv_sort(l);
-
- r = sd_bus_message_append_strv(reply, l);
- if (r < 0)
- return r;
-
- return sd_bus_message_close_container(reply);
-}
-
-static int property_get_syscall_archs(
- 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;
- _cleanup_strv_free_ char **l = NULL;
- int r;
-
-#ifdef HAVE_SECCOMP
- Iterator i;
- void *id;
-#endif
-
- assert(bus);
- assert(reply);
- assert(c);
-
-#ifdef HAVE_SECCOMP
- SET_FOREACH(id, c->syscall_archs, i) {
- const char *name;
-
- name = seccomp_arch_to_string(PTR_TO_UINT32(id) - 1);
- if (!name)
- continue;
-
- r = strv_extend(&l, name);
- if (r < 0)
- return -ENOMEM;
- }
-#endif
-
- strv_sort(l);
-
- r = sd_bus_message_append_strv(reply, l);
- if (r < 0)
- return r;
-
- 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,
- 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, "(bs)", c->selinux_context_ignore, c->selinux_context);
-}
-
-static int property_get_apparmor_profile(
- 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, "(bs)", c->apparmor_profile_ignore, c->apparmor_profile);
-}
-
-static int property_get_smack_process_label(
- 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, "(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,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- ExecContext *c = userdata;
- _cleanup_strv_free_ char **l = NULL;
- Iterator i;
- void *af;
- int r;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- r = sd_bus_message_open_container(reply, 'r', "bas");
- if (r < 0)
- return r;
-
- r = sd_bus_message_append(reply, "b", c->address_families_whitelist);
- if (r < 0)
- return r;
-
- SET_FOREACH(af, c->address_families, i) {
- const char *name;
-
- name = af_to_name(PTR_TO_INT(af));
- if (!name)
- continue;
-
- r = strv_extend(&l, name);
- if (r < 0)
- return -ENOMEM;
- }
-
- strv_sort(l);
-
- r = sd_bus_message_append_strv(reply, l);
- if (r < 0)
- return r;
-
- return sd_bus_message_close_container(reply);
-}
-
-const sd_bus_vtable bus_exec_vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("EnvironmentFiles", "a(sb)", property_get_environment_files, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("UMask", "u", bus_property_get_mode, offsetof(ExecContext, umask), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitCPU", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitFSIZE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitDATA", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitSTACK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitCORE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitRSS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitNOFILE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitAS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitNPROC", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitMEMLOCK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitLOCKS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitSIGPENDING", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitMSGQUEUE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitNICE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitRTPRIO", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitRTTIME", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("WorkingDirectory", "s", NULL, offsetof(ExecContext, working_directory), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Nice", "i", property_get_nice, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("IOScheduling", "i", property_get_ioprio, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("CPUSchedulingPolicy", "i", property_get_cpu_sched_policy, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("CPUSchedulingPriority", "i", property_get_cpu_sched_priority, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("CPUAffinity", "ay", property_get_cpu_affinity, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("CPUSchedulingResetOnFork", "b", bus_property_get_bool, offsetof(ExecContext, cpu_sched_reset_on_fork), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("NonBlocking", "b", bus_property_get_bool, offsetof(ExecContext, non_blocking), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("StandardInput", "s", property_get_exec_input, offsetof(ExecContext, std_input), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("StandardOutput", "s", bus_property_get_exec_output, offsetof(ExecContext, std_output), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("StandardError", "s", bus_property_get_exec_output, offsetof(ExecContext, std_error), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("TTYPath", "s", NULL, offsetof(ExecContext, tty_path), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("TTYReset", "b", bus_property_get_bool, offsetof(ExecContext, tty_reset), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("TTYVHangup", "b", bus_property_get_bool, offsetof(ExecContext, tty_vhangup), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("TTYVTDisallocate", "b", bus_property_get_bool, offsetof(ExecContext, tty_vt_disallocate), SD_BUS_VTABLE_PROPERTY_CONST),
- 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("Capabilities", "s", property_get_capabilities, 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("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("SupplementaryGroups", "as", NULL, offsetof(ExecContext, supplementary_groups), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("PAMName", "s", NULL, offsetof(ExecContext, pam_name), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("ReadWriteDirectories", "as", NULL, offsetof(ExecContext, read_write_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("ReadOnlyDirectories", "as", NULL, offsetof(ExecContext, read_only_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("InaccessibleDirectories", "as", NULL, offsetof(ExecContext, inaccessible_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("MountFlags", "t", bus_property_get_ulong, offsetof(ExecContext, mount_flags), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("PrivateTmp", "b", bus_property_get_bool, offsetof(ExecContext, private_tmp), 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("PrivateDevices", "b", bus_property_get_bool, offsetof(ExecContext, private_devices), 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("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("SELinuxContext", "(bs)", property_get_selinux_context, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("AppArmorProfile", "(bs)", property_get_apparmor_profile, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("SmackProcessLabel", "(bs)", property_get_smack_process_label, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("IgnoreSIGPIPE", "b", bus_property_get_bool, offsetof(ExecContext, ignore_sigpipe), SD_BUS_VTABLE_PROPERTY_CONST),
- 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("RestrictAddressFamilies", "(bas)", property_get_address_families, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RuntimeDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, runtime_directory_mode), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RuntimeDirectory", "as", NULL, offsetof(ExecContext, runtime_directory), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_VTABLE_END
-};
-
-static int append_exec_command(sd_bus_message *reply, ExecCommand *c) {
- int r;
-
- assert(reply);
- assert(c);
-
- if (!c->path)
- return 0;
-
- r = sd_bus_message_open_container(reply, 'r', "sasbttttuii");
- if (r < 0)
- return r;
-
- r = sd_bus_message_append(reply, "s", c->path);
- if (r < 0)
- return r;
-
- r = sd_bus_message_append_strv(reply, c->argv);
- if (r < 0)
- return r;
-
- r = sd_bus_message_append(reply, "bttttuii",
- c->ignore,
- c->exec_status.start_timestamp.realtime,
- c->exec_status.start_timestamp.monotonic,
- c->exec_status.exit_timestamp.realtime,
- c->exec_status.exit_timestamp.monotonic,
- (uint32_t) c->exec_status.pid,
- (int32_t) c->exec_status.code,
- (int32_t) c->exec_status.status);
- if (r < 0)
- return r;
-
- return sd_bus_message_close_container(reply);
-}
-
-int bus_property_get_exec_command(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *ret_error) {
-
- ExecCommand *c = (ExecCommand*) userdata;
- int r;
-
- assert(bus);
- assert(reply);
-
- r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)");
- if (r < 0)
- return r;
-
- r = append_exec_command(reply, c);
- if (r < 0)
- return r;
-
- return sd_bus_message_close_container(reply);
-}
-
-int bus_property_get_exec_command_list(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *ret_error) {
-
- ExecCommand *c = *(ExecCommand**) userdata;
- int r;
-
- assert(bus);
- assert(reply);
-
- r = sd_bus_message_open_container(reply, 'a', "(sasbttttuii)");
- if (r < 0)
- return r;
-
- LIST_FOREACH(command, c, c) {
- r = append_exec_command(reply, c);
- if (r < 0)
- return r;
- }
-
- return sd_bus_message_close_container(reply);
-}
-
-int bus_exec_context_set_transient_property(
- Unit *u,
- ExecContext *c,
- const char *name,
- sd_bus_message *message,
- UnitSetPropertiesMode mode,
- sd_bus_error *error) {
-
- int r;
-
- assert(u);
- assert(c);
- assert(name);
- assert(message);
-
- if (streq(name, "User")) {
- const char *uu;
-
- r = sd_bus_message_read(message, "s", &uu);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
-
- if (isempty(uu)) {
- free(c->user);
- c->user = NULL;
- } else {
- char *t;
-
- t = strdup(uu);
- if (!t)
- return -ENOMEM;
-
- free(c->user);
- c->user = t;
- }
-
- unit_write_drop_in_private_format(u, mode, name, "User=%s\n", uu);
- }
-
- return 1;
-
- } else if (streq(name, "Group")) {
- const char *gg;
-
- r = sd_bus_message_read(message, "s", &gg);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
-
- if (isempty(gg)) {
- free(c->group);
- c->group = NULL;
- } else {
- char *t;
-
- t = strdup(gg);
- if (!t)
- return -ENOMEM;
-
- free(c->group);
- c->group = t;
- }
-
- unit_write_drop_in_private_format(u, mode, name, "Group=%s\n", gg);
- }
-
- return 1;
-
- } else if (streq(name, "Nice")) {
- int n;
-
- r = sd_bus_message_read(message, "i", &n);
- if (r < 0)
- return r;
-
- if (n < PRIO_MIN || n >= PRIO_MAX)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Nice value out of range");
-
- if (mode != UNIT_CHECK) {
- c->nice = n;
- unit_write_drop_in_private_format(u, mode, name, "Nice=%i\n", n);
- }
-
- return 1;
-
- } else if (streq(name, "TTYPath")) {
- const char *tty;
-
- r = sd_bus_message_read(message, "s", &tty);
- if (r < 0)
- return r;
-
- if (!path_is_absolute(tty))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "TTY device not absolute path");
-
- if (mode != UNIT_CHECK) {
- char *t;
-
- t = strdup(tty);
- if (!t)
- return -ENOMEM;
-
- free(c->tty_path);
- c->tty_path = t;
-
- unit_write_drop_in_private_format(u, mode, name, "TTYPath=%s\n", tty);
- }
-
- return 1;
-
- } else if (streq(name, "StandardInput")) {
- const char *s;
- ExecInput p;
-
- r = sd_bus_message_read(message, "s", &s);
- if (r < 0)
- return r;
-
- p = exec_input_from_string(s);
- if (p < 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid standard input name");
-
- if (mode != UNIT_CHECK) {
- c->std_input = p;
-
- unit_write_drop_in_private_format(u, mode, name, "StandardInput=%s\n", exec_input_to_string(p));
- }
-
- return 1;
-
-
- } else if (streq(name, "StandardOutput")) {
- const char *s;
- ExecOutput p;
-
- r = sd_bus_message_read(message, "s", &s);
- if (r < 0)
- return r;
-
- p = exec_output_from_string(s);
- if (p < 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid standard output name");
-
- if (mode != UNIT_CHECK) {
- c->std_output = p;
-
- unit_write_drop_in_private_format(u, mode, name, "StandardOutput=%s\n", exec_output_to_string(p));
- }
-
- return 1;
-
- } else if (streq(name, "StandardError")) {
- const char *s;
- ExecOutput p;
-
- r = sd_bus_message_read(message, "s", &s);
- if (r < 0)
- return r;
-
- p = exec_output_from_string(s);
- if (p < 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid standard error name");
-
- if (mode != UNIT_CHECK) {
- c->std_error = p;
-
- unit_write_drop_in_private_format(u, mode, name, "StandardError=%s\n", exec_output_to_string(p));
- }
-
- return 1;
-
- } else if (streq(name, "Environment")) {
-
- _cleanup_strv_free_ char **l = NULL;
-
- r = sd_bus_message_read_strv(message, &l);
- if (r < 0)
- return r;
-
- if (!strv_env_is_valid(l))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment block.");
-
- if (mode != UNIT_CHECK) {
- _cleanup_free_ char *joined = NULL;
- char **e;
-
- e = strv_env_merge(2, c->environment, l);
- if (!e)
- return -ENOMEM;
-
- strv_free(c->environment);
- c->environment = e;
-
- joined = strv_join_quoted(c->environment);
- if (!joined)
- return -ENOMEM;
-
- unit_write_drop_in_private_format(u, mode, name, "Environment=%s\n", joined);
- }
-
- return 1;
-
- } else if (rlimit_from_string(name) >= 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 (mode != UNIT_CHECK) {
- int z;
-
- z = rlimit_from_string(name);
-
- if (!c->rlimit[z]) {
- c->rlimit[z] = new(struct rlimit, 1);
- if (!c->rlimit[z])
- return -ENOMEM;
- }
-
- c->rlimit[z]->rlim_cur = c->rlimit[z]->rlim_max = x;
-
- if (x == RLIM_INFINITY)
- unit_write_drop_in_private_format(u, mode, name, "%s=infinity\n", name);
- else
- unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64 "\n", name, rl);
- }
-
- return 1;
- }
-
- return 0;
-}
diff --git a/src/core/dbus-execute.h b/src/core/dbus-execute.h
deleted file mode 100644
index e4c2d5ddf..000000000
--- a/src/core/dbus-execute.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 "execute.h"
-
-#define BUS_EXEC_STATUS_VTABLE(prefix, offset, flags) \
- BUS_PROPERTY_DUAL_TIMESTAMP(prefix "StartTimestamp", (offset) + offsetof(ExecStatus, start_timestamp), flags), \
- BUS_PROPERTY_DUAL_TIMESTAMP(prefix "ExitTimestamp", (offset) + offsetof(ExecStatus, exit_timestamp), flags), \
- SD_BUS_PROPERTY(prefix "PID", "u", bus_property_get_pid, (offset) + offsetof(ExecStatus, pid), flags), \
- SD_BUS_PROPERTY(prefix "Code", "i", bus_property_get_int, (offset) + offsetof(ExecStatus, code), flags), \
- SD_BUS_PROPERTY(prefix "Status", "i", bus_property_get_int, (offset) + offsetof(ExecStatus, status), flags)
-
-#define BUS_EXEC_COMMAND_VTABLE(name, offset, flags) \
- SD_BUS_PROPERTY(name, "a(sasbttttuii)", bus_property_get_exec_command, offset, flags)
-
-#define BUS_EXEC_COMMAND_LIST_VTABLE(name, offset, flags) \
- SD_BUS_PROPERTY(name, "a(sasbttttuii)", bus_property_get_exec_command_list, offset, flags)
-
-extern const sd_bus_vtable bus_exec_vtable[];
-
-int bus_property_get_exec_output(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *ret_error);
-int bus_property_get_exec_command(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *ret_error);
-int bus_property_get_exec_command_list(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *ret_error);
-
-int bus_exec_context_set_transient_property(Unit *u, ExecContext *c, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error);
diff --git a/src/core/dbus-job.c b/src/core/dbus-job.c
deleted file mode 100644
index fa1d1f338..000000000
--- a/src/core/dbus-job.c
+++ /dev/null
@@ -1,193 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 "log.h"
-#include "sd-bus.h"
-#include "selinux-access.h"
-#include "job.h"
-#include "dbus-job.h"
-#include "dbus.h"
-
-static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, job_type, JobType);
-static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_state, job_state, JobState);
-
-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) {
-
- _cleanup_free_ char *p = NULL;
- Job *j = userdata;
-
- assert(bus);
- assert(reply);
- assert(j);
-
- p = unit_dbus_path(j->unit);
- if (!p)
- return -ENOMEM;
-
- return sd_bus_message_append(reply, "(so)", j->unit->id, p);
-}
-
-int bus_job_method_cancel(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Job *j = userdata;
- int r;
-
- assert(bus);
- assert(message);
- assert(j);
-
- r = mac_selinux_unit_access_check(j->unit, message, "stop", error);
- if (r < 0)
- return r;
-
- /* Access is granted to the job owner */
- if (!sd_bus_track_contains(j->clients, sd_bus_message_get_sender(message))) {
-
- /* And for everybody else consult PolicyKit */
- r = bus_verify_manage_units_async(j->unit->manager, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
- }
-
- job_finish_and_invalidate(j, JOB_CANCELED, true);
-
- return sd_bus_reply_method_return(message, NULL);
-}
-
-const sd_bus_vtable bus_job_vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_METHOD("Cancel", NULL, NULL, bus_job_method_cancel, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_PROPERTY("Id", "u", NULL, offsetof(Job, id), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Unit", "(so)", property_get_unit, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("JobType", "s", property_get_type, offsetof(Job, type), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("State", "s", property_get_state, offsetof(Job, state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_VTABLE_END
-};
-
-static int send_new_signal(sd_bus *bus, void *userdata) {
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
- _cleanup_free_ char *p = NULL;
- Job *j = userdata;
- int r;
-
- assert(bus);
- assert(j);
-
- p = job_dbus_path(j);
- if (!p)
- return -ENOMEM;
-
- r = sd_bus_message_new_signal(
- bus,
- &m,
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "JobNew");
- if (r < 0)
- return r;
-
- r = sd_bus_message_append(m, "uos", j->id, p, j->unit->id);
- if (r < 0)
- return r;
-
- return sd_bus_send(bus, m, NULL);
-}
-
-static int send_changed_signal(sd_bus *bus, void *userdata) {
- _cleanup_free_ char *p = NULL;
- Job *j = userdata;
-
- assert(bus);
- assert(j);
-
- p = job_dbus_path(j);
- if (!p)
- return -ENOMEM;
-
- return sd_bus_emit_properties_changed(bus, p, "org.freedesktop.systemd1.Job", "State", NULL);
-}
-
-void bus_job_send_change_signal(Job *j) {
- int r;
-
- assert(j);
-
- if (j->in_dbus_queue) {
- LIST_REMOVE(dbus_queue, j->manager->dbus_job_queue, j);
- j->in_dbus_queue = false;
- }
-
- r = bus_foreach_bus(j->manager, j->clients, j->sent_dbus_new_signal ? send_changed_signal : send_new_signal, j);
- if (r < 0)
- log_debug_errno(r, "Failed to send job change signal for %u: %m", j->id);
-
- j->sent_dbus_new_signal = true;
-}
-
-static int send_removed_signal(sd_bus *bus, void *userdata) {
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
- _cleanup_free_ char *p = NULL;
- Job *j = userdata;
- int r;
-
- assert(bus);
- assert(j);
-
- p = job_dbus_path(j);
- if (!p)
- return -ENOMEM;
-
- r = sd_bus_message_new_signal(
- bus,
- &m,
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "JobRemoved");
- if (r < 0)
- return r;
-
- r = sd_bus_message_append(m, "uoss", j->id, p, j->unit->id, job_result_to_string(j->result));
- if (r < 0)
- return r;
-
- return sd_bus_send(bus, m, NULL);
-}
-
-void bus_job_send_removed_signal(Job *j) {
- int r;
-
- assert(j);
-
- if (!j->sent_dbus_new_signal)
- bus_job_send_change_signal(j);
-
- r = bus_foreach_bus(j->manager, j->clients, send_removed_signal, j);
- if (r < 0)
- log_debug_errno(r, "Failed to send job remove signal for %u: %m", j->id);
-}
diff --git a/src/core/dbus-job.h b/src/core/dbus-job.h
deleted file mode 100644
index 6c2fc0789..000000000
--- a/src/core/dbus-job.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 "job.h"
-
-extern const sd_bus_vtable bus_job_vtable[];
-
-int bus_job_method_cancel(sd_bus *bus, sd_bus_message *message, void *job, sd_bus_error *error);
-
-void bus_job_send_change_signal(Job *j);
-void bus_job_send_removed_signal(Job *j);
diff --git a/src/core/dbus-kill.c b/src/core/dbus-kill.c
deleted file mode 100644
index fb29e147c..000000000
--- a/src/core/dbus-kill.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 "dbus-kill.h"
-#include "bus-util.h"
-
-static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_kill_mode, kill_mode, KillMode);
-
-const sd_bus_vtable bus_kill_vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_PROPERTY("KillMode", "s", property_get_kill_mode, offsetof(KillContext, kill_mode), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("KillSignal", "i", bus_property_get_int, offsetof(KillContext, kill_signal), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("SendSIGKILL", "b", bus_property_get_bool, offsetof(KillContext, send_sigkill), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("SendSIGHUP", "b", bus_property_get_bool, offsetof(KillContext, send_sighup), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_VTABLE_END
-};
-
-int bus_kill_context_set_transient_property(
- Unit *u,
- KillContext *c,
- const char *name,
- sd_bus_message *message,
- UnitSetPropertiesMode mode,
- sd_bus_error *error) {
-
- int r;
-
- assert(u);
- assert(c);
- assert(name);
- assert(message);
-
- if (streq(name, "KillMode")) {
- const char *m;
- KillMode k;
-
- r = sd_bus_message_read(message, "s", &m);
- if (r < 0)
- return r;
-
- k = kill_mode_from_string(m);
- if (k < 0)
- return -EINVAL;
-
- if (mode != UNIT_CHECK) {
- c->kill_mode = k;
-
- unit_write_drop_in_private_format(u, mode, name, "KillMode=%s\n", kill_mode_to_string(k));
- }
-
- return 1;
-
- } else if (streq(name, "KillSignal")) {
- int sig;
-
- r = sd_bus_message_read(message, "i", &sig);
- if (r < 0)
- return r;
-
- if (sig <= 0 || sig >= _NSIG)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal %i out of range", sig);
-
- if (mode != UNIT_CHECK) {
- c->kill_signal = sig;
-
- unit_write_drop_in_private_format(u, mode, name, "KillSignal=%s\n", signal_to_string(sig));
- }
-
- return 1;
-
- } else if (streq(name, "SendSIGHUP")) {
- int b;
-
- r = sd_bus_message_read(message, "b", &b);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- c->send_sighup = b;
-
- unit_write_drop_in_private_format(u, mode, name, "SendSIGHUP=%s\n", yes_no(b));
- }
-
- return 1;
-
- } else if (streq(name, "SendSIGKILL")) {
- int b;
-
- r = sd_bus_message_read(message, "b", &b);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- c->send_sigkill = b;
-
- unit_write_drop_in_private_format(u, mode, name, "SendSIGKILL=%s\n", yes_no(b));
- }
-
- return 1;
-
- }
-
- return 0;
-}
diff --git a/src/core/dbus-kill.h b/src/core/dbus-kill.h
deleted file mode 100644
index 7c15f3a90..000000000
--- a/src/core/dbus-kill.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 "unit.h"
-#include "kill.h"
-
-extern const sd_bus_vtable bus_kill_vtable[];
-
-int bus_kill_context_set_transient_property(Unit *u, KillContext *c, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error);
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
deleted file mode 100644
index 1b26e5556..000000000
--- a/src/core/dbus-manager.c
+++ /dev/null
@@ -1,2157 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 <unistd.h>
-
-#include "log.h"
-#include "strv.h"
-#include "build.h"
-#include "install.h"
-#include "selinux-access.h"
-#include "watchdog.h"
-#include "clock-util.h"
-#include "path-util.h"
-#include "virt.h"
-#include "architecture.h"
-#include "env-util.h"
-#include "dbus.h"
-#include "dbus-job.h"
-#include "dbus-manager.h"
-#include "dbus-unit.h"
-#include "dbus-snapshot.h"
-#include "dbus-execute.h"
-#include "bus-common-errors.h"
-
-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 int property_get_virtualization(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- const char *id = NULL;
-
- assert(bus);
- assert(reply);
-
- detect_virtualization(&id);
-
- return sd_bus_message_append(reply, "s", id);
-}
-
-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()));
-}
-
-static int property_get_tainted(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- char buf[sizeof("split-usr:mtab-not-symlink:cgroups-missing:local-hwclock:")] = "", *e = buf;
- _cleanup_free_ char *p = NULL;
- Manager *m = userdata;
-
- assert(bus);
- assert(reply);
- assert(m);
-
- if (m->taint_usr)
- e = stpcpy(e, "split-usr:");
-
- if (readlink_malloc("/etc/mtab", &p) < 0)
- e = stpcpy(e, "mtab-not-symlink:");
-
- if (access("/proc/cgroups", F_OK) < 0)
- e = stpcpy(e, "cgroups-missing:");
-
- if (clock_is_localtime() > 0)
- e = stpcpy(e, "local-hwclock:");
-
- /* remove the last ':' */
- if (e != buf)
- e[-1] = 0;
-
- return sd_bus_message_append(reply, "s", buf);
-}
-
-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,
- const char *interface,
- const char *property,
- sd_bus_message *value,
- void *userdata,
- sd_bus_error *error) {
-
- const char *t;
- int r;
-
- assert(bus);
- assert(value);
-
- r = sd_bus_message_read(value, "s", &t);
- if (r < 0)
- return r;
-
- return log_set_target_from_string(t);
-}
-
-static int property_get_log_level(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- _cleanup_free_ char *t = NULL;
- int r;
-
- assert(bus);
- assert(reply);
-
- r = log_level_to_string_alloc(log_get_max_level(), &t);
- if (r < 0)
- return r;
-
- return sd_bus_message_append(reply, "s", t);
-}
-
-static int property_set_log_level(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *value,
- void *userdata,
- sd_bus_error *error) {
-
- const char *t;
- int r;
-
- assert(bus);
- assert(value);
-
- r = sd_bus_message_read(value, "s", &t);
- if (r < 0)
- return r;
-
- return log_set_max_level_from_string(t);
-}
-
-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) {
-
- Manager *m = userdata;
-
- assert(bus);
- assert(reply);
- assert(m);
-
- return sd_bus_message_append(reply, "u", (uint32_t) hashmap_size(m->jobs));
-}
-
-static int property_get_progress(
- 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;
- double d;
-
- assert(bus);
- assert(reply);
- assert(m);
-
- if (dual_timestamp_is_set(&m->finish_timestamp))
- d = 1.0;
- else
- d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
-
- return sd_bus_message_append(reply, "d", d);
-}
-
-static int property_get_system_state(
- 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, "s", manager_state_to_string(manager_state(m)));
-}
-
-static int property_set_runtime_watchdog(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *value,
- void *userdata,
- sd_bus_error *error) {
-
- usec_t *t = userdata;
- int r;
-
- assert(bus);
- assert(value);
-
- assert_cc(sizeof(usec_t) == sizeof(uint64_t));
-
- r = sd_bus_message_read(value, "t", t);
- if (r < 0)
- return r;
-
- return watchdog_set_timeout(t);
-}
-
-static int method_get_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_free_ char *path = NULL;
- Manager *m = userdata;
- const char *name;
- Unit *u;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- /* Anyone can call this method */
-
- r = sd_bus_message_read(message, "s", &name);
- if (r < 0)
- return r;
-
- if (isempty(name)) {
- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
- pid_t pid;
-
- r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
- if (r < 0)
- return r;
-
- r = sd_bus_creds_get_pid(creds, &pid);
- if (r < 0)
- return r;
-
- u = manager_get_unit_by_pid(m, pid);
- if (!u)
- return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Client not member of any unit.");
- } else {
- u = manager_get_unit(m, name);
- if (!u)
- return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", name);
- }
-
- 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_get_unit_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_free_ char *path = NULL;
- Manager *m = userdata;
- pid_t pid;
- Unit *u;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- assert_cc(sizeof(pid_t) == sizeof(uint32_t));
-
- /* Anyone can call this method */
-
- r = sd_bus_message_read(message, "u", &pid);
- if (r < 0)
- return r;
- if (pid < 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid PID " PID_FMT, pid);
-
- if (pid == 0) {
- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
-
- r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
- if (r < 0)
- return r;
-
- r = sd_bus_creds_get_pid(creds, &pid);
- if (r < 0)
- return r;
- }
-
- u = manager_get_unit_by_pid(m, pid);
- if (!u)
- return sd_bus_error_setf(error, BUS_ERROR_NO_UNIT_FOR_PID, "PID "PID_FMT" does not belong to any loaded unit.", pid);
-
- 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 *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_free_ char *path = NULL;
- Manager *m = userdata;
- const char *name;
- Unit *u;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- /* Anyone can call this method */
-
- r = sd_bus_message_read(message, "s", &name);
- if (r < 0)
- return r;
-
- if (isempty(name)) {
- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
- pid_t pid;
-
- r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
- if (r < 0)
- return r;
-
- r = sd_bus_creds_get_pid(creds, &pid);
- if (r < 0)
- return r;
-
- u = manager_get_unit_by_pid(m, pid);
- if (!u)
- return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Client not member of any unit.");
- } else {
- r = manager_load_unit(m, name, NULL, error, &u);
- if (r < 0)
- return r;
- }
-
- 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_start_unit_generic(sd_bus *bus, sd_bus_message *message, Manager *m, JobType job_type, bool reload_if_possible, sd_bus_error *error) {
- const char *name;
- Unit *u;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = sd_bus_message_read(message, "s", &name);
- if (r < 0)
- return r;
-
- r = manager_load_unit(m, name, NULL, error, &u);
- if (r < 0)
- return r;
-
- return bus_unit_method_start_generic(bus, message, u, job_type, reload_if_possible, error);
-}
-
-static int method_start_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_start_unit_generic(bus, message, userdata, JOB_START, false, error);
-}
-
-static int method_stop_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_start_unit_generic(bus, message, userdata, JOB_STOP, false, error);
-}
-
-static int method_reload_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_start_unit_generic(bus, message, userdata, JOB_RELOAD, false, error);
-}
-
-static int method_restart_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_start_unit_generic(bus, message, userdata, JOB_RESTART, false, error);
-}
-
-static int method_try_restart_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_start_unit_generic(bus, message, userdata, JOB_TRY_RESTART, false, error);
-}
-
-static int method_reload_or_restart_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_start_unit_generic(bus, message, userdata, JOB_RESTART, true, error);
-}
-
-static int method_reload_or_try_restart_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_start_unit_generic(bus, message, userdata, JOB_TRY_RESTART, true, error);
-}
-
-static int method_start_unit_replace(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- const char *old_name;
- Unit *u;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = sd_bus_message_read(message, "s", &old_name);
- if (r < 0)
- return r;
-
- u = manager_get_unit(m, old_name);
- if (!u || !u->job || u->job->type != JOB_START)
- return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
-
- return method_start_unit_generic(bus, message, m, JOB_START, false, error);
-}
-
-static int method_kill_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- const char *name;
- Unit *u;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = sd_bus_message_read(message, "s", &name);
- if (r < 0)
- return r;
-
- u = manager_get_unit(m, name);
- if (!u)
- return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
-
- return bus_unit_method_kill(bus, message, u, error);
-}
-
-static int method_reset_failed_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- const char *name;
- Unit *u;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = sd_bus_message_read(message, "s", &name);
- if (r < 0)
- return r;
-
- u = manager_get_unit(m, name);
- if (!u)
- return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
-
- return bus_unit_method_reset_failed(bus, message, u, error);
-}
-
-static int method_set_unit_properties(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- const char *name;
- Unit *u;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = sd_bus_message_read(message, "s", &name);
- if (r < 0)
- return r;
-
- u = manager_get_unit(m, name);
- if (!u)
- return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
-
- return bus_unit_method_set_properties(bus, message, u, error);
-}
-
-static int transient_unit_from_message(
- Manager *m,
- sd_bus_message *message,
- const char *name,
- Unit **unit,
- sd_bus_error *error) {
-
- Unit *u;
- int r;
-
- assert(m);
- assert(message);
- assert(name);
-
- r = manager_load_unit(m, name, NULL, error, &u);
- if (r < 0)
- return r;
-
- if (u->load_state != UNIT_NOT_FOUND ||
- set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0)
- return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name);
-
- /* OK, the unit failed to load and is unreferenced, now let's
- * fill in the transient data instead */
- r = unit_make_transient(u);
- if (r < 0)
- return r;
-
- /* Set our properties */
- r = bus_unit_set_properties(u, message, UNIT_RUNTIME, false, error);
- if (r < 0)
- return r;
-
- *unit = u;
-
- return 0;
-}
-
-static int transient_aux_units_from_message(
- Manager *m,
- sd_bus_message *message,
- sd_bus_error *error) {
-
- Unit *u;
- char *name = NULL;
- int r;
-
- assert(m);
- assert(message);
-
- r = sd_bus_message_enter_container(message, 'a', "(sa(sv))");
- if (r < 0)
- return r;
-
- while ((r = sd_bus_message_enter_container(message, 'r', "sa(sv)")) > 0) {
- r = sd_bus_message_read(message, "s", &name);
- if (r < 0)
- return r;
-
- r = transient_unit_from_message(m, message, name, &u, error);
- if (r < 0 && r != -EEXIST)
- return r;
-
- if (r != -EEXIST) {
- r = unit_load(u);
- if (r < 0)
- return r;
- }
-
- r = sd_bus_message_exit_container(message);
- if (r < 0)
- return r;
- }
- if (r < 0)
- return r;
-
- r = sd_bus_message_exit_container(message);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-static int method_start_transient_unit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- const char *name, *smode;
- Manager *m = userdata;
- JobMode mode;
- UnitType t;
- Unit *u;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = mac_selinux_access_check(message, "start", error);
- if (r < 0)
- return r;
-
- r = sd_bus_message_read(message, "ss", &name, &smode);
- if (r < 0)
- return r;
-
- t = unit_name_to_type(name);
- if (t < 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit type.");
-
- if (!unit_vtable[t]->can_transient)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units.", unit_type_to_string(t));
-
- mode = job_mode_from_string(smode);
- if (mode < 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s is invalid.", smode);
-
- r = bus_verify_manage_units_async(m, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
- r = transient_unit_from_message(m, message, name, &u, error);
- if (r < 0)
- return r;
-
- r = transient_aux_units_from_message(m, message, error);
- if (r < 0)
- return r;
-
- /* And load this stub fully */
- r = unit_load(u);
- if (r < 0)
- return r;
-
- manager_dispatch_load_queue(m);
-
- /* Finally, start it */
- return bus_unit_queue_job(bus, message, u, JOB_START, mode, false, error);
-}
-
-static int method_get_job(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_free_ char *path = NULL;
- Manager *m = userdata;
- uint32_t id;
- Job *j;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- /* Anyone can call this method */
-
- r = sd_bus_message_read(message, "u", &id);
- if (r < 0)
- return r;
-
- j = manager_get_job(m, id);
- if (!j)
- return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
-
- r = mac_selinux_unit_access_check(j->unit, message, "status", error);
- if (r < 0)
- return r;
-
- path = job_dbus_path(j);
- if (!path)
- return -ENOMEM;
-
- return sd_bus_reply_method_return(message, "o", path);
-}
-
-static int method_cancel_job(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- uint32_t id;
- Job *j;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = sd_bus_message_read(message, "u", &id);
- if (r < 0)
- return r;
-
- j = manager_get_job(m, id);
- if (!j)
- return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
-
- return bus_job_method_cancel(bus, message, j, error);
-}
-
-static int method_clear_jobs(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = mac_selinux_access_check(message, "reload", error);
- if (r < 0)
- return r;
-
- r = bus_verify_manage_units_async(m, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
- manager_clear_jobs(m);
-
- return sd_bus_reply_method_return(message, NULL);
-}
-
-static int method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = mac_selinux_access_check(message, "reload", error);
- if (r < 0)
- return r;
-
- r = bus_verify_manage_units_async(m, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
- manager_reset_failed(m);
-
- return sd_bus_reply_method_return(message, NULL);
-}
-
-static int list_units_filtered(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error, char **states) {
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
- Manager *m = userdata;
- const char *k;
- Iterator i;
- Unit *u;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- /* Anyone can call this method */
-
- r = mac_selinux_access_check(message, "status", error);
- if (r < 0)
- return r;
-
- r = sd_bus_message_new_method_return(message, &reply);
- if (r < 0)
- return r;
-
- r = sd_bus_message_open_container(reply, 'a', "(ssssssouso)");
- if (r < 0)
- return r;
-
- HASHMAP_FOREACH_KEY(u, k, m->units, i) {
- _cleanup_free_ char *unit_path = NULL, *job_path = NULL;
- Unit *following;
-
- if (k != u->id)
- continue;
-
- following = unit_following(u);
-
- if (!strv_isempty(states) &&
- !strv_contains(states, unit_load_state_to_string(u->load_state)) &&
- !strv_contains(states, unit_active_state_to_string(unit_active_state(u))) &&
- !strv_contains(states, unit_sub_state_to_string(u)))
- continue;
-
- unit_path = unit_dbus_path(u);
- if (!unit_path)
- return -ENOMEM;
-
- if (u->job) {
- job_path = job_dbus_path(u->job);
- if (!job_path)
- return -ENOMEM;
- }
-
- r = sd_bus_message_append(
- reply, "(ssssssouso)",
- u->id,
- unit_description(u),
- unit_load_state_to_string(u->load_state),
- unit_active_state_to_string(unit_active_state(u)),
- unit_sub_state_to_string(u),
- following ? following->id : "",
- unit_path,
- u->job ? u->job->id : 0,
- u->job ? job_type_to_string(u->job->type) : "",
- job_path ? job_path : "/");
- if (r < 0)
- return r;
- }
-
- r = sd_bus_message_close_container(reply);
- if (r < 0)
- return r;
-
- return sd_bus_send(bus, reply, NULL);
-}
-
-static int method_list_units(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return list_units_filtered(bus, message, userdata, error, NULL);
-}
-
-static int method_list_units_filtered(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_strv_free_ char **states = NULL;
- int r;
-
- r = sd_bus_message_read_strv(message, &states);
- if (r < 0)
- return r;
-
- return list_units_filtered(bus, message, userdata, error, states);
-}
-
-static int method_list_jobs(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
- Manager *m = userdata;
- Iterator i;
- Job *j;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- /* Anyone can call this method */
-
- r = mac_selinux_access_check(message, "status", error);
- if (r < 0)
- return r;
-
- r = sd_bus_message_new_method_return(message, &reply);
- if (r < 0)
- return r;
-
- r = sd_bus_message_open_container(reply, 'a', "(usssoo)");
- if (r < 0)
- return r;
-
- HASHMAP_FOREACH(j, m->jobs, i) {
- _cleanup_free_ char *unit_path = NULL, *job_path = NULL;
-
- job_path = job_dbus_path(j);
- if (!job_path)
- return -ENOMEM;
-
- unit_path = unit_dbus_path(j->unit);
- if (!unit_path)
- return -ENOMEM;
-
- r = sd_bus_message_append(
- reply, "(usssoo)",
- j->id,
- j->unit->id,
- job_type_to_string(j->type),
- job_state_to_string(j->state),
- job_path,
- unit_path);
- if (r < 0)
- return r;
- }
-
- r = sd_bus_message_close_container(reply);
- if (r < 0)
- return r;
-
- return sd_bus_send(bus, reply, NULL);
-}
-
-static int method_subscribe(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- /* Anyone can call this method */
-
- r = mac_selinux_access_check(message, "status", error);
- if (r < 0)
- return r;
-
- if (bus == m->api_bus) {
-
- /* Note that direct bus connection subscribe by
- * default, we only track peers on the API bus here */
-
- if (!m->subscribed) {
- r = sd_bus_track_new(bus, &m->subscribed, NULL, NULL);
- if (r < 0)
- return r;
- }
-
- r = sd_bus_track_add_sender(m->subscribed, message);
- if (r < 0)
- return r;
- if (r == 0)
- return sd_bus_error_setf(error, BUS_ERROR_ALREADY_SUBSCRIBED, "Client is already subscribed.");
- }
-
- return sd_bus_reply_method_return(message, NULL);
-}
-
-static int method_unsubscribe(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- /* Anyone can call this method */
-
- r = mac_selinux_access_check(message, "status", error);
- if (r < 0)
- return r;
-
- if (bus == m->api_bus) {
- r = sd_bus_track_remove_sender(m->subscribed, message);
- if (r < 0)
- return r;
- if (r == 0)
- return sd_bus_error_setf(error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
- }
-
- return sd_bus_reply_method_return(message, NULL);
-}
-
-static int method_dump(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_free_ char *dump = NULL;
- _cleanup_fclose_ FILE *f = NULL;
- Manager *m = userdata;
- size_t size;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- /* Anyone can call this method */
-
- r = mac_selinux_access_check(message, "status", error);
- if (r < 0)
- return r;
-
- f = open_memstream(&dump, &size);
- if (!f)
- return -ENOMEM;
-
- manager_dump_units(m, f, NULL);
- manager_dump_jobs(m, f, NULL);
-
- fflush(f);
-
- if (ferror(f))
- return -ENOMEM;
-
- return sd_bus_reply_method_return(message, "s", dump);
-}
-
-static int method_create_snapshot(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_free_ char *path = NULL;
- Manager *m = userdata;
- const char *name;
- int cleanup;
- Snapshot *s = NULL;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = mac_selinux_access_check(message, "start", error);
- if (r < 0)
- return r;
-
- r = sd_bus_message_read(message, "sb", &name, &cleanup);
- if (r < 0)
- return r;
-
- if (isempty(name))
- name = NULL;
-
- r = bus_verify_manage_units_async(m, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
- r = snapshot_create(m, name, cleanup, error, &s);
- if (r < 0)
- return r;
-
- path = unit_dbus_path(UNIT(s));
- if (!path)
- return -ENOMEM;
-
- return sd_bus_reply_method_return(message, "o", path);
-}
-
-static int method_remove_snapshot(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- const char *name;
- Unit *u;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = sd_bus_message_read(message, "s", &name);
- if (r < 0)
- return r;
-
- u = manager_get_unit(m, name);
- if (!u)
- return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name);
-
- if (u->type != UNIT_SNAPSHOT)
- return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot", name);
-
- return bus_snapshot_method_remove(bus, message, u, error);
-}
-
-static int method_reload(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = mac_selinux_access_check(message, "reload", error);
- if (r < 0)
- return r;
-
- r = bus_verify_reload_daemon_async(m, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
- /* Instead of sending the reply back right away, we just
- * remember that we need to and then send it after the reload
- * is finished. That way the caller knows when the reload
- * finished. */
-
- assert(!m->queued_message);
- r = sd_bus_message_new_method_return(message, &m->queued_message);
- if (r < 0)
- return r;
-
- m->queued_message_bus = sd_bus_ref(bus);
- m->exit_code = MANAGER_RELOAD;
-
- return 1;
-}
-
-static int method_reexecute(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = mac_selinux_access_check(message, "reload", error);
- if (r < 0)
- return r;
-
- r = bus_verify_reload_daemon_async(m, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
- /* We don't send a reply back here, the client should
- * just wait for us disconnecting. */
-
- m->exit_code = MANAGER_REEXECUTE;
- return 1;
-}
-
-static int method_exit(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = mac_selinux_access_check(message, "halt", error);
- if (r < 0)
- return r;
-
- if (m->running_as == SYSTEMD_SYSTEM)
- return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
-
- m->exit_code = MANAGER_EXIT;
-
- return sd_bus_reply_method_return(message, NULL);
-}
-
-static int method_reboot(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = mac_selinux_access_check(message, "reboot", error);
- if (r < 0)
- return r;
-
- if (m->running_as != SYSTEMD_SYSTEM)
- return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
-
- m->exit_code = MANAGER_REBOOT;
-
- return sd_bus_reply_method_return(message, NULL);
-}
-
-static int method_poweroff(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = mac_selinux_access_check(message, "halt", error);
- if (r < 0)
- return r;
-
- if (m->running_as != SYSTEMD_SYSTEM)
- return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
-
- m->exit_code = MANAGER_POWEROFF;
-
- return sd_bus_reply_method_return(message, NULL);
-}
-
-static int method_halt(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = mac_selinux_access_check(message, "halt", error);
- if (r < 0)
- return r;
-
- if (m->running_as != SYSTEMD_SYSTEM)
- return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Halt is only supported for system managers.");
-
- m->exit_code = MANAGER_HALT;
-
- return sd_bus_reply_method_return(message, NULL);
-}
-
-static int method_kexec(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = mac_selinux_access_check(message, "reboot", error);
- if (r < 0)
- return r;
-
- if (m->running_as != SYSTEMD_SYSTEM)
- return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "KExec is only supported for system managers.");
-
- m->exit_code = MANAGER_KEXEC;
-
- return sd_bus_reply_method_return(message, NULL);
-}
-
-static int method_switch_root(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- char *ri = NULL, *rt = NULL;
- const char *root, *init;
- Manager *m = userdata;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = mac_selinux_access_check(message, "reboot", error);
- if (r < 0)
- return r;
-
- if (m->running_as != SYSTEMD_SYSTEM)
- return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Root switching is only supported by system manager.");
-
- r = sd_bus_message_read(message, "ss", &root, &init);
- if (r < 0)
- return r;
-
- if (path_equal(root, "/") || !path_is_absolute(root))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid switch root path %s", root);
-
- /* Safety check */
- if (isempty(init)) {
- if (!path_is_os_tree(root))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified switch root path %s does not seem to be an OS tree. os-release file is missing.", root);
- } else {
- _cleanup_free_ char *p = NULL;
-
- if (!path_is_absolute(init))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid init path %s", init);
-
- p = strappend(root, init);
- if (!p)
- return -ENOMEM;
-
- if (access(p, X_OK) < 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Specified init binary %s does not exist.", p);
- }
-
- rt = strdup(root);
- if (!rt)
- return -ENOMEM;
-
- if (!isempty(init)) {
- ri = strdup(init);
- if (!ri) {
- free(rt);
- return -ENOMEM;
- }
- }
-
- free(m->switch_root);
- m->switch_root = rt;
-
- free(m->switch_root_init);
- m->switch_root_init = ri;
-
- m->exit_code = MANAGER_SWITCH_ROOT;
-
- return sd_bus_reply_method_return(message, NULL);
-}
-
-static int method_set_environment(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_strv_free_ char **plus = NULL;
- Manager *m = userdata;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = mac_selinux_access_check(message, "reload", error);
- if (r < 0)
- return r;
-
- r = sd_bus_message_read_strv(message, &plus);
- if (r < 0)
- return r;
- if (!strv_env_is_valid(plus))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments");
-
- r = bus_verify_set_environment_async(m, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
- r = manager_environment_add(m, NULL, plus);
- if (r < 0)
- return r;
-
- return sd_bus_reply_method_return(message, NULL);
-}
-
-static int method_unset_environment(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_strv_free_ char **minus = NULL;
- Manager *m = userdata;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = mac_selinux_access_check(message, "reload", error);
- if (r < 0)
- return r;
-
- r = sd_bus_message_read_strv(message, &minus);
- if (r < 0)
- return r;
-
- if (!strv_env_name_or_assignment_is_valid(minus))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment variable names or assignments");
-
- r = bus_verify_set_environment_async(m, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
- r = manager_environment_add(m, minus, NULL);
- if (r < 0)
- return r;
-
- return sd_bus_reply_method_return(message, NULL);
-}
-
-static int method_unset_and_set_environment(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_strv_free_ char **minus = NULL, **plus = NULL;
- Manager *m = userdata;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = mac_selinux_access_check(message, "reload", error);
- if (r < 0)
- return r;
-
- r = sd_bus_message_read_strv(message, &minus);
- if (r < 0)
- return r;
-
- r = sd_bus_message_read_strv(message, &plus);
- if (r < 0)
- return r;
-
- if (!strv_env_name_or_assignment_is_valid(minus))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment variable names or assignments");
- if (!strv_env_is_valid(plus))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments");
-
- r = bus_verify_set_environment_async(m, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
- r = manager_environment_add(m, minus, plus);
- if (r < 0)
- return r;
-
- return sd_bus_reply_method_return(message, NULL);
-}
-
-static int method_list_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
- Manager *m = userdata;
- UnitFileList *item;
- Hashmap *h;
- Iterator i;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- /* Anyone can call this method */
-
- r = mac_selinux_access_check(message, "status", error);
- if (r < 0)
- return r;
-
- r = sd_bus_message_new_method_return(message, &reply);
- if (r < 0)
- return r;
-
- h = hashmap_new(&string_hash_ops);
- if (!h)
- return -ENOMEM;
-
- r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
- if (r < 0)
- goto fail;
-
- r = sd_bus_message_open_container(reply, 'a', "(ss)");
- if (r < 0)
- goto fail;
-
- HASHMAP_FOREACH(item, h, i) {
-
- r = sd_bus_message_append(reply, "(ss)", item->path, unit_file_state_to_string(item->state));
- if (r < 0)
- goto fail;
- }
-
- unit_file_list_free(h);
-
- r = sd_bus_message_close_container(reply);
- if (r < 0)
- return r;
-
- return sd_bus_send(bus, reply, NULL);
-
-fail:
- unit_file_list_free(h);
- return r;
-}
-
-static int method_get_unit_file_state(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- const char *name;
- UnitFileState state;
- UnitFileScope scope;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- /* Anyone can call this method */
-
- r = mac_selinux_access_check(message, "status", error);
- if (r < 0)
- return r;
-
- r = sd_bus_message_read(message, "s", &name);
- if (r < 0)
- return r;
-
- scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
- state = unit_file_get_state(scope, NULL, name);
- if (state < 0)
- return state;
-
- return sd_bus_reply_method_return(message, "s", unit_file_state_to_string(state));
-}
-
-static int method_get_default_target(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_free_ char *default_target = NULL;
- Manager *m = userdata;
- UnitFileScope scope;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- /* Anyone can call this method */
-
- r = mac_selinux_access_check(message, "status", error);
- if (r < 0)
- return r;
-
- scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
- r = unit_file_get_default(scope, NULL, &default_target);
- if (r < 0)
- return r;
-
- return sd_bus_reply_method_return(message, "s", default_target);
-}
-
-static int send_unit_files_changed(sd_bus *bus, void *userdata) {
- _cleanup_bus_message_unref_ sd_bus_message *message = NULL;
- int r;
-
- assert(bus);
-
- r = sd_bus_message_new_signal(bus, &message, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
- if (r < 0)
- return r;
-
- return sd_bus_send(bus, message, NULL);
-}
-
-static int reply_unit_file_changes_and_free(
- Manager *m,
- sd_bus *bus,
- sd_bus_message *message,
- int carries_install_info,
- UnitFileChange *changes,
- unsigned n_changes) {
-
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
- unsigned i;
- int r;
-
- if (n_changes > 0) {
- r = bus_foreach_bus(m, NULL, send_unit_files_changed, NULL);
- if (r < 0)
- log_debug_errno(r, "Failed to send UnitFilesChanged signal: %m");
- }
-
- r = sd_bus_message_new_method_return(message, &reply);
- if (r < 0)
- goto fail;
-
- if (carries_install_info >= 0) {
- r = sd_bus_message_append(reply, "b", carries_install_info);
- if (r < 0)
- goto fail;
- }
-
- r = sd_bus_message_open_container(reply, 'a', "(sss)");
- if (r < 0)
- goto fail;
-
- for (i = 0; i < n_changes; i++) {
- r = sd_bus_message_append(
- reply, "(sss)",
- unit_file_change_type_to_string(changes[i].type),
- changes[i].path,
- changes[i].source);
- if (r < 0)
- goto fail;
- }
-
- r = sd_bus_message_close_container(reply);
- if (r < 0)
- goto fail;
-
- return sd_bus_send(bus, reply, NULL);
-
-fail:
- unit_file_changes_free(changes, n_changes);
- return r;
-}
-
-static int method_enable_unit_files_generic(
- sd_bus *bus,
- sd_bus_message *message,
- Manager *m,
- const char *verb,
- int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], bool force, UnitFileChange **changes, unsigned *n_changes),
- bool carries_install_info,
- sd_bus_error *error) {
-
- _cleanup_strv_free_ char **l = NULL;
- UnitFileChange *changes = NULL;
- unsigned n_changes = 0;
- UnitFileScope scope;
- int runtime, force, r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = sd_bus_message_read_strv(message, &l);
- if (r < 0)
- return r;
-
- r = sd_bus_message_read(message, "bb", &runtime, &force);
- if (r < 0)
- return r;
-
- r = mac_selinux_unit_access_check_strv(l, message, m, verb, error);
- if (r < 0)
- return r;
-
- r = bus_verify_manage_unit_files_async(m, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
- scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
- r = call(scope, runtime, NULL, l, force, &changes, &n_changes);
- if (r < 0)
- return r;
-
- return reply_unit_file_changes_and_free(m, bus, message, carries_install_info ? r : -1, changes, n_changes);
-}
-
-static int method_enable_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_enable, true, error);
-}
-
-static int method_reenable_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_reenable, true, error);
-}
-
-static int method_link_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_link, false, error);
-}
-
-static int unit_file_preset_without_mode(UnitFileScope scope, bool runtime, const char *root_dir, char **files, bool force, UnitFileChange **changes, unsigned *n_changes) {
- return unit_file_preset(scope, runtime, root_dir, files, UNIT_FILE_PRESET_FULL, force, changes, n_changes);
-}
-
-static int method_preset_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_enable_unit_files_generic(bus, message, userdata, "enable", unit_file_preset_without_mode, true, error);
-}
-
-static int method_mask_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_enable_unit_files_generic(bus, message, userdata, "disable", unit_file_mask, false, error);
-}
-
-static int method_preset_unit_files_with_mode(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
-
- _cleanup_strv_free_ char **l = NULL;
- UnitFileChange *changes = NULL;
- unsigned n_changes = 0;
- Manager *m = userdata;
- UnitFilePresetMode mm;
- UnitFileScope scope;
- int runtime, force, r;
- const char *mode;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = sd_bus_message_read_strv(message, &l);
- if (r < 0)
- return r;
-
- r = sd_bus_message_read(message, "sbb", &mode, &runtime, &force);
- if (r < 0)
- return r;
-
- if (isempty(mode))
- mm = UNIT_FILE_PRESET_FULL;
- else {
- mm = unit_file_preset_mode_from_string(mode);
- if (mm < 0)
- return -EINVAL;
- }
-
- r = mac_selinux_unit_access_check_strv(l, message, m, "enable", error);
- if (r < 0)
- return r;
-
- r = bus_verify_manage_unit_files_async(m, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
- scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
- r = unit_file_preset(scope, runtime, NULL, l, mm, force, &changes, &n_changes);
- if (r < 0)
- return r;
-
- return reply_unit_file_changes_and_free(m, bus, message, r, changes, n_changes);
-}
-
-static int method_disable_unit_files_generic(
- sd_bus *bus,
- sd_bus_message *message,
- Manager *m, const
- char *verb,
- int (*call)(UnitFileScope scope, bool runtime, const char *root_dir, char *files[], UnitFileChange **changes, unsigned *n_changes),
- sd_bus_error *error) {
-
- _cleanup_strv_free_ char **l = NULL;
- UnitFileChange *changes = NULL;
- unsigned n_changes = 0;
- UnitFileScope scope;
- int r, runtime;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = sd_bus_message_read_strv(message, &l);
- if (r < 0)
- return r;
-
- r = sd_bus_message_read(message, "b", &runtime);
- if (r < 0)
- return r;
-
- r = mac_selinux_unit_access_check_strv(l, message, m, verb, error);
- if (r < 0)
- return r;
-
- scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
- r = bus_verify_manage_unit_files_async(m, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
- r = call(scope, runtime, NULL, l, &changes, &n_changes);
- if (r < 0)
- return r;
-
- return reply_unit_file_changes_and_free(m, bus, message, -1, changes, n_changes);
-}
-
-static int method_disable_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_disable_unit_files_generic(bus, message, userdata, "disable", unit_file_disable, error);
-}
-
-static int method_unmask_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_disable_unit_files_generic(bus, message, userdata, "enable", unit_file_unmask, error);
-}
-
-static int method_set_default_target(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- UnitFileChange *changes = NULL;
- unsigned n_changes = 0;
- Manager *m = userdata;
- UnitFileScope scope;
- const char *name;
- int force, r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = mac_selinux_access_check(message, "enable", error);
- if (r < 0)
- return r;
-
- r = sd_bus_message_read(message, "sb", &name, &force);
- if (r < 0)
- return r;
-
- r = bus_verify_manage_unit_files_async(m, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
- scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
- r = unit_file_set_default(scope, NULL, name, force, &changes, &n_changes);
- if (r < 0)
- return r;
-
- return reply_unit_file_changes_and_free(m, bus, message, -1, changes, n_changes);
-}
-
-static int method_preset_all_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- UnitFileChange *changes = NULL;
- unsigned n_changes = 0;
- Manager *m = userdata;
- UnitFilePresetMode mm;
- UnitFileScope scope;
- const char *mode;
- int force, runtime, r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = mac_selinux_access_check(message, "enable", error);
- if (r < 0)
- return r;
-
- r = sd_bus_message_read(message, "sbb", &mode, &runtime, &force);
- if (r < 0)
- return r;
-
- if (isempty(mode))
- mm = UNIT_FILE_PRESET_FULL;
- else {
- mm = unit_file_preset_mode_from_string(mode);
- if (mm < 0)
- return -EINVAL;
- }
-
- r = bus_verify_manage_unit_files_async(m, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
- scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
- r = unit_file_preset_all(scope, runtime, NULL, mm, force, &changes, &n_changes);
- if (r < 0)
- return r;
-
- return reply_unit_file_changes_and_free(m, bus, message, -1, changes, n_changes);
-}
-
-static int method_add_dependency_unit_files(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_strv_free_ char **l = NULL;
- Manager *m = userdata;
- UnitFileChange *changes = NULL;
- unsigned n_changes = 0;
- UnitFileScope scope;
- int runtime, force, r;
- char *target;
- char *type;
- UnitDependency dep;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = bus_verify_manage_unit_files_async(m, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
- r = sd_bus_message_read_strv(message, &l);
- if (r < 0)
- return r;
-
- r = sd_bus_message_read(message, "ssbb", &target, &type, &runtime, &force);
- if (r < 0)
- return r;
-
- dep = unit_dependency_from_string(type);
- if (dep < 0)
- return -EINVAL;
-
- r = mac_selinux_unit_access_check_strv(l, message, m, "enable", error);
- if (r < 0)
- return r;
-
- scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
- r = unit_file_add_dependency(scope, runtime, NULL, l, target, dep, force, &changes, &n_changes);
- if (r < 0)
- return r;
-
- return reply_unit_file_changes_and_free(m, bus, message, -1, changes, n_changes);
-}
-
-const sd_bus_vtable bus_manager_vtable[] = {
- SD_BUS_VTABLE_START(0),
-
- SD_BUS_PROPERTY("Version", "s", property_get_version, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Features", "s", property_get_features, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Virtualization", "s", property_get_virtualization, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Architecture", "s", property_get_architecture, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Tainted", "s", property_get_tainted, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- BUS_PROPERTY_DUAL_TIMESTAMP("FirmwareTimestamp", offsetof(Manager, firmware_timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
- BUS_PROPERTY_DUAL_TIMESTAMP("LoaderTimestamp", offsetof(Manager, loader_timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
- BUS_PROPERTY_DUAL_TIMESTAMP("KernelTimestamp", offsetof(Manager, kernel_timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
- BUS_PROPERTY_DUAL_TIMESTAMP("InitRDTimestamp", offsetof(Manager, initrd_timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
- BUS_PROPERTY_DUAL_TIMESTAMP("UserspaceTimestamp", offsetof(Manager, userspace_timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
- BUS_PROPERTY_DUAL_TIMESTAMP("FinishTimestamp", offsetof(Manager, finish_timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
- BUS_PROPERTY_DUAL_TIMESTAMP("SecurityStartTimestamp", offsetof(Manager, security_start_timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
- BUS_PROPERTY_DUAL_TIMESTAMP("SecurityFinishTimestamp", offsetof(Manager, security_finish_timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
- BUS_PROPERTY_DUAL_TIMESTAMP("GeneratorsStartTimestamp", offsetof(Manager, generators_start_timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
- BUS_PROPERTY_DUAL_TIMESTAMP("GeneratorsFinishTimestamp", offsetof(Manager, generators_finish_timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
- BUS_PROPERTY_DUAL_TIMESTAMP("UnitsLoadStartTimestamp", offsetof(Manager, units_load_start_timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
- BUS_PROPERTY_DUAL_TIMESTAMP("UnitsLoadFinishTimestamp", offsetof(Manager, units_load_finish_timestamp), 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("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("UnitPath", "as", NULL, offsetof(Manager, lookup_paths.unit_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),
- SD_BUS_WRITABLE_PROPERTY("RuntimeWatchdogUSec", "t", bus_property_get_usec, property_set_runtime_watchdog, offsetof(Manager, runtime_watchdog), 0),
- SD_BUS_WRITABLE_PROPERTY("ShutdownWatchdogUSec", "t", bus_property_get_usec, bus_property_set_usec, offsetof(Manager, shutdown_watchdog), 0),
- SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Manager, cgroup_root), 0),
- SD_BUS_PROPERTY("SystemState", "s", property_get_system_state, 0, 0),
-
- 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("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),
- SD_BUS_METHOD("StopUnit", "ss", "o", method_stop_unit, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("ReloadUnit", "ss", "o", method_reload_unit, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("RestartUnit", "ss", "o", method_restart_unit, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("TryRestartUnit", "ss", "o", method_try_restart_unit, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("ReloadOrRestartUnit", "ss", "o", method_reload_or_restart_unit, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("ReloadOrTryRestartUnit", "ss", "o", method_reload_or_try_restart_unit, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("KillUnit", "ssi", NULL, method_kill_unit, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("ResetFailedUnit", "s", NULL, method_reset_failed_unit, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("SetUnitProperties", "sba(sv)", NULL, method_set_unit_properties, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("StartTransientUnit", "ssa(sv)a(sa(sv))", "o", method_start_transient_unit, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("GetJob", "u", "o", method_get_job, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("CancelJob", "u", NULL, method_cancel_job, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("ClearJobs", NULL, NULL, method_clear_jobs, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("ResetFailed", NULL, NULL, method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("ListUnits", NULL, "a(ssssssouso)", method_list_units, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("ListUnitsFiltered", "as", "a(ssssssouso)", method_list_units_filtered, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("ListJobs", NULL, "a(usssoo)", method_list_jobs, SD_BUS_VTABLE_UNPRIVILEGED),
- 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_create_snapshot, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("RemoveSnapshot", "s", NULL, method_remove_snapshot, SD_BUS_VTABLE_UNPRIVILEGED),
- 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),
- SD_BUS_METHOD("Reboot", NULL, NULL, method_reboot, SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)),
- SD_BUS_METHOD("PowerOff", NULL, NULL, method_poweroff, SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)),
- SD_BUS_METHOD("Halt", NULL, NULL, method_halt, SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)),
- SD_BUS_METHOD("KExec", NULL, NULL, method_kexec, SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)),
- SD_BUS_METHOD("SwitchRoot", "ss", NULL, method_switch_root, SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)),
- SD_BUS_METHOD("SetEnvironment", "as", NULL, method_set_environment, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("UnsetEnvironment", "as", NULL, method_unset_environment, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("UnsetAndSetEnvironment", "asas", NULL, method_unset_and_set_environment, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("ListUnitFiles", NULL, "a(ss)", method_list_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("GetUnitFileState", "s", "s", method_get_unit_file_state, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("EnableUnitFiles", "asbb", "ba(sss)", method_enable_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("DisableUnitFiles", "asb", "a(sss)", method_disable_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("ReenableUnitFiles", "asbb", "ba(sss)", method_reenable_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("LinkUnitFiles", "asbb", "a(sss)", method_link_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("PresetUnitFiles", "asbb", "ba(sss)", method_preset_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("PresetUnitFilesWithMode", "assbb", "ba(sss)", method_preset_unit_files_with_mode, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("MaskUnitFiles", "asbb", "a(sss)", method_mask_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("UnmaskUnitFiles", "asb", "a(sss)", method_unmask_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("SetDefaultTarget", "sb", "a(sss)", method_set_default_target, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("GetDefaultTarget", NULL, "s", method_get_default_target, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("PresetAllUnitFiles", "sbb", "a(sss)", method_preset_all_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("AddDependencyUnitFiles", "asssbb", "a(sss)", method_add_dependency_unit_files, SD_BUS_VTABLE_UNPRIVILEGED),
-
- SD_BUS_SIGNAL("UnitNew", "so", 0),
- SD_BUS_SIGNAL("UnitRemoved", "so", 0),
- SD_BUS_SIGNAL("JobNew", "uos", 0),
- SD_BUS_SIGNAL("JobRemoved", "uoss", 0),
- SD_BUS_SIGNAL("StartupFinished", "tttttt", 0),
- SD_BUS_SIGNAL("UnitFilesChanged", NULL, 0),
- SD_BUS_SIGNAL("Reloading", "b", 0),
-
- SD_BUS_VTABLE_END
-};
-
-static int send_finished(sd_bus *bus, void *userdata) {
- _cleanup_bus_message_unref_ sd_bus_message *message = NULL;
- usec_t *times = userdata;
- int r;
-
- assert(bus);
- assert(times);
-
- r = sd_bus_message_new_signal(bus, &message, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartupFinished");
- if (r < 0)
- return r;
-
- r = sd_bus_message_append(message, "tttttt", times[0], times[1], times[2], times[3], times[4], times[5]);
- if (r < 0)
- return r;
-
- return sd_bus_send(bus, message, NULL);
-}
-
-void bus_manager_send_finished(
- Manager *m,
- usec_t firmware_usec,
- usec_t loader_usec,
- usec_t kernel_usec,
- usec_t initrd_usec,
- usec_t userspace_usec,
- usec_t total_usec) {
-
- int r;
-
- assert(m);
-
- r = bus_foreach_bus(
- m,
- NULL,
- send_finished,
- (usec_t[6]) {
- firmware_usec,
- loader_usec,
- kernel_usec,
- initrd_usec,
- userspace_usec,
- total_usec
- });
- if (r < 0)
- log_debug_errno(r, "Failed to send finished signal: %m");
-}
-
-static int send_reloading(sd_bus *bus, void *userdata) {
- _cleanup_bus_message_unref_ sd_bus_message *message = NULL;
- int r;
-
- assert(bus);
-
- r = sd_bus_message_new_signal(bus, &message, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "Reloading");
- if (r < 0)
- return r;
-
- r = sd_bus_message_append(message, "b", PTR_TO_INT(userdata));
- if (r < 0)
- return r;
-
- return sd_bus_send(bus, message, NULL);
-}
-
-void bus_manager_send_reloading(Manager *m, bool active) {
- int r;
-
- assert(m);
-
- r = bus_foreach_bus(m, NULL, send_reloading, INT_TO_PTR(active));
- if (r < 0)
- log_debug_errno(r, "Failed to send reloading signal: %m");
-}
-
-static int send_changed_signal(sd_bus *bus, void *userdata) {
- assert(bus);
-
- return sd_bus_emit_properties_changed_strv(bus,
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- NULL);
-}
-
-void bus_manager_send_change_signal(Manager *m) {
- int r;
-
- assert(m);
-
- r = bus_foreach_bus(m, NULL, send_changed_signal, NULL);
- if (r < 0)
- log_debug_errno(r, "Failed to send manager change signal: %m");
-}
diff --git a/src/core/dbus-manager.h b/src/core/dbus-manager.h
deleted file mode 100644
index 5bdf6e17a..000000000
--- a/src/core/dbus-manager.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 "manager.h"
-
-extern const sd_bus_vtable bus_manager_vtable[];
-
-void bus_manager_send_finished(Manager *m, usec_t firmware_usec, usec_t loader_usec, usec_t kernel_usec, usec_t initrd_usec, usec_t userspace_usec, usec_t total_usec);
-void bus_manager_send_reloading(Manager *m, bool active);
-void bus_manager_send_change_signal(Manager *m);
diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c
deleted file mode 100644
index 24813c6d2..000000000
--- a/src/core/dbus-mount.c
+++ /dev/null
@@ -1,212 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 "mount.h"
-#include "dbus-execute.h"
-#include "dbus-kill.h"
-#include "dbus-cgroup.h"
-#include "dbus-mount.h"
-#include "bus-util.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;
-
- assert(bus);
- assert(reply);
- assert(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;
- else
- d = "";
-
- return sd_bus_message_append(reply, "s", d);
-}
-
-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;
-
- assert(bus);
- assert(reply);
- assert(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;
- else
- d = "";
-
- return sd_bus_message_append(reply, "s", d);
-}
-
-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) {
-
- Mount *m = userdata;
- const char *d;
-
- assert(bus);
- assert(reply);
- assert(m);
-
- if (m->from_proc_self_mountinfo && m->parameters_proc_self_mountinfo.fstype)
- d = m->parameters_proc_self_mountinfo.fstype;
- else if (m->from_fragment && m->parameters_fragment.fstype)
- d = m->parameters_fragment.fstype;
- else
- d = "";
-
- return sd_bus_message_append(reply, "s", d);
-}
-
-static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, mount_result, MountResult);
-
-const sd_bus_vtable bus_mount_vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_PROPERTY("Where", "s", NULL, offsetof(Mount, where), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("What", "s", property_get_what, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("Options","s", property_get_options, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("Type", "s", property_get_type, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("TimeoutUSec", "t", bus_property_get_usec, offsetof(Mount, timeout_usec), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Mount, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Mount, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("SloppyOptions", "b", bus_property_get_bool, offsetof(Mount, sloppy_options), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Mount, result), 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),
- SD_BUS_VTABLE_END
-};
-
-static int bus_mount_set_transient_property(
- Mount *m,
- const char *name,
- sd_bus_message *message,
- UnitSetPropertiesMode mode,
- sd_bus_error *error) {
-
- const char *new_property;
- char **property;
- char *p;
- int r;
-
- assert(m);
- assert(name);
- assert(message);
-
- if (streq(name, "What"))
- property = &m->parameters_fragment.what;
- else if (streq(name, "Options"))
- property = &m->parameters_fragment.options;
- else if (streq(name, "Type"))
- property = &m->parameters_fragment.fstype;
- else
- return 0;
-
- r = sd_bus_message_read(message, "s", &new_property);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- p = strdup(new_property);
- if (!p)
- return -ENOMEM;
-
- free(*property);
- *property = p;
- }
-
- return 1;
-}
-
-int bus_mount_set_property(
- Unit *u,
- const char *name,
- sd_bus_message *message,
- UnitSetPropertiesMode mode,
- sd_bus_error *error) {
-
- Mount *m = MOUNT(u);
- int r;
-
- assert(m);
- assert(name);
- assert(message);
-
- r = bus_cgroup_set_property(u, &m->cgroup_context, name, message, mode, error);
- if (r != 0)
- return r;
-
- if (u->transient && u->load_state == UNIT_STUB) {
- /* This is a transient unit, let's load a little more */
-
- r = bus_mount_set_transient_property(m, name, message, mode, error);
- if (r != 0)
- return r;
-
- r = bus_exec_context_set_transient_property(u, &m->exec_context, name, message, mode, error);
- if (r != 0)
- return r;
-
- r = bus_kill_context_set_transient_property(u, &m->kill_context, name, message, mode, error);
- if (r != 0)
- return r;
- }
-
- return 0;
-}
-
-int bus_mount_commit_properties(Unit *u) {
- assert(u);
-
- unit_update_cgroup_members_masks(u);
- unit_realize_cgroup(u);
-
- return 0;
-}
diff --git a/src/core/dbus-mount.h b/src/core/dbus-mount.h
deleted file mode 100644
index f7004d252..000000000
--- a/src/core/dbus-mount.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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"
-
-extern const sd_bus_vtable bus_mount_vtable[];
-
-int bus_mount_set_property(Unit *u, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error);
-int bus_mount_commit_properties(Unit *u);
diff --git a/src/core/dbus-path.c b/src/core/dbus-path.c
deleted file mode 100644
index 683561999..000000000
--- a/src/core/dbus-path.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 "path.h"
-#include "dbus-path.h"
-#include "bus-util.h"
-
-static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, path_result, PathResult);
-
-static int property_get_paths(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Path *p = userdata;
- PathSpec *k;
- int r;
-
- assert(bus);
- assert(reply);
- assert(p);
-
- r = sd_bus_message_open_container(reply, 'a', "(ss)");
- if (r < 0)
- return r;
-
- LIST_FOREACH(spec, k, p->specs) {
- r = sd_bus_message_append(reply, "(ss)", path_type_to_string(k->type), k->path);
- if (r < 0)
- return r;
- }
-
- 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("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),
- SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Path, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_VTABLE_END
-};
diff --git a/src/core/dbus-path.h b/src/core/dbus-path.h
deleted file mode 100644
index 389b0d7f9..000000000
--- a/src/core/dbus-path.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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/>.
-***/
-
-
-
-extern const sd_bus_vtable bus_path_vtable[];
diff --git a/src/core/dbus-scope.c b/src/core/dbus-scope.c
deleted file mode 100644
index 651c163be..000000000
--- a/src/core/dbus-scope.c
+++ /dev/null
@@ -1,231 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 "selinux-access.h"
-#include "unit.h"
-#include "scope.h"
-#include "dbus.h"
-#include "bus-util.h"
-#include "bus-internal.h"
-#include "bus-common-errors.h"
-#include "dbus-unit.h"
-#include "dbus-cgroup.h"
-#include "dbus-kill.h"
-#include "dbus-scope.h"
-
-static int bus_scope_abandon(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Scope *s = userdata;
- int r;
-
- assert(bus);
- assert(message);
- assert(s);
-
- r = mac_selinux_unit_access_check(UNIT(s), message, "stop", error);
- if (r < 0)
- return r;
-
- r = bus_verify_manage_units_async(UNIT(s)->manager, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
- r = scope_abandon(s);
- if (r == -ESTALE)
- return sd_bus_error_setf(error, BUS_ERROR_SCOPE_NOT_RUNNING, "Scope %s is not running, cannot abandon.", UNIT(s)->id);
- if (r < 0)
- return r;
-
- return sd_bus_reply_method_return(message, NULL);
-}
-
-static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, scope_result, ScopeResult);
-
-const sd_bus_vtable bus_scope_vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_PROPERTY("Controller", "s", NULL, offsetof(Scope, controller), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec, offsetof(Scope, timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Scope, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_SIGNAL("RequestStop", NULL, 0),
- SD_BUS_METHOD("Abandon", NULL, NULL, bus_scope_abandon, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_VTABLE_END
-};
-
-static int bus_scope_set_transient_property(
- Scope *s,
- const char *name,
- sd_bus_message *message,
- UnitSetPropertiesMode mode,
- sd_bus_error *error) {
-
- int r;
-
- assert(s);
- assert(name);
- assert(message);
-
- if (streq(name, "PIDs")) {
- unsigned n = 0;
- uint32_t pid;
-
- r = sd_bus_message_enter_container(message, 'a', "u");
- if (r < 0)
- return r;
-
- while ((r = sd_bus_message_read(message, "u", &pid)) > 0) {
-
- if (pid <= 1)
- return -EINVAL;
-
- if (mode != UNIT_CHECK) {
- r = unit_watch_pid(UNIT(s), pid);
- if (r < 0 && r != -EEXIST)
- return r;
- }
-
- n++;
- }
- if (r < 0)
- return r;
-
- r = sd_bus_message_exit_container(message);
- if (r < 0)
- return r;
-
- if (n <= 0)
- return -EINVAL;
-
- return 1;
-
- } else if (streq(name, "Controller")) {
- const char *controller;
- char *c;
-
- r = sd_bus_message_read(message, "s", &controller);
- if (r < 0)
- return r;
-
- if (!isempty(controller) && !service_name_is_valid(controller))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Controller '%s' is not a valid bus name.", controller);
-
- if (mode != UNIT_CHECK) {
- if (isempty(controller))
- c = NULL;
- else {
- c = strdup(controller);
- if (!c)
- return -ENOMEM;
- }
-
- free(s->controller);
- s->controller = c;
- }
-
- return 1;
-
- } else if (streq(name, "TimeoutStopUSec")) {
-
- if (mode != UNIT_CHECK) {
- r = sd_bus_message_read(message, "t", &s->timeout_stop_usec);
- if (r < 0)
- return r;
-
- unit_write_drop_in_format(UNIT(s), mode, name, "[Scope]\nTimeoutStopSec="USEC_FMT"us\n", s->timeout_stop_usec);
- } else {
- r = sd_bus_message_skip(message, "t");
- if (r < 0)
- return r;
- }
-
- return 1;
- }
-
- return 0;
-}
-
-int bus_scope_set_property(
- Unit *u,
- const char *name,
- sd_bus_message *message,
- UnitSetPropertiesMode mode,
- sd_bus_error *error) {
-
- Scope *s = SCOPE(u);
- int r;
-
- assert(s);
- assert(name);
- assert(message);
-
- r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error);
- if (r != 0)
- return r;
-
- if (u->load_state == UNIT_STUB) {
- /* While we are created we still accept PIDs */
-
- r = bus_scope_set_transient_property(s, name, message, mode, error);
- if (r != 0)
- return r;
-
- r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, mode, error);
- if (r != 0)
- return r;
- }
-
- return 0;
-}
-
-int bus_scope_commit_properties(Unit *u) {
- assert(u);
-
- unit_update_cgroup_members_masks(u);
- unit_realize_cgroup(u);
-
- return 0;
-}
-
-int bus_scope_send_request_stop(Scope *s) {
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
- _cleanup_free_ char *p = NULL;
- int r;
-
- assert(s);
-
- if (!s->controller)
- return 0;
-
- p = unit_dbus_path(UNIT(s));
- if (!p)
- return -ENOMEM;
-
- r = sd_bus_message_new_signal(
- UNIT(s)->manager->api_bus,
- &m,
- p,
- "org.freedesktop.systemd1.Scope",
- "RequestStop");
- if (r < 0)
- return r;
-
- return sd_bus_send_to(UNIT(s)->manager->api_bus, m, /* s->controller */ NULL, NULL);
-}
diff --git a/src/core/dbus-scope.h b/src/core/dbus-scope.h
deleted file mode 100644
index 33beda47b..000000000
--- a/src/core/dbus-scope.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 "unit.h"
-
-extern const sd_bus_vtable bus_scope_vtable[];
-
-int bus_scope_set_property(Unit *u, const char *name, sd_bus_message *i, UnitSetPropertiesMode mode, sd_bus_error *error);
-int bus_scope_commit_properties(Unit *u);
-
-int bus_scope_send_request_stop(Scope *s);
diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
deleted file mode 100644
index e1f3d5649..000000000
--- a/src/core/dbus-service.c
+++ /dev/null
@@ -1,266 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 "strv.h"
-#include "path-util.h"
-#include "unit.h"
-#include "service.h"
-#include "dbus-execute.h"
-#include "dbus-kill.h"
-#include "dbus-cgroup.h"
-#include "dbus-service.h"
-#include "bus-util.h"
-
-static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, service_type, ServiceType);
-static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, service_result, ServiceResult);
-static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_restart, service_restart, ServiceRestart);
-static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_notify_access, notify_access, NotifyAccess);
-static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_failure_action, failure_action, FailureAction);
-
-const sd_bus_vtable bus_service_vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Service, type), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Restart", "s", property_get_restart, offsetof(Service, restart), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("PIDFile", "s", NULL, offsetof(Service, pid_file), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("NotifyAccess", "s", property_get_notify_access, offsetof(Service, notify_access), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RestartUSec", "t", bus_property_get_usec, offsetof(Service, restart_usec), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("TimeoutStartUSec", "t", bus_property_get_usec, offsetof(Service, timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec, offsetof(Service, timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("WatchdogUSec", "t", bus_property_get_usec, offsetof(Service, watchdog_usec), SD_BUS_VTABLE_PROPERTY_CONST),
- BUS_PROPERTY_DUAL_TIMESTAMP("WatchdogTimestamp", offsetof(Service, watchdog_timestamp), 0),
- SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Service, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Service, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("StartLimitAction", "s", property_get_failure_action, offsetof(Service, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Service, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("FailureAction", "s", property_get_failure_action, offsetof(Service, failure_action), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("PermissionsStartOnly", "b", bus_property_get_bool, offsetof(Service, permissions_start_only), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RootDirectoryStartOnly", "b", bus_property_get_bool, offsetof(Service, root_directory_start_only), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RemainAfterExit", "b", bus_property_get_bool, offsetof(Service, remain_after_exit), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("GuessMainPID", "b", bus_property_get_bool, offsetof(Service, guess_main_pid), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("MainPID", "u", bus_property_get_pid, offsetof(Service, main_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Service, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("BusName", "s", NULL, offsetof(Service, bus_name), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("FileDescriptorStoreMax", "u", NULL, offsetof(Service, n_fd_store_max), SD_BUS_VTABLE_PROPERTY_CONST),
- 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("Result", "s", property_get_result, offsetof(Service, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- BUS_EXEC_STATUS_VTABLE("ExecMain", offsetof(Service, main_exec_status), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Service, exec_command[SERVICE_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
- BUS_EXEC_COMMAND_LIST_VTABLE("ExecStart", offsetof(Service, exec_command[SERVICE_EXEC_START]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
- BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Service, exec_command[SERVICE_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
- BUS_EXEC_COMMAND_LIST_VTABLE("ExecReload", offsetof(Service, exec_command[SERVICE_EXEC_RELOAD]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
- BUS_EXEC_COMMAND_LIST_VTABLE("ExecStop", offsetof(Service, exec_command[SERVICE_EXEC_STOP]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
- BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPost", offsetof(Service, exec_command[SERVICE_EXEC_STOP_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
- SD_BUS_VTABLE_END
-};
-
-static int bus_service_set_transient_property(
- Service *s,
- const char *name,
- sd_bus_message *message,
- UnitSetPropertiesMode mode,
- sd_bus_error *error) {
-
- int r;
-
- assert(s);
- assert(name);
- assert(message);
-
- if (streq(name, "RemainAfterExit")) {
- int b;
-
- r = sd_bus_message_read(message, "b", &b);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- s->remain_after_exit = b;
- unit_write_drop_in_private_format(UNIT(s), mode, name, "RemainAfterExit=%s\n", yes_no(b));
- }
-
- return 1;
-
- } else if (streq(name, "Type")) {
- const char *t;
- ServiceType k;
-
- r = sd_bus_message_read(message, "s", &t);
- if (r < 0)
- return r;
-
- k = service_type_from_string(t);
- if (k < 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid service type %s", t);
-
- if (mode != UNIT_CHECK) {
- s->type = k;
- unit_write_drop_in_private_format(UNIT(s), mode, name, "Type=%s\n", service_type_to_string(s->type));
- }
-
- return 1;
-
- } else if (streq(name, "ExecStart")) {
- unsigned n = 0;
-
- r = sd_bus_message_enter_container(message, 'a', "(sasb)");
- if (r < 0)
- return r;
-
- while ((r = sd_bus_message_enter_container(message, 'r', "sasb")) > 0) {
- _cleanup_strv_free_ char **argv = NULL;
- const char *path;
- int b;
-
- r = sd_bus_message_read(message, "s", &path);
- if (r < 0)
- return r;
-
- if (!path_is_absolute(path))
- return sd_bus_error_set_errnof(error, EINVAL, "Path %s is not absolute.", path);
-
- r = sd_bus_message_read_strv(message, &argv);
- if (r < 0)
- return r;
-
- r = sd_bus_message_read(message, "b", &b);
- if (r < 0)
- return r;
-
- r = sd_bus_message_exit_container(message);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- ExecCommand *c;
-
- c = new0(ExecCommand, 1);
- if (!c)
- return -ENOMEM;
-
- c->path = strdup(path);
- if (!c->path) {
- free(c);
- return -ENOMEM;
- }
-
- c->argv = argv;
- argv = NULL;
-
- c->ignore = b;
-
- path_kill_slashes(c->path);
- exec_command_append_list(&s->exec_command[SERVICE_EXEC_START], c);
- }
-
- n++;
- }
-
- if (r < 0)
- return r;
-
- r = sd_bus_message_exit_container(message);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- _cleanup_free_ char *buf = NULL;
- _cleanup_fclose_ FILE *f = NULL;
- ExecCommand *c;
- size_t size = 0;
-
- if (n == 0)
- s->exec_command[SERVICE_EXEC_START] = exec_command_free_list(s->exec_command[SERVICE_EXEC_START]);
-
- f = open_memstream(&buf, &size);
- if (!f)
- return -ENOMEM;
-
- fputs("ExecStart=\n", f);
-
- LIST_FOREACH(command, c, s->exec_command[SERVICE_EXEC_START]) {
- _cleanup_free_ char *a;
-
- a = strv_join_quoted(c->argv);
- if (!a)
- return -ENOMEM;
-
- fprintf(f, "ExecStart=%s@%s %s\n",
- c->ignore ? "-" : "",
- c->path,
- a);
- }
-
- fflush(f);
- unit_write_drop_in_private(UNIT(s), mode, name, buf);
- }
-
- return 1;
- }
-
- return 0;
-}
-
-int bus_service_set_property(
- Unit *u,
- const char *name,
- sd_bus_message *message,
- UnitSetPropertiesMode mode,
- sd_bus_error *error) {
-
- Service *s = SERVICE(u);
- int r;
-
- assert(s);
- assert(name);
- assert(message);
-
- r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error);
- if (r != 0)
- return r;
-
- if (u->transient && u->load_state == UNIT_STUB) {
- /* This is a transient unit, let's load a little more */
-
- r = bus_service_set_transient_property(s, name, message, mode, error);
- if (r != 0)
- return r;
-
- r = bus_exec_context_set_transient_property(u, &s->exec_context, name, message, mode, error);
- if (r != 0)
- return r;
-
- r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, mode, error);
- if (r != 0)
- return r;
- }
-
- return 0;
-}
-
-int bus_service_commit_properties(Unit *u) {
- assert(u);
-
- unit_update_cgroup_members_masks(u);
- unit_realize_cgroup(u);
-
- return 0;
-}
diff --git a/src/core/dbus-service.h b/src/core/dbus-service.h
deleted file mode 100644
index aab9f7aa2..000000000
--- a/src/core/dbus-service.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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"
-
-extern const sd_bus_vtable bus_service_vtable[];
-
-int bus_service_set_property(Unit *u, const char *name, sd_bus_message *i, UnitSetPropertiesMode mode, sd_bus_error *error);
-int bus_service_commit_properties(Unit *u);
diff --git a/src/core/dbus-slice.c b/src/core/dbus-slice.c
deleted file mode 100644
index 09e78d1f3..000000000
--- a/src/core/dbus-slice.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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"
-#include "slice.h"
-#include "dbus-cgroup.h"
-#include "dbus-slice.h"
-
-const sd_bus_vtable bus_slice_vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_VTABLE_END
-};
-
-int bus_slice_set_property(
- Unit *u,
- const char *name,
- sd_bus_message *message,
- UnitSetPropertiesMode mode,
- sd_bus_error *error) {
-
- Slice *s = SLICE(u);
-
- assert(name);
- assert(u);
-
- return bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error);
-}
-
-int bus_slice_commit_properties(Unit *u) {
- assert(u);
-
- unit_update_cgroup_members_masks(u);
- unit_realize_cgroup(u);
-
- return 0;
-}
diff --git a/src/core/dbus-slice.h b/src/core/dbus-slice.h
deleted file mode 100644
index eadc3b1a9..000000000
--- a/src/core/dbus-slice.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 "unit.h"
-
-extern const sd_bus_vtable bus_slice_vtable[];
-
-int bus_slice_set_property(Unit *u, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error);
-int bus_slice_commit_properties(Unit *u);
diff --git a/src/core/dbus-snapshot.c b/src/core/dbus-snapshot.c
deleted file mode 100644
index 0be46c288..000000000
--- a/src/core/dbus-snapshot.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 "selinux-access.h"
-#include "unit.h"
-#include "dbus.h"
-#include "snapshot.h"
-#include "dbus-snapshot.h"
-
-int bus_snapshot_method_remove(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Snapshot *s = userdata;
- int r;
-
- assert(bus);
- assert(message);
- assert(s);
-
- r = mac_selinux_unit_access_check(UNIT(s), message, "stop", error);
- if (r < 0)
- return r;
-
- r = bus_verify_manage_units_async(UNIT(s)->manager, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
- snapshot_remove(s);
-
- return sd_bus_reply_method_return(message, NULL);
-}
-
-const sd_bus_vtable bus_snapshot_vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_PROPERTY("Cleanup", "b", bus_property_get_bool, offsetof(Snapshot, cleanup), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_METHOD("Remove", NULL, NULL, bus_snapshot_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_VTABLE_END
-};
diff --git a/src/core/dbus-snapshot.h b/src/core/dbus-snapshot.h
deleted file mode 100644
index d7551cbcd..000000000
--- a/src/core/dbus-snapshot.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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"
-
-extern const sd_bus_vtable bus_snapshot_vtable[];
-
-int bus_snapshot_method_remove(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c
deleted file mode 100644
index 02599a9e5..000000000
--- a/src/core/dbus-socket.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 "socket.h"
-#include "dbus-execute.h"
-#include "dbus-cgroup.h"
-#include "dbus-socket.h"
-#include "bus-util.h"
-
-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 int property_get_listen(
- 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);
- SocketPort *p;
- int r;
-
- assert(bus);
- assert(reply);
- assert(s);
-
- r = sd_bus_message_open_container(reply, 'a', "(ss)");
- if (r < 0)
- return r;
-
- LIST_FOREACH(port, p, s->ports) {
- _cleanup_free_ char *address = NULL;
- const char *a;
-
- switch (p->type) {
- case SOCKET_SOCKET: {
- r = socket_address_print(&p->address, &address);
- if (r)
- return r;
-
- a = address;
- break;
- }
-
- case SOCKET_SPECIAL:
- case SOCKET_MQUEUE:
- case SOCKET_FIFO:
- a = p->path;
- break;
-
- default:
- assert_not_reached("Unknown socket type");
- }
-
- r = sd_bus_message_append(reply, "(ss)", socket_port_type_to_string(p), a);
- if (r < 0)
- return r;
- }
-
- return sd_bus_message_close_container(reply);
-}
-
-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),
- SD_BUS_PROPERTY("Backlog", "u", bus_property_get_unsigned, offsetof(Socket, backlog), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("TimeoutUSec", "t", bus_property_get_usec, offsetof(Socket, timeout_usec), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("BindToDevice", "s", NULL, offsetof(Socket, bind_to_device), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("SocketUser", "s", NULL, offsetof(Socket, user), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("SocketGroup", "s", NULL, offsetof(Socket, group), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("SocketMode", "u", bus_property_get_mode, offsetof(Socket, socket_mode), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DirectoryMode", "u", bus_property_get_mode, offsetof(Socket, directory_mode), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Accept", "b", bus_property_get_bool, offsetof(Socket, accept), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("KeepAlive", "b", bus_property_get_bool, offsetof(Socket, keep_alive), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("KeepAliveTimeUSec", "t", bus_property_get_usec, offsetof(Socket, keep_alive_time), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("KeepAliveIntervalUSec", "t", bus_property_get_usec, offsetof(Socket, keep_alive_interval), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("KeepAliveProbes", "u", bus_property_get_unsigned, offsetof(Socket, keep_alive_cnt), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DeferAcceptUSec" , "t", bus_property_get_usec, offsetof(Socket, defer_accept), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("NoDelay", "b", bus_property_get_bool, offsetof(Socket, no_delay), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Priority", "i", bus_property_get_int, offsetof(Socket, priority), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("ReceiveBuffer", "t", bus_property_get_size, offsetof(Socket, receive_buffer), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("SendBuffer", "t", bus_property_get_size, offsetof(Socket, send_buffer), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("IPTOS", "i", bus_property_get_int, offsetof(Socket, ip_tos), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("IPTTL", "i", bus_property_get_int, offsetof(Socket, ip_ttl), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("PipeSize", "t", bus_property_get_size, offsetof(Socket, pipe_size), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("FreeBind", "b", bus_property_get_bool, offsetof(Socket, free_bind), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Transparent", "b", bus_property_get_bool, offsetof(Socket, transparent), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Broadcast", "b", bus_property_get_bool, offsetof(Socket, broadcast), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("PassCredentials", "b", bus_property_get_bool, offsetof(Socket, pass_cred), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("PassSecurity", "b", bus_property_get_bool, offsetof(Socket, pass_sec), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RemoveOnStop", "b", bus_property_get_bool, offsetof(Socket, remove_on_stop), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Listen", "a(ss)", property_get_listen, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Symlinks", "as", NULL, offsetof(Socket, symlinks), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Mark", "i", bus_property_get_int, offsetof(Socket, mark), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("MaxConnections", "u", bus_property_get_unsigned, offsetof(Socket, max_connections), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("MessageQueueMaxMessages", "x", bus_property_get_long, offsetof(Socket, mq_maxmsg), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("MessageQueueMessageSize", "x", bus_property_get_long, offsetof(Socket, mq_msgsize), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("ReusePort", "b", bus_property_get_bool, offsetof(Socket, reuse_port), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("SmackLabel", "s", NULL, offsetof(Socket, smack), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("SmackLabelIPIn", "s", NULL, offsetof(Socket, smack_ip_in), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("SmackLabelIPOut", "s", NULL, offsetof(Socket, smack_ip_out), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Socket, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- 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),
- 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),
- BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPost", offsetof(Socket, exec_command[SOCKET_EXEC_STOP_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
- SD_BUS_VTABLE_END
-};
-
-int bus_socket_set_property(
- Unit *u,
- const char *name,
- sd_bus_message *message,
- UnitSetPropertiesMode mode,
- sd_bus_error *error) {
-
- Socket *s = SOCKET(u);
-
- assert(s);
- assert(name);
- assert(message);
-
- return bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error);
-}
-
-int bus_socket_commit_properties(Unit *u) {
- assert(u);
-
- unit_update_cgroup_members_masks(u);
- unit_realize_cgroup(u);
-
- return 0;
-}
diff --git a/src/core/dbus-socket.h b/src/core/dbus-socket.h
deleted file mode 100644
index 17164d987..000000000
--- a/src/core/dbus-socket.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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"
-
-extern const sd_bus_vtable bus_socket_vtable[];
-
-int bus_socket_set_property(Unit *u, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error);
-int bus_socket_commit_properties(Unit *u);
diff --git a/src/core/dbus-swap.c b/src/core/dbus-swap.c
deleted file mode 100644
index 009337130..000000000
--- a/src/core/dbus-swap.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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/>.
-***/
-
-#include "unit.h"
-#include "swap.h"
-#include "dbus-execute.h"
-#include "dbus-cgroup.h"
-#include "dbus-swap.h"
-#include "bus-util.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);
-
- 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);
-}
-
-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);
-
- if (s->from_fragment)
- options = s->parameters_fragment.options;
-
- return sd_bus_message_append(reply, "s", options);
-}
-
-static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, swap_result, SwapResult);
-
-const sd_bus_vtable bus_swap_vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_PROPERTY("What", "s", NULL, offsetof(Swap, what), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("Priority", "i", property_get_priority, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("Options", "s", property_get_options, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- 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),
- 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
-};
-
-int bus_swap_set_property(
- Unit *u,
- const char *name,
- sd_bus_message *message,
- UnitSetPropertiesMode mode,
- sd_bus_error *error) {
-
- Swap *s = SWAP(u);
-
- assert(s);
- assert(name);
- assert(message);
-
- return bus_cgroup_set_property(u, &s->cgroup_context, name, message, mode, error);
-}
-
-int bus_swap_commit_properties(Unit *u) {
- assert(u);
-
- unit_update_cgroup_members_masks(u);
- unit_realize_cgroup(u);
-
- return 0;
-}
diff --git a/src/core/dbus-swap.h b/src/core/dbus-swap.h
deleted file mode 100644
index 9469f68ab..000000000
--- a/src/core/dbus-swap.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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/>.
-***/
-
-#include "sd-bus.h"
-#include "unit.h"
-
-extern const sd_bus_vtable bus_swap_vtable[];
-
-int bus_swap_set_property(Unit *u, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error);
-int bus_swap_commit_properties(Unit *u);
diff --git a/src/core/dbus-target.c b/src/core/dbus-target.c
deleted file mode 100644
index 350f5c3ed..000000000
--- a/src/core/dbus-target.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 "dbus-target.h"
-
-const sd_bus_vtable bus_target_vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_VTABLE_END
-};
diff --git a/src/core/dbus-target.h b/src/core/dbus-target.h
deleted file mode 100644
index 4c4297bc9..000000000
--- a/src/core/dbus-target.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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/>.
-***/
-
-
-extern const sd_bus_vtable bus_target_vtable[];
diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c
deleted file mode 100644
index 74a991435..000000000
--- a/src/core/dbus-timer.c
+++ /dev/null
@@ -1,326 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 "timer.h"
-#include "dbus-timer.h"
-#include "bus-util.h"
-#include "strv.h"
-
-static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, timer_result, TimerResult);
-
-static int property_get_monotonic_timers(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Timer *t = userdata;
- TimerValue *v;
- int r;
-
- assert(bus);
- assert(reply);
- assert(t);
-
- r = sd_bus_message_open_container(reply, 'a', "(stt)");
- if (r < 0)
- return r;
-
- LIST_FOREACH(value, v, t->values) {
- _cleanup_free_ char *buf = NULL;
- const char *s;
- size_t l;
-
- if (v->base == TIMER_CALENDAR)
- continue;
-
- s = timer_base_to_string(v->base);
- assert(endswith(s, "Sec"));
-
- /* s/Sec/USec/ */
- l = strlen(s);
- buf = new(char, l+2);
- if (!buf)
- return -ENOMEM;
-
- memcpy(buf, s, l-3);
- memcpy(buf+l-3, "USec", 5);
-
- r = sd_bus_message_append(reply, "(stt)", buf, v->value, v->next_elapse);
- if (r < 0)
- return r;
- }
-
- return sd_bus_message_close_container(reply);
-}
-
-static int property_get_calendar_timers(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Timer *t = userdata;
- TimerValue *v;
- int r;
-
- assert(bus);
- assert(reply);
- assert(t);
-
- r = sd_bus_message_open_container(reply, 'a', "(sst)");
- if (r < 0)
- return r;
-
- LIST_FOREACH(value, v, t->values) {
- _cleanup_free_ char *buf = NULL;
-
- if (v->base != TIMER_CALENDAR)
- continue;
-
- r = calendar_spec_to_string(v->calendar_spec, &buf);
- if (r < 0)
- return r;
-
- r = sd_bus_message_append(reply, "(sst)", timer_base_to_string(v->base), buf, v->next_elapse);
- if (r < 0)
- return r;
- }
-
- 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,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Timer *t = userdata;
- usec_t x;
-
- assert(bus);
- assert(reply);
- assert(t);
-
- if (t->next_elapse_monotonic_or_boottime <= 0)
- x = 0;
- else if (t->wake_system) {
- usec_t a, b;
-
- a = now(CLOCK_MONOTONIC);
- b = now(CLOCK_BOOTTIME);
-
- if (t->next_elapse_monotonic_or_boottime + a > b)
- x = t->next_elapse_monotonic_or_boottime + a - b;
- else
- x = 0;
- } else
- x = t->next_elapse_monotonic_or_boottime;
-
- return sd_bus_message_append(reply, "t", x);
-}
-
-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("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),
- SD_BUS_PROPERTY("NextElapseUSecMonotonic", "t", property_get_next_elapse_monotonic, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- BUS_PROPERTY_DUAL_TIMESTAMP("LastTriggerUSec", offsetof(Timer, last_trigger), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Timer, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("AccuracyUSec", "t", bus_property_get_usec, offsetof(Timer, accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Persistent", "b", bus_property_get_bool, offsetof(Timer, persistent), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("WakeSystem", "b", bus_property_get_bool, offsetof(Timer, wake_system), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_VTABLE_END
-};
-
-static int bus_timer_set_transient_property(
- Timer *t,
- const char *name,
- sd_bus_message *message,
- UnitSetPropertiesMode mode,
- sd_bus_error *error) {
-
- int r;
-
- assert(t);
- assert(name);
- assert(message);
-
- if (STR_IN_SET(name,
- "OnActiveSec",
- "OnBootSec",
- "OnStartupSec",
- "OnUnitActiveSec",
- "OnUnitInactiveSec")) {
-
- TimerValue *v;
- TimerBase b = _TIMER_BASE_INVALID;
- usec_t u = 0;
-
- b = timer_base_from_string(name);
- if (b < 0)
- return -EINVAL;
-
- r = sd_bus_message_read(message, "t", &u);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- char time[FORMAT_TIMESPAN_MAX];
-
- unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, format_timespan(time, sizeof(time), u, USEC_PER_MSEC));
-
- v = new0(TimerValue, 1);
- if (!v)
- return -ENOMEM;
-
- v->base = b;
- v->value = u;
-
- LIST_PREPEND(value, t->values, v);
- }
-
- return 1;
-
- } else if (streq(name, "OnCalendar")) {
-
- TimerValue *v;
- CalendarSpec *c = NULL;
- const char *str;
-
- r = sd_bus_message_read(message, "s", &str);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- r = calendar_spec_from_string(str, &c);
- if (r < 0)
- return r;
-
- unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, str);
-
- v = new0(TimerValue, 1);
- if (!v) {
- if (c)
- calendar_spec_free(c);
- return -ENOMEM;
- }
-
- v->base = TIMER_CALENDAR;
- v->calendar_spec = c;
-
- LIST_PREPEND(value, t->values, v);
- }
-
- return 1;
-
- } else if (streq(name, "AccuracySec")) {
-
- usec_t u = 0;
-
- r = sd_bus_message_read(message, "t", &u);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- char time[FORMAT_TIMESPAN_MAX];
-
- t->accuracy_usec = u;
- unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, format_timespan(time, sizeof(time), u, USEC_PER_MSEC));
- }
-
- return 1;
-
- } else if (streq(name, "WakeSystem")) {
-
- int b;
-
- r = sd_bus_message_read(message, "b", &b);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- t->wake_system = b;
- unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, yes_no(t->wake_system));
- }
-
- return 1;
-
- }
-
- return 0;
-}
-
-int bus_timer_set_property(
- Unit *u,
- const char *name,
- sd_bus_message *message,
- UnitSetPropertiesMode mode,
- sd_bus_error *error) {
-
- Timer *t = TIMER(u);
- int r;
-
- assert(t);
- assert(name);
- assert(message);
-
- if (u->transient && u->load_state == UNIT_STUB) {
- r = bus_timer_set_transient_property(t, name, message, mode, error);
- if (r != 0)
- return r;
- }
-
- return 0;
-}
diff --git a/src/core/dbus-timer.h b/src/core/dbus-timer.h
deleted file mode 100644
index 103172f05..000000000
--- a/src/core/dbus-timer.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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"
-
-extern const sd_bus_vtable bus_timer_vtable[];
-
-int bus_timer_set_property(Unit *u, const char *name, sd_bus_message *i, UnitSetPropertiesMode mode, sd_bus_error *error);
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
deleted file mode 100644
index af7dc2624..000000000
--- a/src/core/dbus-unit.c
+++ /dev/null
@@ -1,1109 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 "log.h"
-#include "selinux-access.h"
-#include "cgroup-util.h"
-#include "strv.h"
-#include "bus-common-errors.h"
-#include "dbus.h"
-#include "dbus-unit.h"
-
-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_failure_action, failure_action, FailureAction);
-
-static int property_get_names(
- 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;
- Iterator i;
- const char *t;
- int r;
-
- assert(bus);
- assert(reply);
- assert(u);
-
- r = sd_bus_message_open_container(reply, 'a', "s");
- if (r < 0)
- return r;
-
- SET_FOREACH(t, u->names, i) {
- r = sd_bus_message_append(reply, "s", t);
- if (r < 0)
- return r;
- }
-
- return sd_bus_message_close_container(reply);
-}
-
-static int property_get_following(
- 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, *f;
-
- assert(bus);
- assert(reply);
- assert(u);
-
- f = unit_following(u);
- return sd_bus_message_append(reply, "s", f ? f->id : "");
-}
-
-static int property_get_dependencies(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Set *s = *(Set**) userdata;
- Iterator j;
- Unit *u;
- int r;
-
- assert(bus);
- assert(reply);
-
- r = sd_bus_message_open_container(reply, 'a', "s");
- if (r < 0)
- return r;
-
- SET_FOREACH(u, s, j) {
- r = sd_bus_message_append(reply, "s", u->id);
- if (r < 0)
- return r;
- }
-
- 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,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Unit *u = userdata;
- int r;
-
- assert(bus);
- assert(reply);
- assert(u);
-
- r = unit_get_unit_file_preset(u);
-
- return sd_bus_message_append(reply, "s",
- r < 0 ? "":
- 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);
-
- /* On the lower levels we assume that every unit we can start
- * we can also stop */
-
- return sd_bus_message_append(reply, "b", unit_can_start(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,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- _cleanup_free_ char *p = NULL;
- Unit *u = userdata;
-
- assert(bus);
- assert(reply);
- assert(u);
-
- if (!u->job)
- return sd_bus_message_append(reply, "(uo)", 0, "/");
-
- p = job_dbus_path(u->job);
- 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));
-}
-
-static int property_get_conditions(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- const char *(*to_string)(ConditionType type) = NULL;
- Condition **list = userdata, *c;
- int r;
-
- assert(bus);
- assert(reply);
- assert(list);
-
- to_string = streq(property, "Asserts") ? assert_type_to_string : condition_type_to_string;
-
- r = sd_bus_message_open_container(reply, 'a', "(sbbsi)");
- if (r < 0)
- return r;
-
- LIST_FOREACH(conditions, c, *list) {
- int tristate;
-
- tristate =
- c->result == CONDITION_UNTESTED ? 0 :
- c->result == CONDITION_SUCCEEDED ? 1 : -1;
-
- r = sd_bus_message_append(reply, "(sbbsi)",
- to_string(c->type),
- c->trigger, c->negate,
- c->parameter, tristate);
- if (r < 0)
- return r;
-
- }
-
- return sd_bus_message_close_container(reply);
-}
-
-static int property_get_load_error(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
- Unit *u = userdata;
-
- assert(bus);
- assert(reply);
- assert(u);
-
- if (u->load_error != 0)
- sd_bus_error_set_errno(&e, u->load_error);
-
- return sd_bus_message_append(reply, "(ss)", e.name, e.message);
-}
-
-int bus_unit_method_start_generic(
- sd_bus *bus,
- sd_bus_message *message,
- Unit *u,
- JobType job_type,
- bool reload_if_possible,
- sd_bus_error *error) {
-
- const char *smode;
- JobMode mode;
- int r;
-
- assert(bus);
- assert(message);
- assert(u);
- assert(job_type >= 0 && job_type < _JOB_TYPE_MAX);
-
- r = mac_selinux_unit_access_check(u, message, job_type == JOB_STOP ? "stop" : "start", error);
- if (r < 0)
- return r;
-
- r = sd_bus_message_read(message, "s", &smode);
- if (r < 0)
- return r;
-
- mode = job_mode_from_string(smode);
- if (mode < 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode);
-
- r = bus_verify_manage_units_async(u->manager, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
- return bus_unit_queue_job(bus, message, u, job_type, mode, reload_if_possible, error);
-}
-
-static int method_start(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return bus_unit_method_start_generic(bus, message, userdata, JOB_START, false, error);
-}
-
-static int method_stop(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return bus_unit_method_start_generic(bus, message, userdata, JOB_STOP, false, error);
-}
-
-static int method_reload(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return bus_unit_method_start_generic(bus, message, userdata, JOB_RELOAD, false, error);
-}
-
-static int method_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, false, error);
-}
-
-static int method_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, false, error);
-}
-
-static int method_reload_or_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return bus_unit_method_start_generic(bus, message, userdata, JOB_RESTART, true, error);
-}
-
-static int method_reload_or_try_restart(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return bus_unit_method_start_generic(bus, message, userdata, JOB_TRY_RESTART, true, error);
-}
-
-int bus_unit_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Unit *u = userdata;
- const char *swho;
- int32_t signo;
- KillWho who;
- int r;
-
- assert(bus);
- assert(message);
- assert(u);
-
- r = mac_selinux_unit_access_check(u, message, "stop", error);
- if (r < 0)
- return r;
-
- r = sd_bus_message_read(message, "si", &swho, &signo);
- if (r < 0)
- return r;
-
- if (isempty(swho))
- who = KILL_ALL;
- else {
- who = kill_who_from_string(swho);
- if (who < 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho);
- }
-
- if (signo <= 0 || signo >= _NSIG)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range.");
-
- r = bus_verify_manage_units_async_for_kill(u->manager, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
- r = unit_kill(u, who, signo, error);
- if (r < 0)
- return r;
-
- return sd_bus_reply_method_return(message, NULL);
-}
-
-int bus_unit_method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Unit *u = userdata;
- int r;
-
- assert(bus);
- assert(message);
- assert(u);
-
- r = mac_selinux_unit_access_check(u, message, "reload", error);
- if (r < 0)
- return r;
-
- r = bus_verify_manage_units_async(u->manager, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
- unit_reset_failed(u);
-
- return sd_bus_reply_method_return(message, NULL);
-}
-
-int bus_unit_method_set_properties(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Unit *u = userdata;
- int runtime, r;
-
- assert(bus);
- assert(message);
- assert(u);
-
- r = mac_selinux_unit_access_check(u, message, "start", error);
- if (r < 0)
- return r;
-
- r = sd_bus_message_read(message, "b", &runtime);
- if (r < 0)
- return r;
-
- r = bus_verify_manage_units_async(u->manager, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
- r = bus_unit_set_properties(u, message, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, error);
- if (r < 0)
- return r;
-
- return sd_bus_reply_method_return(message, NULL);
-}
-
-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("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("RequiresOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Wants", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BINDS_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PART_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Before", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BEFORE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("After", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_AFTER]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_ON_FAILURE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_JOINS_NAMESPACE_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("SubState", "s", property_get_sub_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("FragmentPath", "s", NULL, offsetof(Unit, fragment_path), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0),
- SD_BUS_PROPERTY("UnitFilePreset", "s", property_get_unit_file_preset, 0, 0),
- BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit, inactive_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("CanStart", "b", property_get_can_start, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- 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("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),
- SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool, offsetof(Unit, allow_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool, offsetof(Unit, ignore_on_snapshot), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_failure_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL, offsetof(Unit, job_timeout_reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("AssertResult", "b", bus_property_get_bool, offsetof(Unit, assert_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit, condition_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- BUS_PROPERTY_DUAL_TIMESTAMP("AssertTimestamp", offsetof(Unit, assert_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, offsetof(Unit, conditions), 0),
- SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0),
- SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
-
- SD_BUS_METHOD("Start", "s", "o", method_start, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("Stop", "s", "o", method_stop, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("Reload", "s", "o", method_reload, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("Restart", "s", "o", method_restart, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, SD_BUS_VTABLE_UNPRIVILEGED),
-
- SD_BUS_VTABLE_END
-};
-
-static int property_get_slice(
- 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_slice_name(u));
-}
-
-static int property_get_current_memory(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- uint64_t sz = (uint64_t) -1;
- Unit *u = userdata;
- int r;
-
- assert(bus);
- assert(reply);
- assert(u);
-
- r = unit_get_memory_current(u, &sz);
- if (r < 0 && r != -ENODATA)
- log_unit_warning_errno(u->id, r, "Failed to get memory.usage_in_bytes attribute: %m");
-
- return sd_bus_message_append(reply, "t", sz);
-}
-
-static int property_get_cpu_usage(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- nsec_t ns = (nsec_t) -1;
- Unit *u = userdata;
- int r;
-
- assert(bus);
- assert(reply);
- assert(u);
-
- r = unit_get_cpu_usage(u, &ns);
- if (r < 0 && r != -ENODATA)
- log_unit_warning_errno(u->id, r, "Failed to get cpuacct.usage attribute: %m");
-
- return sd_bus_message_append(reply, "t", ns);
-}
-
-const sd_bus_vtable bus_unit_cgroup_vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0),
- SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Unit, cgroup_path), 0),
- SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0),
- SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage, 0, 0),
- SD_BUS_VTABLE_END
-};
-
-static int send_new_signal(sd_bus *bus, void *userdata) {
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
- _cleanup_free_ char *p = NULL;
- Unit *u = userdata;
- int r;
-
- assert(bus);
- assert(u);
-
- p = unit_dbus_path(u);
- if (!u)
- return -ENOMEM;
-
- r = sd_bus_message_new_signal(
- bus,
- &m,
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "UnitNew");
- if (r < 0)
- return r;
-
- r = sd_bus_message_append(m, "so", u->id, p);
- if (r < 0)
- return r;
-
- return sd_bus_send(bus, m, NULL);
-}
-
-static int send_changed_signal(sd_bus *bus, void *userdata) {
- _cleanup_free_ char *p = NULL;
- Unit *u = userdata;
- int r;
-
- assert(bus);
- assert(u);
-
- p = unit_dbus_path(u);
- if (!p)
- return -ENOMEM;
-
- /* Send a properties changed signal. First for the specific
- * type, then for the generic unit. The clients may rely on
- * this order to get atomic behavior if needed. */
-
- r = sd_bus_emit_properties_changed_strv(
- bus, p,
- UNIT_VTABLE(u)->bus_interface,
- NULL);
- if (r < 0)
- return r;
-
- return sd_bus_emit_properties_changed_strv(
- bus, p,
- "org.freedesktop.systemd1.Unit",
- NULL);
-}
-
-void bus_unit_send_change_signal(Unit *u) {
- int r;
- assert(u);
-
- if (u->in_dbus_queue) {
- LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
- u->in_dbus_queue = false;
- }
-
- if (!u->id)
- return;
-
- r = bus_foreach_bus(u->manager, NULL, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u);
- if (r < 0)
- log_debug_errno(r, "Failed to send unit change signal for %s: %m", u->id);
-
- u->sent_dbus_new_signal = true;
-}
-
-static int send_removed_signal(sd_bus *bus, void *userdata) {
- _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
- _cleanup_free_ char *p = NULL;
- Unit *u = userdata;
- int r;
-
- assert(bus);
- assert(u);
-
- p = unit_dbus_path(u);
- if (!u)
- return -ENOMEM;
-
- r = sd_bus_message_new_signal(
- bus,
- &m,
- "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager",
- "UnitRemoved");
- if (r < 0)
- return r;
-
- r = sd_bus_message_append(m, "so", u->id, p);
- if (r < 0)
- return r;
-
- return sd_bus_send(bus, m, NULL);
-}
-
-void bus_unit_send_removed_signal(Unit *u) {
- int r;
- assert(u);
-
- if (!u->sent_dbus_new_signal)
- bus_unit_send_change_signal(u);
-
- if (!u->id)
- return;
-
- r = bus_foreach_bus(u->manager, NULL, send_removed_signal, u);
- if (r < 0)
- log_debug_errno(r, "Failed to send unit remove signal for %s: %m", u->id);
-}
-
-int bus_unit_queue_job(
- sd_bus *bus,
- sd_bus_message *message,
- Unit *u,
- JobType type,
- JobMode mode,
- bool reload_if_possible,
- sd_bus_error *error) {
-
- _cleanup_free_ char *path = NULL;
- Job *j;
- int r;
-
- assert(bus);
- assert(message);
- assert(u);
- assert(type >= 0 && type < _JOB_TYPE_MAX);
- assert(mode >= 0 && mode < _JOB_MODE_MAX);
-
- if (reload_if_possible && unit_can_reload(u)) {
- if (type == JOB_RESTART)
- type = JOB_RELOAD_OR_START;
- else if (type == JOB_TRY_RESTART)
- type = JOB_RELOAD;
- }
-
- r = mac_selinux_unit_access_check(
- u, message,
- (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" :
- type == JOB_STOP ? "stop" : "reload", error);
- if (r < 0)
- return r;
-
- if (type == JOB_STOP &&
- (u->load_state == UNIT_NOT_FOUND || u->load_state == UNIT_ERROR) &&
- unit_active_state(u) == UNIT_INACTIVE)
- return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
-
- if ((type == JOB_START && u->refuse_manual_start) ||
- (type == JOB_STOP && u->refuse_manual_stop) ||
- ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)))
- return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id);
-
- r = manager_add_job(u->manager, type, u, mode, true, error, &j);
- if (r < 0)
- return r;
-
- if (bus == u->manager->api_bus) {
- if (!j->clients) {
- r = sd_bus_track_new(bus, &j->clients, NULL, NULL);
- if (r < 0)
- return r;
- }
-
- r = sd_bus_track_add_sender(j->clients, message);
- if (r < 0)
- return r;
- }
-
- path = job_dbus_path(j);
- if (!path)
- return -ENOMEM;
-
- return sd_bus_reply_method_return(message, "o", path);
-}
-
-static int bus_unit_set_transient_property(
- Unit *u,
- const char *name,
- sd_bus_message *message,
- UnitSetPropertiesMode mode,
- sd_bus_error *error) {
-
- int r;
-
- assert(u);
- assert(name);
- assert(message);
-
- if (streq(name, "Description")) {
- const char *d;
-
- r = sd_bus_message_read(message, "s", &d);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- r = unit_set_description(u, d);
- if (r < 0)
- return r;
-
- unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", d);
- }
-
- return 1;
-
- } else if (streq(name, "DefaultDependencies")) {
- int b;
-
- r = sd_bus_message_read(message, "b", &b);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- u->default_dependencies = b;
- unit_write_drop_in_format(u, mode, name, "[Unit]\nDefaultDependencies=%s\n", yes_no(b));
- }
-
- return 1;
-
- } else if (streq(name, "Slice") && unit_get_cgroup_context(u)) {
- const char *s;
-
- r = sd_bus_message_read(message, "s", &s);
- if (r < 0)
- return r;
-
- if (!unit_name_is_valid(s, TEMPLATE_INVALID) || !endswith(s, ".slice"))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid slice name %s", s);
-
- if (isempty(s)) {
- if (mode != UNIT_CHECK) {
- unit_ref_unset(&u->slice);
- unit_remove_drop_in(u, mode, name);
- }
- } else {
- Unit *slice;
-
- r = manager_load_unit(u->manager, s, NULL, error, &slice);
- if (r < 0)
- return r;
-
- if (slice->type != UNIT_SLICE)
- return -EINVAL;
-
- if (mode != UNIT_CHECK) {
- unit_ref_set(&u->slice, slice);
- unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s);
- }
- }
-
- return 1;
- } else if (STR_IN_SET(name,
- "Requires", "RequiresOverridable",
- "Requisite", "RequisiteOverridable",
- "Wants",
- "BindsTo",
- "Conflicts",
- "Before", "After",
- "OnFailure",
- "PropagatesReloadTo", "ReloadPropagatedFrom",
- "PartOf")) {
-
- UnitDependency d;
- const char *other;
-
- d = unit_dependency_from_string(name);
- if (d < 0)
- return -EINVAL;
-
- r = sd_bus_message_enter_container(message, 'a', "s");
- if (r < 0)
- return r;
-
- while ((r = sd_bus_message_read(message, "s", &other)) > 0) {
- if (!unit_name_is_valid(other, TEMPLATE_INVALID))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other);
-
- if (mode != UNIT_CHECK) {
- _cleanup_free_ char *label = NULL;
-
- r = unit_add_dependency_by_name(u, d, other, NULL, true);
- if (r < 0)
- return r;
-
- label = strjoin(name, "-", other, NULL);
- if (!label)
- return -ENOMEM;
-
- unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s\n", name, other);
- }
-
- }
- if (r < 0)
- return r;
-
- r = sd_bus_message_exit_container(message);
- if (r < 0)
- return r;
-
- return 1;
- }
-
- return 0;
-}
-
-int bus_unit_set_properties(
- Unit *u,
- sd_bus_message *message,
- UnitSetPropertiesMode mode,
- bool commit,
- sd_bus_error *error) {
-
- bool for_real = false;
- unsigned n = 0;
- int r;
-
- assert(u);
- assert(message);
-
- /* We iterate through the array twice. First run we just check
- * if all passed data is valid, second run actually applies
- * it. This is to implement transaction-like behaviour without
- * actually providing full transactions. */
-
- r = sd_bus_message_enter_container(message, 'a', "(sv)");
- if (r < 0)
- return r;
-
- for (;;) {
- const char *name;
-
- r = sd_bus_message_enter_container(message, 'r', "sv");
- if (r < 0)
- return r;
- if (r == 0) {
- if (for_real || mode == UNIT_CHECK)
- break;
-
- /* Reached EOF. Let's try again, and this time for realz... */
- r = sd_bus_message_rewind(message, false);
- if (r < 0)
- return r;
-
- for_real = true;
- continue;
- }
-
- r = sd_bus_message_read(message, "s", &name);
- if (r < 0)
- return r;
-
- if (!UNIT_VTABLE(u)->bus_set_property)
- return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties.");
-
- r = sd_bus_message_enter_container(message, 'v', NULL);
- if (r < 0)
- return r;
-
- r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
- if (r == 0 && u->transient && u->load_state == UNIT_STUB)
- r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error);
- if (r < 0)
- return r;
- if (r == 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name);
-
- r = sd_bus_message_exit_container(message);
- if (r < 0)
- return r;
-
- r = sd_bus_message_exit_container(message);
- if (r < 0)
- return r;
-
- n += for_real;
- }
-
- r = sd_bus_message_exit_container(message);
- if (r < 0)
- return r;
-
- if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties)
- UNIT_VTABLE(u)->bus_commit_properties(u);
-
- return n;
-}
diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h
deleted file mode 100644
index 57a5e1974..000000000
--- a/src/core/dbus-unit.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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"
-
-extern const sd_bus_vtable bus_unit_vtable[];
-extern const sd_bus_vtable bus_unit_cgroup_vtable[];
-
-void bus_unit_send_change_signal(Unit *u);
-void bus_unit_send_removed_signal(Unit *u);
-
-int bus_unit_method_start_generic(sd_bus *bus, sd_bus_message *message, Unit *u, JobType job_type, bool reload_if_possible, sd_bus_error *error);
-int bus_unit_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
-int bus_unit_method_reset_failed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
-
-int bus_unit_queue_job(sd_bus *bus, sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible, sd_bus_error *error);
-int bus_unit_set_properties(Unit *u, sd_bus_message *message, UnitSetPropertiesMode mode, bool commit, sd_bus_error *error);
-int bus_unit_method_set_properties(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error);
diff --git a/src/core/dbus.c b/src/core/dbus.c
deleted file mode 100644
index ae259c37d..000000000
--- a/src/core/dbus.c
+++ /dev/null
@@ -1,1214 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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/epoll.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include "sd-bus.h"
-#include "log.h"
-#include "strv.h"
-#include "mkdir.h"
-#include "missing.h"
-#include "dbus-unit.h"
-#include "dbus-job.h"
-#include "dbus-manager.h"
-#include "dbus-execute.h"
-#include "dbus-kill.h"
-#include "dbus-cgroup.h"
-#include "special.h"
-#include "dbus.h"
-#include "bus-util.h"
-#include "bus-error.h"
-#include "bus-common-errors.h"
-#include "strxcpyx.h"
-#include "bus-internal.h"
-#include "selinux-access.h"
-
-#define CONNECTIONS_MAX 4096
-
-static void destroy_bus(Manager *m, sd_bus **bus);
-
-int bus_send_queued_message(Manager *m) {
- int r;
-
- assert(m);
-
- if (!m->queued_message)
- return 0;
-
- assert(m->queued_message_bus);
-
- /* If we cannot get rid of this message we won't dispatch any
- * D-Bus messages, so that we won't end up wanting to queue
- * another message. */
-
- r = sd_bus_send(m->queued_message_bus, m->queued_message, NULL);
- if (r < 0)
- log_warning_errno(r, "Failed to send queued message: %m");
-
- m->queued_message = sd_bus_message_unref(m->queued_message);
- m->queued_message_bus = sd_bus_unref(m->queued_message_bus);
-
- return 0;
-}
-
-static int signal_agent_released(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- const char *cgroup;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = sd_bus_message_read(message, "s", &cgroup);
- if (r < 0) {
- bus_log_parse_error(r);
- return 0;
- }
-
- manager_notify_cgroup_empty(m, cgroup);
-
- /* only forward to system bus if running as system instance */
- if (m->running_as != SYSTEMD_SYSTEM || !m->system_bus)
- return 0;
-
- r = sd_bus_message_rewind(message, 1);
- if (r < 0)
- goto exit;
-
- r = sd_bus_send(m->system_bus, message, NULL);
-
-exit:
- if (r < 0)
- log_warning_errno(r, "Failed to forward Released message: %m");
- return 0;
-}
-
-static int signal_disconnected(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
-
- assert(bus);
- assert(message);
- assert(m);
-
- if (bus == m->api_bus)
- destroy_bus(m, &m->api_bus);
- if (bus == m->system_bus)
- destroy_bus(m, &m->system_bus);
- if (set_remove(m->private_buses, bus)) {
- log_debug("Got disconnect on private connection.");
- destroy_bus(m, &bus);
- }
-
- return 0;
-}
-
-static int signal_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- const char *name, *old_owner, *new_owner;
- Manager *m = userdata;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = sd_bus_message_read(message, "sss", &name, &old_owner, &new_owner);
- if (r < 0) {
- bus_log_parse_error(r);
- return 0;
- }
-
- manager_dispatch_bus_name_owner_changed(
- m, name,
- isempty(old_owner) ? NULL : old_owner,
- isempty(new_owner) ? NULL : new_owner);
-
- return 0;
-}
-
-static int signal_activation_request(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
- Manager *m = userdata;
- const char *name;
- Unit *u;
- int r;
-
- assert(bus);
- assert(message);
- assert(m);
-
- r = sd_bus_message_read(message, "s", &name);
- if (r < 0) {
- bus_log_parse_error(r);
- return 0;
- }
-
- if (manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SERVICE) ||
- manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SOCKET)) {
- r = sd_bus_error_setf(&error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is shutting down.");
- goto failed;
- }
-
- r = manager_load_unit(m, name, NULL, &error, &u);
- if (r < 0)
- goto failed;
-
- if (u->refuse_manual_start) {
- r = sd_bus_error_setf(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, %s may be requested by dependency only.", u->id);
- goto failed;
- }
-
- r = manager_add_job(m, JOB_START, u, JOB_REPLACE, true, &error, NULL);
- if (r < 0)
- goto failed;
-
- /* Successfully queued, that's it for us */
- return 0;
-
-failed:
- if (!sd_bus_error_is_set(&error))
- sd_bus_error_set_errno(&error, r);
-
- log_debug("D-Bus activation failed for %s: %s", name, bus_error_message(&error, r));
-
- r = sd_bus_message_new_signal(bus, &reply, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure");
- if (r < 0) {
- bus_log_create_error(r);
- return 0;
- }
-
- r = sd_bus_message_append(reply, "sss", name, error.name, error.message);
- if (r < 0) {
- bus_log_create_error(r);
- return 0;
- }
-
- r = sd_bus_send_to(bus, reply, "org.freedesktop.DBus", NULL);
- if (r < 0)
- return log_error_errno(r, "Failed to respond with to bus activation request: %m");
-
- return 0;
-}
-
-#ifdef HAVE_SELINUX
-static int mac_selinux_filter(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- const char *verb, *path;
- Unit *u = NULL;
- Job *j;
- int r;
-
- assert(bus);
- assert(message);
-
- /* Our own method calls are all protected individually with
- * selinux checks, but the built-in interfaces need to be
- * protected too. */
-
- if (sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Set"))
- verb = "reload";
- else if (sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", NULL) ||
- sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Properties", NULL) ||
- sd_bus_message_is_method_call(message, "org.freedesktop.DBus.ObjectManager", NULL) ||
- sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Peer", NULL))
- verb = "status";
- else
- return 0;
-
- 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;
-
- return 0;
- }
-
- if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) {
- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
- pid_t pid;
-
- r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
- if (r < 0)
- return 0;
-
- r = sd_bus_creds_get_pid(creds, &pid);
- if (r < 0)
- return 0;
-
- u = manager_get_unit_by_pid(m, pid);
- } else {
- r = manager_get_job_from_dbus_path(m, path, &j);
- if (r >= 0)
- u = j->unit;
- else
- manager_load_unit_from_dbus_path(m, path, NULL, &u);
- }
-
- if (!u)
- return 0;
-
- r = mac_selinux_unit_access_check(u, message, verb, error);
- if (r < 0)
- return r;
-
- return 0;
-}
-#endif
-
-static int bus_job_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
- Manager *m = userdata;
- Job *j;
- int r;
-
- assert(bus);
- assert(path);
- assert(interface);
- assert(found);
- assert(m);
-
- r = manager_get_job_from_dbus_path(m, path, &j);
- if (r < 0)
- return 0;
-
- *found = j;
- return 1;
-}
-
-static int find_unit(Manager *m, sd_bus *bus, const char *path, Unit **unit, sd_bus_error *error) {
- Unit *u;
- int r;
-
- assert(m);
- assert(bus);
- assert(path);
-
- if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) {
- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
- sd_bus_message *message;
- pid_t pid;
-
- message = sd_bus_get_current_message(bus);
- if (!message)
- return 0;
-
- r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
- if (r < 0)
- return r;
-
- r = sd_bus_creds_get_pid(creds, &pid);
- if (r < 0)
- return r;
-
- u = manager_get_unit_by_pid(m, pid);
- } else {
- r = manager_load_unit_from_dbus_path(m, path, error, &u);
- if (r < 0)
- return 0;
- }
-
- if (!u)
- return 0;
-
- *unit = u;
- return 1;
-}
-
-static int bus_unit_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
- Manager *m = userdata;
-
- assert(bus);
- assert(path);
- assert(interface);
- assert(found);
- assert(m);
-
- return find_unit(m, bus, path, (Unit**) found, error);
-}
-
-static int bus_unit_interface_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
- Manager *m = userdata;
- Unit *u;
- int r;
-
- assert(bus);
- assert(path);
- assert(interface);
- assert(found);
- assert(m);
-
- r = find_unit(m, bus, path, &u, error);
- if (r <= 0)
- return r;
-
- if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
- return 0;
-
- *found = u;
- return 1;
-}
-
-static int bus_unit_cgroup_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
- Manager *m = userdata;
- Unit *u;
- int r;
-
- assert(bus);
- assert(path);
- assert(interface);
- assert(found);
- assert(m);
-
- r = find_unit(m, bus, path, &u, error);
- if (r <= 0)
- return r;
-
- if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
- return 0;
-
- if (!unit_get_cgroup_context(u))
- return 0;
-
- *found = u;
- return 1;
-}
-
-static int bus_cgroup_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
- Manager *m = userdata;
- CGroupContext *c;
- Unit *u;
- int r;
-
- assert(bus);
- assert(path);
- assert(interface);
- assert(found);
- assert(m);
-
- r = find_unit(m, bus, path, &u, error);
- if (r <= 0)
- return r;
-
- if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
- return 0;
-
- c = unit_get_cgroup_context(u);
- if (!c)
- return 0;
-
- *found = c;
- return 1;
-}
-
-static int bus_exec_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
- Manager *m = userdata;
- ExecContext *c;
- Unit *u;
- int r;
-
- assert(bus);
- assert(path);
- assert(interface);
- assert(found);
- assert(m);
-
- r = find_unit(m, bus, path, &u, error);
- if (r <= 0)
- return r;
-
- if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
- return 0;
-
- c = unit_get_exec_context(u);
- if (!c)
- return 0;
-
- *found = c;
- return 1;
-}
-
-static int bus_kill_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
- Manager *m = userdata;
- KillContext *c;
- Unit *u;
- int r;
-
- assert(bus);
- assert(path);
- assert(interface);
- assert(found);
- assert(m);
-
- r = find_unit(m, bus, path, &u, error);
- if (r <= 0)
- return r;
-
- if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
- return 0;
-
- c = unit_get_kill_context(u);
- if (!c)
- return 0;
-
- *found = c;
- return 1;
-}
-
-static int bus_job_enumerate(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
- _cleanup_free_ char **l = NULL;
- Manager *m = userdata;
- unsigned k = 0;
- Iterator i;
- Job *j;
-
- l = new0(char*, hashmap_size(m->jobs)+1);
- if (!l)
- return -ENOMEM;
-
- HASHMAP_FOREACH(j, m->jobs, i) {
- l[k] = job_dbus_path(j);
- if (!l[k])
- return -ENOMEM;
-
- k++;
- }
-
- assert(hashmap_size(m->jobs) == k);
-
- *nodes = l;
- l = NULL;
-
- return k;
-}
-
-static int bus_unit_enumerate(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
- _cleanup_free_ char **l = NULL;
- Manager *m = userdata;
- unsigned k = 0;
- Iterator i;
- Unit *u;
-
- l = new0(char*, hashmap_size(m->units)+1);
- if (!l)
- return -ENOMEM;
-
- HASHMAP_FOREACH(u, m->units, i) {
- l[k] = unit_dbus_path(u);
- if (!l[k])
- return -ENOMEM;
-
- k++;
- }
-
- *nodes = l;
- l = NULL;
-
- return k;
-}
-
-static int bus_setup_api_vtables(Manager *m, sd_bus *bus) {
- UnitType t;
- int r;
-
- assert(m);
- assert(bus);
-
-#ifdef HAVE_SELINUX
- r = sd_bus_add_filter(bus, NULL, mac_selinux_filter, m);
- if (r < 0)
- return log_error_errno(r, "Failed to add SELinux access filter: %m");
-#endif
-
- r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", bus_manager_vtable, m);
- if (r < 0)
- return log_error_errno(r, "Failed to register Manager vtable: %m");
-
- r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/job", "org.freedesktop.systemd1.Job", bus_job_vtable, bus_job_find, m);
- if (r < 0)
- return log_error_errno(r, "Failed to register Job vtable: %m");
-
- r = sd_bus_add_node_enumerator(bus, NULL, "/org/freedesktop/systemd1/job", bus_job_enumerate, m);
- if (r < 0)
- return log_error_errno(r, "Failed to add job enumerator: %m");
-
- r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", "org.freedesktop.systemd1.Unit", bus_unit_vtable, bus_unit_find, m);
- if (r < 0)
- return log_error_errno(r, "Failed to register Unit vtable: %m");
-
- r = sd_bus_add_node_enumerator(bus, NULL, "/org/freedesktop/systemd1/unit", bus_unit_enumerate, m);
- if (r < 0)
- return log_error_errno(r, "Failed to add job enumerator: %m");
-
- for (t = 0; t < _UNIT_TYPE_MAX; t++) {
- r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, unit_vtable[t]->bus_vtable, bus_unit_interface_find, m);
- if (r < 0)
- return log_error_errno(r, "Failed to register type specific vtable for %s: %m", unit_vtable[t]->bus_interface);
-
- if (unit_vtable[t]->cgroup_context_offset > 0) {
- r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_unit_cgroup_vtable, bus_unit_cgroup_find, m);
- if (r < 0)
- return log_error_errno(r, "Failed to register control group unit vtable for %s: %m", unit_vtable[t]->bus_interface);
-
- r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_cgroup_vtable, bus_cgroup_context_find, m);
- if (r < 0)
- return log_error_errno(r, "Failed to register control group vtable for %s: %m", unit_vtable[t]->bus_interface);
- }
-
- if (unit_vtable[t]->exec_context_offset > 0) {
- r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_exec_vtable, bus_exec_context_find, m);
- if (r < 0)
- return log_error_errno(r, "Failed to register execute vtable for %s: %m", unit_vtable[t]->bus_interface);
- }
-
- if (unit_vtable[t]->kill_context_offset > 0) {
- r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_kill_vtable, bus_kill_context_find, m);
- if (r < 0)
- return log_error_errno(r, "Failed to register kill vtable for %s: %m", unit_vtable[t]->bus_interface);
- }
- }
-
- return 0;
-}
-
-static int bus_setup_disconnected_match(Manager *m, sd_bus *bus) {
- int r;
-
- assert(m);
- assert(bus);
-
- r = sd_bus_add_match(
- bus,
- NULL,
- "sender='org.freedesktop.DBus.Local',"
- "type='signal',"
- "path='/org/freedesktop/DBus/Local',"
- "interface='org.freedesktop.DBus.Local',"
- "member='Disconnected'",
- signal_disconnected, m);
-
- if (r < 0)
- return log_error_errno(r, "Failed to register match for Disconnected message: %m");
-
- return 0;
-}
-
-static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
- _cleanup_bus_unref_ sd_bus *bus = NULL;
- _cleanup_close_ int nfd = -1;
- Manager *m = userdata;
- sd_id128_t id;
- int r;
-
- assert(s);
- assert(m);
-
- nfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
- if (nfd < 0) {
- log_warning_errno(errno, "Failed to accept private connection, ignoring: %m");
- return 0;
- }
-
- if (set_size(m->private_buses) >= CONNECTIONS_MAX) {
- log_warning("Too many concurrent connections, refusing");
- return 0;
- }
-
- r = set_ensure_allocated(&m->private_buses, NULL);
- if (r < 0) {
- log_oom();
- return 0;
- }
-
- r = sd_bus_new(&bus);
- if (r < 0) {
- log_warning_errno(r, "Failed to allocate new private connection bus: %m");
- return 0;
- }
-
- r = sd_bus_set_fd(bus, nfd, nfd);
- if (r < 0) {
- log_warning_errno(r, "Failed to set fd on new connection bus: %m");
- return 0;
- }
-
- nfd = -1;
-
- r = bus_check_peercred(bus);
- if (r < 0) {
- log_warning_errno(r, "Incoming private connection from unprivileged client, refusing: %m");
- return 0;
- }
-
- assert_se(sd_id128_randomize(&id) >= 0);
-
- r = sd_bus_set_server(bus, 1, id);
- if (r < 0) {
- log_warning_errno(r, "Failed to enable server support for new connection bus: %m");
- return 0;
- }
-
- r = sd_bus_start(bus);
- if (r < 0) {
- log_warning_errno(r, "Failed to start new connection bus: %m");
- return 0;
- }
-
- r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL);
- if (r < 0) {
- log_warning_errno(r, "Failed to attach new connection bus to event loop: %m");
- return 0;
- }
-
- if (m->running_as == SYSTEMD_SYSTEM) {
- /* When we run as system instance we get the Released
- * signal via a direct connection */
-
- r = sd_bus_add_match(
- bus,
- NULL,
- "type='signal',"
- "interface='org.freedesktop.systemd1.Agent',"
- "member='Released',"
- "path='/org/freedesktop/systemd1/agent'",
- signal_agent_released, m);
-
- if (r < 0) {
- log_warning_errno(r, "Failed to register Released match on new connection bus: %m");
- return 0;
- }
- }
-
- r = bus_setup_disconnected_match(m, bus);
- if (r < 0)
- return 0;
-
- r = bus_setup_api_vtables(m, bus);
- if (r < 0) {
- log_warning_errno(r, "Failed to set up API vtables on new connection bus: %m");
- return 0;
- }
-
- r = set_put(m->private_buses, bus);
- if (r < 0) {
- log_warning_errno(r, "Failed to add new conenction bus to set: %m");
- return 0;
- }
-
- bus = NULL;
-
- log_debug("Accepted new private connection.");
-
- return 0;
-}
-
-static int bus_list_names(Manager *m, sd_bus *bus) {
- _cleanup_strv_free_ char **names = NULL;
- char **i;
- int r;
-
- assert(m);
- assert(bus);
-
- r = sd_bus_list_names(bus, &names, NULL);
- if (r < 0)
- return log_error_errno(r, "Failed to get initial list of names: %m");
-
- /* This is a bit hacky, we say the owner of the name is the
- * name itself, because we don't want the extra traffic to
- * figure out the real owner. */
- STRV_FOREACH(i, names)
- manager_dispatch_bus_name_owner_changed(m, *i, NULL, *i);
-
- return 0;
-}
-
-static int bus_setup_api(Manager *m, sd_bus *bus) {
- int r;
-
- assert(m);
- assert(bus);
-
- /* Let's make sure we have enough credential bits so that we can make security and selinux decisions */
- r = sd_bus_negotiate_creds(bus, 1,
- SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|
- SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS|
- SD_BUS_CREDS_SELINUX_CONTEXT);
- if (r < 0)
- log_warning_errno(r, "Failed to enable credential passing, ignoring: %m");
-
- r = bus_setup_api_vtables(m, bus);
- if (r < 0)
- return r;
-
- r = sd_bus_add_match(
- bus,
- NULL,
- "type='signal',"
- "sender='org.freedesktop.DBus',"
- "path='/org/freedesktop/DBus',"
- "interface='org.freedesktop.DBus',"
- "member='NameOwnerChanged'",
- signal_name_owner_changed, m);
- if (r < 0)
- log_warning_errno(r, "Failed to subscribe to NameOwnerChanged signal: %m");
-
- r = sd_bus_add_match(
- bus,
- NULL,
- "type='signal',"
- "sender='org.freedesktop.DBus',"
- "path='/org/freedesktop/DBus',"
- "interface='org.freedesktop.systemd1.Activator',"
- "member='ActivationRequest'",
- signal_activation_request, m);
- if (r < 0)
- log_warning_errno(r, "Failed to subscribe to activation signal: %m");
-
- /* Allow replacing of our name, to ease implementation of
- * reexecution, where we keep the old connection open until
- * after the new connection is set up and the name installed
- * to allow clients to synchronously wait for reexecution to
- * finish */
- r = sd_bus_request_name(bus,"org.freedesktop.systemd1", SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_ALLOW_REPLACEMENT);
- if (r < 0)
- return log_error_errno(r, "Failed to register name: %m");
-
- bus_list_names(m, bus);
-
- log_debug("Successfully connected to API bus.");
- return 0;
-}
-
-static int bus_init_api(Manager *m) {
- _cleanup_bus_unref_ sd_bus *bus = NULL;
- int r;
-
- if (m->api_bus)
- return 0;
-
- /* The API and system bus is the same if we are running in system mode */
- if (m->running_as == SYSTEMD_SYSTEM && m->system_bus)
- bus = sd_bus_ref(m->system_bus);
- else {
- if (m->running_as == SYSTEMD_SYSTEM)
- r = sd_bus_open_system(&bus);
- else
- r = sd_bus_open_user(&bus);
-
- if (r < 0) {
- log_debug("Failed to connect to API bus, retrying later...");
- return 0;
- }
-
- r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL);
- if (r < 0) {
- log_error_errno(r, "Failed to attach API bus to event loop: %m");
- return 0;
- }
-
- r = bus_setup_disconnected_match(m, bus);
- if (r < 0)
- return 0;
- }
-
- r = bus_setup_api(m, bus);
- if (r < 0) {
- log_error_errno(r, "Failed to set up API bus: %m");
- return 0;
- }
-
- m->api_bus = bus;
- bus = NULL;
-
- return 0;
-}
-
-static int bus_setup_system(Manager *m, sd_bus *bus) {
- int r;
-
- assert(m);
- assert(bus);
-
- /* On kdbus or if we are a user instance we get the Released message via the system bus */
- if (m->running_as == SYSTEMD_USER || m->kdbus_fd >= 0) {
- r = sd_bus_add_match(
- bus,
- NULL,
- "type='signal',"
- "interface='org.freedesktop.systemd1.Agent',"
- "member='Released',"
- "path='/org/freedesktop/systemd1/agent'",
- signal_agent_released, m);
- if (r < 0)
- log_warning_errno(r, "Failed to register Released match on system bus: %m");
- }
-
- log_debug("Successfully connected to system bus.");
- return 0;
-}
-
-static int bus_init_system(Manager *m) {
- _cleanup_bus_unref_ sd_bus *bus = NULL;
- int r;
-
- if (m->system_bus)
- return 0;
-
- /* The API and system bus is the same if we are running in system mode */
- if (m->running_as == SYSTEMD_SYSTEM && m->api_bus) {
- m->system_bus = sd_bus_ref(m->api_bus);
- return 0;
- }
-
- r = sd_bus_open_system(&bus);
- if (r < 0) {
- log_debug("Failed to connect to system bus, retrying later...");
- return 0;
- }
-
- r = bus_setup_disconnected_match(m, bus);
- if (r < 0)
- return 0;
-
- r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL);
- if (r < 0) {
- log_error_errno(r, "Failed to attach system bus to event loop: %m");
- return 0;
- }
-
- r = bus_setup_system(m, bus);
- if (r < 0) {
- log_error_errno(r, "Failed to set up system bus: %m");
- return 0;
- }
-
- m->system_bus = bus;
- bus = NULL;
-
- return 0;
-}
-
-static int bus_init_private(Manager *m) {
- _cleanup_close_ int fd = -1;
- union sockaddr_union sa = {
- .un.sun_family = AF_UNIX
- };
- sd_event_source *s;
- socklen_t salen;
- int r;
-
- assert(m);
-
- if (m->private_listen_fd >= 0)
- return 0;
-
- /* We don't need the private socket if we have kdbus */
- if (m->kdbus_fd >= 0)
- return 0;
-
- if (m->running_as == SYSTEMD_SYSTEM) {
-
- /* We want the private bus only when running as init */
- if (getpid() != 1)
- return 0;
-
- strcpy(sa.un.sun_path, "/run/systemd/private");
- salen = offsetof(union sockaddr_union, un.sun_path) + strlen("/run/systemd/private");
- } else {
- size_t left = sizeof(sa.un.sun_path);
- char *p = sa.un.sun_path;
- const char *e;
-
- e = secure_getenv("XDG_RUNTIME_DIR");
- if (!e) {
- log_error("Failed to determine XDG_RUNTIME_DIR");
- return -EHOSTDOWN;
- }
-
- left = strpcpy(&p, left, e);
- left = strpcpy(&p, left, "/systemd/private");
-
- salen = sizeof(sa.un) - left;
- }
-
- (void) mkdir_parents_label(sa.un.sun_path, 0755);
- (void) unlink(sa.un.sun_path);
-
- fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
- if (fd < 0)
- return log_error_errno(errno, "Failed to allocate private socket: %m");
-
- r = bind(fd, &sa.sa, salen);
- if (r < 0)
- return log_error_errno(errno, "Failed to bind private socket: %m");
-
- r = listen(fd, SOMAXCONN);
- if (r < 0)
- return log_error_errno(errno, "Failed to make private socket listening: %m");
-
- r = sd_event_add_io(m->event, &s, fd, EPOLLIN, bus_on_connection, m);
- if (r < 0)
- return log_error_errno(r, "Failed to allocate event source: %m");
-
- m->private_listen_fd = fd;
- m->private_listen_event_source = s;
- fd = -1;
-
- log_debug("Successfully created private D-Bus server.");
-
- return 0;
-}
-
-int bus_init(Manager *m, bool try_bus_connect) {
- int r;
-
- if (try_bus_connect) {
- r = bus_init_system(m);
- if (r < 0)
- return r;
-
- r = bus_init_api(m);
- if (r < 0)
- return r;
- }
-
- r = bus_init_private(m);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-static void destroy_bus(Manager *m, sd_bus **bus) {
- Iterator i;
- Job *j;
-
- assert(m);
- assert(bus);
-
- if (!*bus)
- return;
-
- /* Get rid of tracked clients on this bus */
- if (m->subscribed && sd_bus_track_get_bus(m->subscribed) == *bus)
- m->subscribed = sd_bus_track_unref(m->subscribed);
-
- HASHMAP_FOREACH(j, m->jobs, i)
- if (j->clients && sd_bus_track_get_bus(j->clients) == *bus)
- j->clients = sd_bus_track_unref(j->clients);
-
- /* Get rid of queued message on this bus */
- if (m->queued_message_bus == *bus) {
- m->queued_message_bus = sd_bus_unref(m->queued_message_bus);
-
- if (m->queued_message)
- m->queued_message = sd_bus_message_unref(m->queued_message);
- }
-
- /* Possibly flush unwritten data, but only if we are
- * unprivileged, since we don't want to sync here */
- if (m->running_as != SYSTEMD_SYSTEM)
- sd_bus_flush(*bus);
-
- /* And destroy the object */
- sd_bus_close(*bus);
- *bus = sd_bus_unref(*bus);
-}
-
-void bus_done(Manager *m) {
- sd_bus *b;
-
- assert(m);
-
- if (m->api_bus)
- destroy_bus(m, &m->api_bus);
- if (m->system_bus)
- destroy_bus(m, &m->system_bus);
- while ((b = set_steal_first(m->private_buses)))
- destroy_bus(m, &b);
-
- set_free(m->private_buses);
- m->private_buses = NULL;
-
- m->subscribed = sd_bus_track_unref(m->subscribed);
- strv_free(m->deserialized_subscribed);
- m->deserialized_subscribed = NULL;
-
- if (m->private_listen_event_source)
- m->private_listen_event_source = sd_event_source_unref(m->private_listen_event_source);
-
- m->private_listen_fd = safe_close(m->private_listen_fd);
-
- bus_verify_polkit_async_registry_free(m->polkit_registry);
-}
-
-int bus_fdset_add_all(Manager *m, FDSet *fds) {
- Iterator i;
- sd_bus *b;
- int fd;
-
- assert(m);
- assert(fds);
-
- /* When we are about to reexecute we add all D-Bus fds to the
- * set to pass over to the newly executed systemd. They won't
- * be used there however, except thatt they are closed at the
- * very end of deserialization, those making it possible for
- * clients to synchronously wait for systemd to reexec by
- * simply waiting for disconnection */
-
- if (m->api_bus) {
- fd = sd_bus_get_fd(m->api_bus);
- if (fd >= 0) {
- fd = fdset_put_dup(fds, fd);
- if (fd < 0)
- return fd;
- }
- }
-
- SET_FOREACH(b, m->private_buses, i) {
- fd = sd_bus_get_fd(b);
- if (fd >= 0) {
- fd = fdset_put_dup(fds, fd);
- if (fd < 0)
- return fd;
- }
- }
-
- /* We don't offer any APIs on the system bus (well, unless it
- * is the same as the API bus) hence we don't bother with it
- * here */
-
- return 0;
-}
-
-int bus_foreach_bus(
- Manager *m,
- sd_bus_track *subscribed2,
- int (*send_message)(sd_bus *bus, void *userdata),
- void *userdata) {
-
- Iterator i;
- sd_bus *b;
- int r, ret = 0;
-
- /* Send to all direct busses, unconditionally */
- SET_FOREACH(b, m->private_buses, i) {
- r = send_message(b, userdata);
- if (r < 0)
- ret = r;
- }
-
- /* Send to API bus, but only if somebody is subscribed */
- if (sd_bus_track_count(m->subscribed) > 0 ||
- sd_bus_track_count(subscribed2) > 0) {
- r = send_message(m->api_bus, userdata);
- if (r < 0)
- ret = r;
- }
-
- return ret;
-}
-
-void bus_track_serialize(sd_bus_track *t, FILE *f) {
- const char *n;
-
- assert(f);
-
- for (n = sd_bus_track_first(t); n; n = sd_bus_track_next(t))
- fprintf(f, "subscribed=%s\n", n);
-}
-
-int bus_track_deserialize_item(char ***l, const char *line) {
- const char *e;
- int r;
-
- assert(l);
- assert(line);
-
- e = startswith(line, "subscribed=");
- if (!e)
- return 0;
-
- r = strv_extend(l, e);
- if (r < 0)
- return r;
-
- return 1;
-}
-
-int bus_track_coldplug(Manager *m, sd_bus_track **t, char ***l) {
- int r = 0;
-
- assert(m);
- assert(t);
- assert(l);
-
- if (!strv_isempty(*l) && m->api_bus) {
- char **i;
-
- if (!*t) {
- r = sd_bus_track_new(m->api_bus, t, NULL, NULL);
- if (r < 0)
- return r;
- }
-
- r = 0;
- STRV_FOREACH(i, *l) {
- int k;
-
- k = sd_bus_track_add_name(*t, *i);
- if (k < 0)
- r = k;
- }
- }
-
- strv_free(*l);
- *l = NULL;
-
- return r;
-}
-
-int bus_verify_manage_units_async(Manager *m, sd_bus_message *call, sd_bus_error *error) {
- return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.manage-units", false, UID_INVALID, &m->polkit_registry, error);
-}
-
-/* Same as bus_verify_manage_unit_async(), but checks for CAP_KILL instead of CAP_SYS_ADMIN */
-int bus_verify_manage_units_async_for_kill(Manager *m, sd_bus_message *call, sd_bus_error *error) {
- return bus_verify_polkit_async(call, CAP_KILL, "org.freedesktop.systemd1.manage-units", false, UID_INVALID, &m->polkit_registry, error);
-}
-
-int bus_verify_manage_unit_files_async(Manager *m, sd_bus_message *call, sd_bus_error *error) {
- return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.manage-unit-files", false, UID_INVALID, &m->polkit_registry, error);
-}
-
-int bus_verify_reload_daemon_async(Manager *m, sd_bus_message *call, sd_bus_error *error) {
- return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.reload-daemon", false, UID_INVALID, &m->polkit_registry, error);
-}
-
-int bus_verify_set_environment_async(Manager *m, sd_bus_message *call, sd_bus_error *error) {
- return bus_verify_polkit_async(call, CAP_SYS_ADMIN, "org.freedesktop.systemd1.set-environment", false, UID_INVALID, &m->polkit_registry, error);
-}
diff --git a/src/core/dbus.h b/src/core/dbus.h
deleted file mode 100644
index 483272206..000000000
--- a/src/core/dbus.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 "manager.h"
-
-int bus_send_queued_message(Manager *m);
-
-int bus_init(Manager *m, bool try_bus_connect);
-void bus_done(Manager *m);
-
-int bus_fdset_add_all(Manager *m, FDSet *fds);
-
-void bus_track_serialize(sd_bus_track *t, FILE *f);
-int bus_track_deserialize_item(char ***l, const char *line);
-int bus_track_coldplug(Manager *m, sd_bus_track **t, char ***l);
-
-int bus_foreach_bus(Manager *m, sd_bus_track *subscribed2, int (*send_message)(sd_bus *bus, void *userdata), void *userdata);
-
-int bus_verify_manage_units_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
-int bus_verify_manage_units_async_for_kill(Manager *m, sd_bus_message *call, sd_bus_error *error);
-int bus_verify_manage_unit_files_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
-int bus_verify_reload_daemon_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
-int bus_verify_set_environment_async(Manager *m, sd_bus_message *call, sd_bus_error *error);
diff --git a/src/core/device.c b/src/core/device.c
deleted file mode 100644
index b5d9d827e..000000000
--- a/src/core/device.c
+++ /dev/null
@@ -1,813 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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>
-#include <libudev.h>
-
-#include "log.h"
-#include "unit-name.h"
-#include "dbus-device.h"
-#include "path-util.h"
-#include "udev-util.h"
-#include "unit.h"
-#include "swap.h"
-#include "device.h"
-
-static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
- [DEVICE_DEAD] = UNIT_INACTIVE,
- [DEVICE_TENTATIVE] = UNIT_ACTIVATING,
- [DEVICE_PLUGGED] = UNIT_ACTIVE,
-};
-
-static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
-
-static void device_unset_sysfs(Device *d) {
- Hashmap *devices;
- Device *first;
-
- assert(d);
-
- if (!d->sysfs)
- return;
-
- /* Remove this unit from the chain of devices which share the
- * same sysfs path. */
- devices = UNIT(d)->manager->devices_by_sysfs;
- first = hashmap_get(devices, d->sysfs);
- LIST_REMOVE(same_sysfs, first, d);
-
- if (first)
- hashmap_remove_and_replace(devices, d->sysfs, first->sysfs, first);
- else
- hashmap_remove(devices, d->sysfs);
-
- free(d->sysfs);
- d->sysfs = NULL;
-}
-
-static int device_set_sysfs(Device *d, const char *sysfs) {
- Device *first;
- char *copy;
- int r;
-
- assert(d);
-
- if (streq_ptr(d->sysfs, sysfs))
- return 0;
-
- r = hashmap_ensure_allocated(&UNIT(d)->manager->devices_by_sysfs, &string_hash_ops);
- if (r < 0)
- return r;
-
- copy = strdup(sysfs);
- if (!copy)
- return -ENOMEM;
-
- device_unset_sysfs(d);
-
- first = hashmap_get(UNIT(d)->manager->devices_by_sysfs, sysfs);
- LIST_PREPEND(same_sysfs, first, d);
-
- 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;
-
- return 0;
-}
-
-static void device_init(Unit *u) {
- Device *d = DEVICE(u);
-
- assert(d);
- assert(UNIT(d)->load_state == UNIT_STUB);
-
- /* In contrast to all other unit types we timeout jobs waiting
- * for devices by default. This is because they otherwise wait
- * indefinitely for plugged in devices, something which cannot
- * happen for the other units since their operations time out
- * anyway. */
- u->job_timeout = u->manager->default_timeout_start_usec;
-
- u->ignore_on_isolate = true;
- u->ignore_on_snapshot = true;
-}
-
-static void device_done(Unit *u) {
- Device *d = DEVICE(u);
-
- assert(d);
-
- device_unset_sysfs(d);
-}
-
-static void device_set_state(Device *d, DeviceState state) {
- DeviceState old_state;
- assert(d);
-
- old_state = d->state;
- d->state = state;
-
- if (state != old_state)
- log_unit_debug(UNIT(d)->id,
- "%s changed %s -> %s", UNIT(d)->id,
- 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);
-}
-
-static int device_coldplug(Unit *u, Hashmap *deferred_work) {
- Device *d = DEVICE(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)
- /* If a device is found in /proc/self/mountinfo or
- * /proc/swaps, it's "tentatively" around. */
- device_set_state(d, DEVICE_TENTATIVE);
-
- return 0;
-}
-
-static void device_dump(Unit *u, FILE *f, const char *prefix) {
- Device *d = DEVICE(u);
-
- assert(d);
-
- fprintf(f,
- "%sDevice State: %s\n"
- "%sSysfs Path: %s\n",
- prefix, device_state_to_string(d->state),
- prefix, strna(d->sysfs));
-}
-
-_pure_ static UnitActiveState device_active_state(Unit *u) {
- assert(u);
-
- return state_translation_table[DEVICE(u)->state];
-}
-
-_pure_ static const char *device_sub_state_to_string(Unit *u) {
- assert(u);
-
- return device_state_to_string(DEVICE(u)->state);
-}
-
-static int device_update_description(Unit *u, struct udev_device *dev, const char *path) {
- const char *model;
- int r;
-
- assert(u);
- assert(dev);
- assert(path);
-
- model = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE");
- if (!model)
- model = udev_device_get_property_value(dev, "ID_MODEL");
-
- if (model) {
- const char *label;
-
- /* Try to concatenate the device model string with a label, if there is one */
- label = udev_device_get_property_value(dev, "ID_FS_LABEL");
- if (!label)
- label = udev_device_get_property_value(dev, "ID_PART_ENTRY_NAME");
- if (!label)
- label = udev_device_get_property_value(dev, "ID_PART_ENTRY_NUMBER");
-
- if (label) {
- _cleanup_free_ char *j;
-
- j = strjoin(model, " ", label, NULL);
- if (j)
- r = unit_set_description(u, j);
- else
- r = -ENOMEM;
- } else
- r = unit_set_description(u, model);
- } else
- r = unit_set_description(u, path);
-
- if (r < 0)
- log_unit_error_errno(u->id, r, "Failed to set device description: %m");
-
- return r;
-}
-
-static int device_add_udev_wants(Unit *u, struct udev_device *dev) {
- const char *wants;
- const char *word, *state;
- size_t l;
- int r;
- const char *property;
-
- assert(u);
- assert(dev);
-
- property = u->manager->running_as == SYSTEMD_USER ? "SYSTEMD_USER_WANTS" : "SYSTEMD_WANTS";
- wants = udev_device_get_property_value(dev, property);
- if (!wants)
- return 0;
-
- FOREACH_WORD_QUOTED(word, l, wants, state) {
- _cleanup_free_ char *n = NULL;
- char e[l+1];
-
- memcpy(e, word, l);
- e[l] = 0;
-
- n = unit_name_mangle(e, MANGLE_NOGLOB);
- if (!n)
- return log_oom();
-
- r = unit_add_dependency_by_name(u, UNIT_WANTS, n, NULL, true);
- if (r < 0)
- return log_unit_error_errno(u->id, r, "Failed to add wants dependency: %m");
- }
- if (!isempty(state))
- log_unit_warning(u->id, "Property %s on %s has trailing garbage, ignoring.", property, strna(udev_device_get_syspath(dev)));
-
- return 0;
-}
-
-static int device_setup_unit(Manager *m, struct udev_device *dev, const char *path, bool main) {
- _cleanup_free_ char *e = NULL;
- const char *sysfs;
- Unit *u = NULL;
- bool delete;
- int r;
-
- assert(m);
- assert(dev);
- assert(path);
-
- sysfs = udev_device_get_syspath(dev);
- if (!sysfs)
- return 0;
-
- e = unit_name_from_path(path, ".device");
- if (!e)
- return log_oom();
-
- u = manager_get_unit(m, e);
-
- if (u &&
- DEVICE(u)->sysfs &&
- !path_equal(DEVICE(u)->sysfs, sysfs)) {
- log_unit_error(u->id, "Device %s appeared twice with different sysfs paths %s and %s", e, DEVICE(u)->sysfs, sysfs);
- return -EEXIST;
- }
-
- if (!u) {
- delete = true;
-
- u = unit_new(m, sizeof(Device));
- if (!u)
- return log_oom();
-
- r = unit_add_name(u, e);
- if (r < 0)
- goto fail;
-
- unit_add_to_load_queue(u);
- } else
- delete = false;
-
- /* If this was created via some dependency and has not
- * actually been seen yet ->sysfs will not be
- * initialized. Hence initialize it if necessary. */
-
- r = device_set_sysfs(DEVICE(u), sysfs);
- if (r < 0)
- goto fail;
-
- (void) device_update_description(u, dev, path);
-
- /* The additional systemd udev properties we only interpret
- * for the main object */
- if (main)
- (void) device_add_udev_wants(u, dev);
-
- /* 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->id, r, "Failed to set up device unit: %m");
-
- if (delete && u)
- unit_free(u);
-
- return r;
-}
-
-static int device_process_new(Manager *m, struct udev_device *dev) {
- const char *sysfs, *dn, *alias;
- struct udev_list_entry *item = NULL, *first = NULL;
- int r;
-
- assert(m);
-
- sysfs = udev_device_get_syspath(dev);
- if (!sysfs)
- return 0;
-
- /* Add the main unit named after the sysfs path */
- r = device_setup_unit(m, dev, sysfs, true);
- if (r < 0)
- return r;
-
- /* Add an additional unit for the device node */
- dn = udev_device_get_devnode(dev);
- if (dn)
- (void) device_setup_unit(m, dev, dn, false);
-
- /* Add additional units for all symlinks */
- first = udev_device_get_devlinks_list_entry(dev);
- udev_list_entry_foreach(item, first) {
- const char *p;
- struct stat st;
-
- /* 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/"))
- continue;
-
- /* Verify that the symlink in the FS actually belongs
- * to this device. This is useful to deal with
- * conflicting devices, e.g. when two disks want the
- * same /dev/disk/by-label/xxx link because they have
- * the same label. We want to make sure that the same
- * device that won the symlink wins in systemd, so we
- * check the device node major/minor */
- if (stat(p, &st) >= 0)
- if ((!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) ||
- st.st_rdev != udev_device_get_devnum(dev))
- continue;
-
- (void) device_setup_unit(m, dev, p, false);
- }
-
- /* Add additional units for all explicitly configured
- * aliases */
- alias = udev_device_get_property_value(dev, "SYSTEMD_ALIAS");
- if (alias) {
- const char *word, *state;
- size_t l;
-
- FOREACH_WORD_QUOTED(word, l, alias, state) {
- char e[l+1];
-
- memcpy(e, word, l);
- e[l] = 0;
-
- if (path_is_absolute(e))
- (void) device_setup_unit(m, dev, e, false);
- else
- log_warning("SYSTEMD_ALIAS for %s is not an absolute path, ignoring: %s", sysfs, e);
- }
- if (!isempty(state))
- log_warning("SYSTEMD_ALIAS for %s has trailing garbage, ignoring.", sysfs);
- }
-
- return 0;
-}
-
-static void device_update_found_one(Device *d, bool add, DeviceFound found, bool now) {
- DeviceFound n;
-
- assert(d);
-
- n = add ? (d->found | found) : (d->found & ~found);
- if (n == d->found)
- return;
-
- d->found = n;
-
- if (now) {
- if (d->found & DEVICE_FOUND_UDEV)
- device_set_state(d, DEVICE_PLUGGED);
- else if (add && d->found != DEVICE_NOT_FOUND)
- device_set_state(d, DEVICE_TENTATIVE);
- else
- device_set_state(d, DEVICE_DEAD);
- }
-}
-
-static int device_update_found_by_sysfs(Manager *m, const char *sysfs, bool add, DeviceFound found, bool now) {
- Device *d, *l;
-
- assert(m);
- assert(sysfs);
-
- if (found == DEVICE_NOT_FOUND)
- return 0;
-
- l = hashmap_get(m->devices_by_sysfs, sysfs);
- LIST_FOREACH(same_sysfs, d, l)
- device_update_found_one(d, add, found, now);
-
- return 0;
-}
-
-static int device_update_found_by_name(Manager *m, const char *path, bool add, DeviceFound found, bool now) {
- _cleanup_free_ char *e = NULL;
- Unit *u;
-
- assert(m);
- assert(path);
-
- if (found == DEVICE_NOT_FOUND)
- return 0;
-
- e = unit_name_from_path(path, ".device");
- if (!e)
- return log_oom();
-
- u = manager_get_unit(m, e);
- if (!u)
- return 0;
-
- device_update_found_one(DEVICE(u), add, found, now);
- return 0;
-}
-
-static bool device_is_ready(struct udev_device *dev) {
- const char *ready;
-
- assert(dev);
-
- ready = udev_device_get_property_value(dev, "SYSTEMD_READY");
- if (!ready)
- return true;
-
- return parse_boolean(ready) != 0;
-}
-
-static Unit *device_following(Unit *u) {
- Device *d = DEVICE(u);
- Device *other, *first = NULL;
-
- assert(d);
-
- if (startswith(u->id, "sys-"))
- return NULL;
-
- /* Make everybody follow the unit that's named after the sysfs path */
- for (other = d->same_sysfs_next; other; other = other->same_sysfs_next)
- if (startswith(UNIT(other)->id, "sys-"))
- return UNIT(other);
-
- for (other = d->same_sysfs_prev; other; other = other->same_sysfs_prev) {
- if (startswith(UNIT(other)->id, "sys-"))
- return UNIT(other);
-
- first = other;
- }
-
- return UNIT(first);
-}
-
-static int device_following_set(Unit *u, Set **_set) {
- Device *d = DEVICE(u), *other;
- Set *set;
- int r;
-
- assert(d);
- assert(_set);
-
- if (LIST_JUST_US(same_sysfs, d)) {
- *_set = NULL;
- return 0;
- }
-
- set = set_new(NULL);
- if (!set)
- return -ENOMEM;
-
- LIST_FOREACH_AFTER(same_sysfs, other, d) {
- r = set_put(set, other);
- if (r < 0)
- goto fail;
- }
-
- LIST_FOREACH_BEFORE(same_sysfs, other, d) {
- r = set_put(set, other);
- if (r < 0)
- goto fail;
- }
-
- *_set = 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;
- }
-
- hashmap_free(m->devices_by_sysfs);
- m->devices_by_sysfs = NULL;
-}
-
-static int device_enumerate(Manager *m) {
- _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
- struct udev_list_entry *item = NULL, *first = NULL;
- int r;
-
- assert(m);
-
- if (!m->udev_monitor) {
- m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
- if (!m->udev_monitor) {
- r = -ENOMEM;
- goto fail;
- }
-
- /* This will fail if we are unprivileged, but that
- * should not matter much, as user instances won't run
- * during boot. */
- (void) udev_monitor_set_receive_buffer_size(m->udev_monitor, 128*1024*1024);
-
- r = udev_monitor_filter_add_match_tag(m->udev_monitor, "systemd");
- if (r < 0)
- goto fail;
-
- r = udev_monitor_enable_receiving(m->udev_monitor);
- if (r < 0)
- goto fail;
-
- r = sd_event_add_io(m->event, &m->udev_event_source, udev_monitor_get_fd(m->udev_monitor), EPOLLIN, device_dispatch_io, m);
- if (r < 0)
- goto fail;
- }
-
- e = udev_enumerate_new(m->udev);
- if (!e) {
- r = -ENOMEM;
- goto fail;
- }
-
- r = udev_enumerate_add_match_tag(e, "systemd");
- if (r < 0)
- goto fail;
-
- r = udev_enumerate_add_match_is_initialized(e);
- if (r < 0)
- goto fail;
-
- r = udev_enumerate_scan_devices(e);
- if (r < 0)
- goto fail;
-
- first = udev_enumerate_get_list_entry(e);
- udev_list_entry_foreach(item, first) {
- _cleanup_udev_device_unref_ 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();
- continue;
- }
-
- if (!device_is_ready(dev))
- continue;
-
- (void) device_process_new(m, dev);
-
- device_update_found_by_sysfs(m, sysfs, true, DEVICE_FOUND_UDEV, false);
- }
-
- return 0;
-
-fail:
- log_error_errno(r, "Failed to enumerate devices: %m");
-
- device_shutdown(m);
- return r;
-}
-
-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;
- Manager *m = userdata;
- const char *action, *sysfs;
- int r;
-
- assert(m);
-
- 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 (!(revents & EPOLLIN))
- return 0;
- }
-
- /*
- * libudev might filter-out devices which pass the bloom
- * filter, so getting NULL here is not necessarily an error.
- */
- dev = udev_monitor_receive_device(m->udev_monitor);
- if (!dev)
- return 0;
-
- sysfs = udev_device_get_syspath(dev);
- if (!sysfs) {
- log_error("Failed to get udev sys path.");
- return 0;
- }
-
- action = udev_device_get_action(dev);
- if (!action) {
- log_error("Failed to get udev action string.");
- return 0;
- }
-
- 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");
-
- /* 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);
-
- } else if (device_is_ready(dev)) {
-
- (void) device_process_new(m, dev);
-
- r = swap_process_device_new(m, dev);
- if (r < 0)
- log_error_errno(r, "Failed to process swap device new event: %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);
-
- } 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);
- }
-
- return 0;
-}
-
-static bool device_supported(Manager *m) {
- static int read_only = -1;
- assert(m);
-
- /* If /sys is read-only we don't support device units, and any
- * attempts to start one should fail immediately. */
-
- if (read_only < 0)
- read_only = path_is_read_only_fs("/sys");
-
- 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;
- struct stat st;
-
- assert(m);
- assert(node);
-
- /* 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 (add) {
- if (!path_startswith(node, "/dev"))
- return 0;
-
- if (stat(node, &st) < 0) {
- if (errno == ENOENT)
- return 0;
-
- return log_error_errno(errno, "Failed to stat device node file %s: %m", node);
- }
-
- if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))
- return 0;
-
- dev = udev_device_new_from_devnum(m->udev, S_ISBLK(st.st_mode) ? 'b' : 'c', st.st_rdev);
- if (!dev) {
- if (errno == ENOENT)
- return 0;
-
- return log_oom();
- }
-
- /* 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. */
-
- (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);
-}
-
-static const char* const device_state_table[_DEVICE_STATE_MAX] = {
- [DEVICE_DEAD] = "dead",
- [DEVICE_TENTATIVE] = "tentative",
- [DEVICE_PLUGGED] = "plugged",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState);
-
-const UnitVTable device_vtable = {
- .object_size = sizeof(Device),
- .sections =
- "Unit\0"
- "Device\0"
- "Install\0",
-
- .no_instances = true,
-
- .init = device_init,
- .done = device_done,
- .load = unit_load_fragment_and_dropin_optional,
-
- .coldplug = device_coldplug,
-
- .dump = device_dump,
-
- .active_state = device_active_state,
- .sub_state_to_string = device_sub_state_to_string,
-
- .bus_interface = "org.freedesktop.systemd1.Device",
- .bus_vtable = bus_device_vtable,
-
- .following = device_following,
- .following_set = device_following_set,
-
- .enumerate = device_enumerate,
- .shutdown = device_shutdown,
- .supported = device_supported,
-
- .status_message_formats = {
- .starting_stopping = {
- [0] = "Expecting device %s...",
- },
- .finished_start_job = {
- [JOB_DONE] = "Found device %s.",
- [JOB_TIMEOUT] = "Timed out waiting for device %s.",
- },
- },
-};
diff --git a/src/core/device.h b/src/core/device.h
deleted file mode 100644
index 9f46e0895..000000000
--- a/src/core/device.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 Device Device;
-
-
-/* We simply watch devices, we cannot plug/unplug them. That
- * simplifies the state engine greatly */
-typedef enum DeviceState {
- DEVICE_DEAD,
- DEVICE_TENTATIVE, /* mounted or swapped, but not (yet) announced by udev */
- DEVICE_PLUGGED, /* announced by udev */
- _DEVICE_STATE_MAX,
- _DEVICE_STATE_INVALID = -1
-} DeviceState;
-
-typedef enum DeviceFound {
- DEVICE_NOT_FOUND = 0,
- DEVICE_FOUND_UDEV = 1,
- DEVICE_FOUND_MOUNT = 2,
- DEVICE_FOUND_SWAP = 4,
-} 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. */
- LIST_FIELDS(struct Device, same_sysfs);
-
- DeviceState state;
-};
-
-extern const UnitVTable device_vtable;
-
-const char* device_state_to_string(DeviceState i) _const_;
-DeviceState device_state_from_string(const char *s) _pure_;
-
-int device_found_node(Manager *m, const char *node, bool add, DeviceFound found, bool now);
diff --git a/src/core/execute.c b/src/core/execute.c
deleted file mode 100644
index 027e3319e..000000000
--- a/src/core/execute.c
+++ /dev/null
@@ -1,2912 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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>
-#include <unistd.h>
-#include <string.h>
-#include <signal.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/prctl.h>
-#include <sys/stat.h>
-#include <grp.h>
-#include <poll.h>
-#include <glob.h>
-#include <sys/personality.h>
-
-#ifdef HAVE_PAM
-#include <security/pam_appl.h>
-#endif
-
-#ifdef HAVE_SELINUX
-#include <selinux/selinux.h>
-#endif
-
-#ifdef HAVE_SECCOMP
-#include <seccomp.h>
-#endif
-
-#ifdef HAVE_APPARMOR
-#include <sys/apparmor.h>
-#endif
-
-#include "execute.h"
-#include "strv.h"
-#include "macro.h"
-#include "capability.h"
-#include "util.h"
-#include "log.h"
-#include "sd-messages.h"
-#include "ioprio.h"
-#include "securebits.h"
-#include "namespace.h"
-#include "exit-status.h"
-#include "missing.h"
-#include "def.h"
-#include "path-util.h"
-#include "env-util.h"
-#include "fileio.h"
-#include "unit.h"
-#include "async.h"
-#include "selinux-util.h"
-#include "errno-list.h"
-#include "af-list.h"
-#include "mkdir.h"
-#include "smack-util.h"
-#include "bus-endpoint.h"
-#include "cap-list.h"
-
-#ifdef HAVE_APPARMOR
-#include "apparmor-util.h"
-#endif
-
-#ifdef HAVE_SECCOMP
-#include "seccomp-util.h"
-#endif
-
-#define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC)
-#define IDLE_TIMEOUT2_USEC (1*USEC_PER_SEC)
-
-/* This assumes there is a 'tty' group */
-#define TTY_MODE 0620
-
-#define SNDBUF_SIZE (8*1024*1024)
-
-static int shift_fds(int fds[], unsigned n_fds) {
- int start, restart_from;
-
- if (n_fds <= 0)
- return 0;
-
- /* Modifies the fds array! (sorts it) */
-
- assert(fds);
-
- start = 0;
- for (;;) {
- int i;
-
- restart_from = -1;
-
- for (i = start; i < (int) n_fds; i++) {
- int nfd;
-
- /* Already at right index? */
- if (fds[i] == i+3)
- continue;
-
- if ((nfd = fcntl(fds[i], F_DUPFD, i+3)) < 0)
- return -errno;
-
- safe_close(fds[i]);
- fds[i] = nfd;
-
- /* Hmm, the fd we wanted isn't free? Then
- * let's remember that and try again from here */
- if (nfd != i+3 && restart_from < 0)
- restart_from = i;
- }
-
- if (restart_from < 0)
- break;
-
- start = restart_from;
- }
-
- return 0;
-}
-
-static int flags_fds(const int fds[], unsigned n_fds, bool nonblock) {
- unsigned i;
- int r;
-
- if (n_fds <= 0)
- return 0;
-
- assert(fds);
-
- /* Drops/Sets O_NONBLOCK and FD_CLOEXEC from the file flags */
-
- for (i = 0; i < n_fds; i++) {
-
- if ((r = fd_nonblock(fds[i], nonblock)) < 0)
- return r;
-
- /* We unconditionally drop FD_CLOEXEC from the fds,
- * since after all we want to pass these fds to our
- * children */
-
- if ((r = fd_cloexec(fds[i], false)) < 0)
- return r;
- }
-
- return 0;
-}
-
-_pure_ static const char *tty_path(const ExecContext *context) {
- assert(context);
-
- if (context->tty_path)
- return context->tty_path;
-
- return "/dev/console";
-}
-
-static void exec_context_tty_reset(const ExecContext *context) {
- assert(context);
-
- if (context->tty_vhangup)
- terminal_vhangup(tty_path(context));
-
- if (context->tty_reset)
- reset_terminal(tty_path(context));
-
- if (context->tty_vt_disallocate && context->tty_path)
- vt_disallocate(context->tty_path);
-}
-
-static bool is_terminal_output(ExecOutput o) {
- return
- o == EXEC_OUTPUT_TTY ||
- o == EXEC_OUTPUT_SYSLOG_AND_CONSOLE ||
- o == EXEC_OUTPUT_KMSG_AND_CONSOLE ||
- o == EXEC_OUTPUT_JOURNAL_AND_CONSOLE;
-}
-
-static int open_null_as(int flags, int nfd) {
- int fd, r;
-
- assert(nfd >= 0);
-
- fd = open("/dev/null", flags|O_NOCTTY);
- if (fd < 0)
- return -errno;
-
- if (fd != nfd) {
- r = dup2(fd, nfd) < 0 ? -errno : nfd;
- safe_close(fd);
- } else
- r = nfd;
-
- return r;
-}
-
-static int connect_journal_socket(int fd, uid_t uid, gid_t gid) {
- union sockaddr_union sa = {
- .un.sun_family = AF_UNIX,
- .un.sun_path = "/run/systemd/journal/stdout",
- };
- uid_t olduid = UID_INVALID;
- gid_t oldgid = GID_INVALID;
- int r;
-
- if (gid != GID_INVALID) {
- oldgid = getgid();
-
- r = setegid(gid);
- if (r < 0)
- return -errno;
- }
-
- if (uid != UID_INVALID) {
- olduid = getuid();
-
- r = seteuid(uid);
- if (r < 0) {
- r = -errno;
- goto restore_gid;
- }
- }
-
- r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
- if (r < 0)
- r = -errno;
-
- /* If we fail to restore the uid or gid, things will likely
- fail later on. This should only happen if an LSM interferes. */
-
- if (uid != UID_INVALID)
- (void) seteuid(olduid);
-
- restore_gid:
- if (gid != GID_INVALID)
- (void) setegid(oldgid);
-
- return r;
-}
-
-static int connect_logger_as(const ExecContext *context, ExecOutput output, const char *ident, const char *unit_id, int nfd, uid_t uid, gid_t gid) {
- int fd, r;
-
- assert(context);
- assert(output < _EXEC_OUTPUT_MAX);
- assert(ident);
- assert(nfd >= 0);
-
- fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (fd < 0)
- return -errno;
-
- r = connect_journal_socket(fd, uid, gid);
- if (r < 0)
- return r;
-
- if (shutdown(fd, SHUT_RD) < 0) {
- safe_close(fd);
- return -errno;
- }
-
- fd_inc_sndbuf(fd, SNDBUF_SIZE);
-
- dprintf(fd,
- "%s\n"
- "%s\n"
- "%i\n"
- "%i\n"
- "%i\n"
- "%i\n"
- "%i\n",
- context->syslog_identifier ? context->syslog_identifier : ident,
- unit_id,
- context->syslog_priority,
- !!context->syslog_level_prefix,
- output == EXEC_OUTPUT_SYSLOG || output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
- output == EXEC_OUTPUT_KMSG || output == EXEC_OUTPUT_KMSG_AND_CONSOLE,
- is_terminal_output(output));
-
- if (fd != nfd) {
- r = dup2(fd, nfd) < 0 ? -errno : nfd;
- safe_close(fd);
- } else
- r = nfd;
-
- return r;
-}
-static int open_terminal_as(const char *path, mode_t mode, int nfd) {
- int fd, r;
-
- assert(path);
- assert(nfd >= 0);
-
- if ((fd = open_terminal(path, mode | O_NOCTTY)) < 0)
- return fd;
-
- if (fd != nfd) {
- r = dup2(fd, nfd) < 0 ? -errno : nfd;
- safe_close(fd);
- } else
- r = nfd;
-
- return r;
-}
-
-static bool is_terminal_input(ExecInput i) {
- return
- i == EXEC_INPUT_TTY ||
- i == EXEC_INPUT_TTY_FORCE ||
- i == EXEC_INPUT_TTY_FAIL;
-}
-
-static int fixup_input(ExecInput std_input, int socket_fd, bool apply_tty_stdin) {
-
- if (is_terminal_input(std_input) && !apply_tty_stdin)
- return EXEC_INPUT_NULL;
-
- if (std_input == EXEC_INPUT_SOCKET && socket_fd < 0)
- return EXEC_INPUT_NULL;
-
- return std_input;
-}
-
-static int fixup_output(ExecOutput std_output, int socket_fd) {
-
- if (std_output == EXEC_OUTPUT_SOCKET && socket_fd < 0)
- return EXEC_OUTPUT_INHERIT;
-
- return std_output;
-}
-
-static int setup_input(const ExecContext *context, int socket_fd, bool apply_tty_stdin) {
- ExecInput i;
-
- assert(context);
-
- i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
-
- switch (i) {
-
- case EXEC_INPUT_NULL:
- return open_null_as(O_RDONLY, STDIN_FILENO);
-
- case EXEC_INPUT_TTY:
- case EXEC_INPUT_TTY_FORCE:
- case EXEC_INPUT_TTY_FAIL: {
- int fd, r;
-
- fd = acquire_terminal(tty_path(context),
- i == EXEC_INPUT_TTY_FAIL,
- i == EXEC_INPUT_TTY_FORCE,
- false,
- USEC_INFINITY);
- if (fd < 0)
- return fd;
-
- if (fd != STDIN_FILENO) {
- r = dup2(fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO;
- safe_close(fd);
- } else
- r = STDIN_FILENO;
-
- return r;
- }
-
- case EXEC_INPUT_SOCKET:
- return dup2(socket_fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO;
-
- default:
- assert_not_reached("Unknown input type");
- }
-}
-
-static int setup_output(const ExecContext *context, int fileno, int socket_fd, const char *ident, const char *unit_id, bool apply_tty_stdin, uid_t uid, gid_t gid) {
- ExecOutput o;
- ExecInput i;
- int r;
-
- assert(context);
- assert(ident);
-
- i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
- o = fixup_output(context->std_output, socket_fd);
-
- if (fileno == STDERR_FILENO) {
- ExecOutput e;
- e = fixup_output(context->std_error, socket_fd);
-
- /* This expects the input and output are already set up */
-
- /* Don't change the stderr file descriptor if we inherit all
- * the way and are not on a tty */
- if (e == EXEC_OUTPUT_INHERIT &&
- o == EXEC_OUTPUT_INHERIT &&
- i == EXEC_INPUT_NULL &&
- !is_terminal_input(context->std_input) &&
- getppid () != 1)
- return fileno;
-
- /* Duplicate from stdout if possible */
- if (e == o || e == EXEC_OUTPUT_INHERIT)
- return dup2(STDOUT_FILENO, fileno) < 0 ? -errno : fileno;
-
- o = e;
-
- } else if (o == EXEC_OUTPUT_INHERIT) {
- /* If input got downgraded, inherit the original value */
- if (i == EXEC_INPUT_NULL && is_terminal_input(context->std_input))
- return open_terminal_as(tty_path(context), O_WRONLY, fileno);
-
- /* If the input is connected to anything that's not a /dev/null, inherit that... */
- if (i != EXEC_INPUT_NULL)
- return dup2(STDIN_FILENO, fileno) < 0 ? -errno : fileno;
-
- /* If we are not started from PID 1 we just inherit STDOUT from our parent process. */
- if (getppid() != 1)
- return fileno;
-
- /* We need to open /dev/null here anew, to get the right access mode. */
- return open_null_as(O_WRONLY, fileno);
- }
-
- switch (o) {
-
- case EXEC_OUTPUT_NULL:
- return open_null_as(O_WRONLY, fileno);
-
- case EXEC_OUTPUT_TTY:
- if (is_terminal_input(i))
- return dup2(STDIN_FILENO, fileno) < 0 ? -errno : fileno;
-
- /* We don't reset the terminal if this is just about output */
- return open_terminal_as(tty_path(context), O_WRONLY, fileno);
-
- case EXEC_OUTPUT_SYSLOG:
- case EXEC_OUTPUT_SYSLOG_AND_CONSOLE:
- case EXEC_OUTPUT_KMSG:
- case EXEC_OUTPUT_KMSG_AND_CONSOLE:
- case EXEC_OUTPUT_JOURNAL:
- case EXEC_OUTPUT_JOURNAL_AND_CONSOLE:
- r = connect_logger_as(context, o, ident, unit_id, fileno, uid, gid);
- if (r < 0) {
- log_unit_struct(unit_id,
- LOG_ERR,
- LOG_MESSAGE("Failed to connect %s of %s to the journal socket: %s",
- fileno == STDOUT_FILENO ? "stdout" : "stderr",
- unit_id, strerror(-r)),
- LOG_ERRNO(-r),
- NULL);
- r = open_null_as(O_WRONLY, fileno);
- }
- return r;
-
- case EXEC_OUTPUT_SOCKET:
- assert(socket_fd >= 0);
- return dup2(socket_fd, fileno) < 0 ? -errno : fileno;
-
- default:
- assert_not_reached("Unknown error type");
- }
-}
-
-static int chown_terminal(int fd, uid_t uid) {
- struct stat st;
-
- assert(fd >= 0);
-
- /* This might fail. What matters are the results. */
- (void) fchown(fd, uid, -1);
- (void) fchmod(fd, TTY_MODE);
-
- if (fstat(fd, &st) < 0)
- return -errno;
-
- if (st.st_uid != uid || (st.st_mode & 0777) != TTY_MODE)
- return -EPERM;
-
- return 0;
-}
-
-static int setup_confirm_stdio(int *_saved_stdin,
- int *_saved_stdout) {
- int fd = -1, saved_stdin, saved_stdout = -1, r;
-
- assert(_saved_stdin);
- assert(_saved_stdout);
-
- saved_stdin = fcntl(STDIN_FILENO, F_DUPFD, 3);
- if (saved_stdin < 0)
- return -errno;
-
- saved_stdout = fcntl(STDOUT_FILENO, F_DUPFD, 3);
- if (saved_stdout < 0) {
- r = errno;
- goto fail;
- }
-
- fd = acquire_terminal(
- "/dev/console",
- false,
- false,
- false,
- DEFAULT_CONFIRM_USEC);
- if (fd < 0) {
- r = fd;
- goto fail;
- }
-
- r = chown_terminal(fd, getuid());
- if (r < 0)
- goto fail;
-
- if (dup2(fd, STDIN_FILENO) < 0) {
- r = -errno;
- goto fail;
- }
-
- if (dup2(fd, STDOUT_FILENO) < 0) {
- r = -errno;
- goto fail;
- }
-
- if (fd >= 2)
- safe_close(fd);
-
- *_saved_stdin = saved_stdin;
- *_saved_stdout = saved_stdout;
-
- return 0;
-
-fail:
- safe_close(saved_stdout);
- safe_close(saved_stdin);
- safe_close(fd);
-
- return r;
-}
-
-_printf_(1, 2) static int write_confirm_message(const char *format, ...) {
- _cleanup_close_ int fd = -1;
- va_list ap;
-
- assert(format);
-
- fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
- if (fd < 0)
- return fd;
-
- va_start(ap, format);
- vdprintf(fd, format, ap);
- va_end(ap);
-
- return 0;
-}
-
-static int restore_confirm_stdio(int *saved_stdin,
- int *saved_stdout) {
-
- int r = 0;
-
- assert(saved_stdin);
- assert(saved_stdout);
-
- release_terminal();
-
- if (*saved_stdin >= 0)
- if (dup2(*saved_stdin, STDIN_FILENO) < 0)
- r = -errno;
-
- if (*saved_stdout >= 0)
- if (dup2(*saved_stdout, STDOUT_FILENO) < 0)
- r = -errno;
-
- safe_close(*saved_stdin);
- safe_close(*saved_stdout);
-
- return r;
-}
-
-static int ask_for_confirmation(char *response, char **argv) {
- int saved_stdout = -1, saved_stdin = -1, r;
- _cleanup_free_ char *line = NULL;
-
- r = setup_confirm_stdio(&saved_stdin, &saved_stdout);
- if (r < 0)
- return r;
-
- line = exec_command_line(argv);
- if (!line)
- return -ENOMEM;
-
- r = ask_char(response, "yns", "Execute %s? [Yes, No, Skip] ", line);
-
- restore_confirm_stdio(&saved_stdin, &saved_stdout);
-
- return r;
-}
-
-static int enforce_groups(const ExecContext *context, const char *username, gid_t gid) {
- bool keep_groups = false;
- int r;
-
- assert(context);
-
- /* Lookup and set GID and supplementary group list. Here too
- * we avoid NSS lookups for gid=0. */
-
- if (context->group || username) {
-
- if (context->group) {
- const char *g = context->group;
-
- if ((r = get_group_creds(&g, &gid)) < 0)
- return r;
- }
-
- /* First step, initialize groups from /etc/groups */
- if (username && gid != 0) {
- if (initgroups(username, gid) < 0)
- return -errno;
-
- keep_groups = true;
- }
-
- /* Second step, set our gids */
- if (setresgid(gid, gid, gid) < 0)
- return -errno;
- }
-
- if (context->supplementary_groups) {
- int ngroups_max, k;
- gid_t *gids;
- char **i;
-
- /* Final step, initialize any manually set supplementary groups */
- assert_se((ngroups_max = (int) sysconf(_SC_NGROUPS_MAX)) > 0);
-
- if (!(gids = new(gid_t, ngroups_max)))
- return -ENOMEM;
-
- if (keep_groups) {
- if ((k = getgroups(ngroups_max, gids)) < 0) {
- free(gids);
- return -errno;
- }
- } else
- k = 0;
-
- STRV_FOREACH(i, context->supplementary_groups) {
- const char *g;
-
- if (k >= ngroups_max) {
- free(gids);
- return -E2BIG;
- }
-
- g = *i;
- r = get_group_creds(&g, gids+k);
- if (r < 0) {
- free(gids);
- return r;
- }
-
- k++;
- }
-
- if (setgroups(k, gids) < 0) {
- free(gids);
- return -errno;
- }
-
- free(gids);
- }
-
- return 0;
-}
-
-static int enforce_user(const ExecContext *context, uid_t uid) {
- assert(context);
-
- /* Sets (but doesn't lookup) the uid and make sure we keep the
- * capabilities while doing so. */
-
- if (context->capabilities) {
- _cleanup_cap_free_ cap_t d = NULL;
- static const cap_value_t bits[] = {
- CAP_SETUID, /* Necessary so that we can run setresuid() below */
- CAP_SETPCAP /* Necessary so that we can set PR_SET_SECUREBITS later on */
- };
-
- /* First step: If we need to keep capabilities but
- * drop privileges we need to make sure we keep our
- * caps, while we drop privileges. */
- if (uid != 0) {
- int sb = context->secure_bits | 1<<SECURE_KEEP_CAPS;
-
- if (prctl(PR_GET_SECUREBITS) != sb)
- if (prctl(PR_SET_SECUREBITS, sb) < 0)
- return -errno;
- }
-
- /* Second step: set the capabilities. This will reduce
- * the capabilities to the minimum we need. */
-
- d = cap_dup(context->capabilities);
- if (!d)
- return -errno;
-
- if (cap_set_flag(d, CAP_EFFECTIVE, ELEMENTSOF(bits), bits, CAP_SET) < 0 ||
- cap_set_flag(d, CAP_PERMITTED, ELEMENTSOF(bits), bits, CAP_SET) < 0)
- return -errno;
-
- if (cap_set_proc(d) < 0)
- return -errno;
- }
-
- /* Third step: actually set the uids */
- if (setresuid(uid, uid, uid) < 0)
- return -errno;
-
- /* At this point we should have all necessary capabilities but
- are otherwise a normal user. However, the caps might got
- corrupted due to the setresuid() so we need clean them up
- later. This is done outside of this call. */
-
- return 0;
-}
-
-#ifdef HAVE_PAM
-
-static int null_conv(
- int num_msg,
- const struct pam_message **msg,
- struct pam_response **resp,
- void *appdata_ptr) {
-
- /* We don't support conversations */
-
- return PAM_CONV_ERR;
-}
-
-static int setup_pam(
- const char *name,
- const char *user,
- uid_t uid,
- const char *tty,
- char ***pam_env,
- int fds[], unsigned n_fds) {
-
- static const struct pam_conv conv = {
- .conv = null_conv,
- .appdata_ptr = NULL
- };
-
- pam_handle_t *handle = NULL;
- sigset_t ss, old_ss;
- int pam_code = PAM_SUCCESS;
- int err;
- char **e = NULL;
- bool close_session = false;
- pid_t pam_pid = 0, parent_pid;
- int flags = 0;
-
- assert(name);
- assert(user);
- assert(pam_env);
-
- /* We set up PAM in the parent process, then fork. The child
- * will then stay around until killed via PR_GET_PDEATHSIG or
- * systemd via the cgroup logic. It will then remove the PAM
- * session again. The parent process will exec() the actual
- * daemon. We do things this way to ensure that the main PID
- * of the daemon is the one we initially fork()ed. */
-
- if (log_get_max_level() < LOG_DEBUG)
- flags |= PAM_SILENT;
-
- pam_code = pam_start(name, user, &conv, &handle);
- if (pam_code != PAM_SUCCESS) {
- handle = NULL;
- goto fail;
- }
-
- if (tty) {
- pam_code = pam_set_item(handle, PAM_TTY, tty);
- if (pam_code != PAM_SUCCESS)
- goto fail;
- }
-
- pam_code = pam_acct_mgmt(handle, flags);
- if (pam_code != PAM_SUCCESS)
- goto fail;
-
- pam_code = pam_open_session(handle, flags);
- if (pam_code != PAM_SUCCESS)
- goto fail;
-
- close_session = true;
-
- e = pam_getenvlist(handle);
- if (!e) {
- pam_code = PAM_BUF_ERR;
- goto fail;
- }
-
- /* Block SIGTERM, so that we know that it won't get lost in
- * the child */
- if (sigemptyset(&ss) < 0 ||
- sigaddset(&ss, SIGTERM) < 0 ||
- sigprocmask(SIG_BLOCK, &ss, &old_ss) < 0)
- goto fail;
-
- parent_pid = getpid();
-
- pam_pid = fork();
- if (pam_pid < 0)
- goto fail;
-
- if (pam_pid == 0) {
- int sig;
- int r = EXIT_PAM;
-
- /* The child's job is to reset the PAM session on
- * termination */
-
- /* This string must fit in 10 chars (i.e. the length
- * of "/sbin/init"), to look pretty in /bin/ps */
- rename_process("(sd-pam)");
-
- /* Make sure we don't keep open the passed fds in this
- child. We assume that otherwise only those fds are
- open here that have been opened by PAM. */
- close_many(fds, n_fds);
-
- /* Drop privileges - we don't need any to pam_close_session
- * and this will make PR_SET_PDEATHSIG work in most cases.
- * If this fails, ignore the error - but expect sd-pam threads
- * to fail to exit normally */
- if (setresuid(uid, uid, uid) < 0)
- log_error_errno(r, "Error: Failed to setresuid() in sd-pam: %m");
-
- /* Wait until our parent died. This will only work if
- * the above setresuid() succeeds, otherwise the kernel
- * will not allow unprivileged parents kill their privileged
- * children this way. We rely on the control groups kill logic
- * to do the rest for us. */
- if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
- goto child_finish;
-
- /* Check if our parent process might already have
- * died? */
- if (getppid() == parent_pid) {
- for (;;) {
- if (sigwait(&ss, &sig) < 0) {
- if (errno == EINTR)
- continue;
-
- goto child_finish;
- }
-
- assert(sig == SIGTERM);
- break;
- }
- }
-
- /* If our parent died we'll end the session */
- if (getppid() != parent_pid) {
- pam_code = pam_close_session(handle, flags);
- if (pam_code != PAM_SUCCESS)
- goto child_finish;
- }
-
- r = 0;
-
- child_finish:
- pam_end(handle, pam_code | flags);
- _exit(r);
- }
-
- /* If the child was forked off successfully it will do all the
- * cleanups, so forget about the handle here. */
- handle = NULL;
-
- /* Unblock SIGTERM again in the parent */
- if (sigprocmask(SIG_SETMASK, &old_ss, NULL) < 0)
- goto fail;
-
- /* We close the log explicitly here, since the PAM modules
- * might have opened it, but we don't want this fd around. */
- closelog();
-
- *pam_env = e;
- e = NULL;
-
- return 0;
-
-fail:
- if (pam_code != PAM_SUCCESS) {
- log_error("PAM failed: %s", pam_strerror(handle, pam_code));
- err = -EPERM; /* PAM errors do not map to errno */
- } else {
- log_error_errno(errno, "PAM failed: %m");
- err = -errno;
- }
-
- if (handle) {
- if (close_session)
- pam_code = pam_close_session(handle, flags);
-
- pam_end(handle, pam_code | flags);
- }
-
- strv_free(e);
-
- closelog();
-
- if (pam_pid > 1) {
- kill(pam_pid, SIGTERM);
- kill(pam_pid, SIGCONT);
- }
-
- return err;
-}
-#endif
-
-static void rename_process_from_path(const char *path) {
- char process_name[11];
- const char *p;
- size_t l;
-
- /* This resulting string must fit in 10 chars (i.e. the length
- * of "/sbin/init") to look pretty in /bin/ps */
-
- p = basename(path);
- if (isempty(p)) {
- rename_process("(...)");
- return;
- }
-
- l = strlen(p);
- if (l > 8) {
- /* The end of the process name is usually more
- * interesting, since the first bit might just be
- * "systemd-" */
- p = p + l - 8;
- l = 8;
- }
-
- process_name[0] = '(';
- memcpy(process_name+1, p, l);
- process_name[1+l] = ')';
- process_name[1+l+1] = 0;
-
- rename_process(process_name);
-}
-
-#ifdef HAVE_SECCOMP
-
-static int apply_seccomp(const ExecContext *c) {
- uint32_t negative_action, action;
- scmp_filter_ctx *seccomp;
- Iterator i;
- void *id;
- int r;
-
- assert(c);
-
- negative_action = c->syscall_errno == 0 ? SCMP_ACT_KILL : SCMP_ACT_ERRNO(c->syscall_errno);
-
- seccomp = seccomp_init(c->syscall_whitelist ? negative_action : SCMP_ACT_ALLOW);
- if (!seccomp)
- return -ENOMEM;
-
- if (c->syscall_archs) {
-
- SET_FOREACH(id, c->syscall_archs, i) {
- r = seccomp_arch_add(seccomp, PTR_TO_UINT32(id) - 1);
- if (r == -EEXIST)
- continue;
- if (r < 0)
- goto finish;
- }
-
- } else {
- r = seccomp_add_secondary_archs(seccomp);
- if (r < 0)
- goto finish;
- }
-
- action = c->syscall_whitelist ? SCMP_ACT_ALLOW : negative_action;
- SET_FOREACH(id, c->syscall_filter, i) {
- r = seccomp_rule_add(seccomp, action, PTR_TO_INT(id) - 1, 0);
- if (r < 0)
- goto finish;
- }
-
- r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0);
- if (r < 0)
- goto finish;
-
- r = seccomp_load(seccomp);
-
-finish:
- seccomp_release(seccomp);
- return r;
-}
-
-static int apply_address_families(const ExecContext *c) {
- scmp_filter_ctx *seccomp;
- Iterator i;
- int r;
-
- assert(c);
-
- seccomp = seccomp_init(SCMP_ACT_ALLOW);
- if (!seccomp)
- return -ENOMEM;
-
- r = seccomp_add_secondary_archs(seccomp);
- if (r < 0)
- goto finish;
-
- if (c->address_families_whitelist) {
- int af, first = 0, last = 0;
- void *afp;
-
- /* If this is a whitelist, we first block the address
- * families that are out of range and then everything
- * that is not in the set. First, we find the lowest
- * and highest address family in the set. */
-
- SET_FOREACH(afp, c->address_families, i) {
- af = PTR_TO_INT(afp);
-
- if (af <= 0 || af >= af_max())
- continue;
-
- if (first == 0 || af < first)
- first = af;
-
- if (last == 0 || af > last)
- last = af;
- }
-
- assert((first == 0) == (last == 0));
-
- if (first == 0) {
-
- /* No entries in the valid range, block everything */
- r = seccomp_rule_add(
- seccomp,
- SCMP_ACT_ERRNO(EPROTONOSUPPORT),
- SCMP_SYS(socket),
- 0);
- if (r < 0)
- goto finish;
-
- } else {
-
- /* Block everything below the first entry */
- r = seccomp_rule_add(
- seccomp,
- SCMP_ACT_ERRNO(EPROTONOSUPPORT),
- SCMP_SYS(socket),
- 1,
- SCMP_A0(SCMP_CMP_LT, first));
- if (r < 0)
- goto finish;
-
- /* Block everything above the last entry */
- r = seccomp_rule_add(
- seccomp,
- SCMP_ACT_ERRNO(EPROTONOSUPPORT),
- SCMP_SYS(socket),
- 1,
- SCMP_A0(SCMP_CMP_GT, last));
- if (r < 0)
- goto finish;
-
- /* Block everything between the first and last
- * entry */
- for (af = 1; af < af_max(); af++) {
-
- if (set_contains(c->address_families, INT_TO_PTR(af)))
- continue;
-
- r = seccomp_rule_add(
- seccomp,
- SCMP_ACT_ERRNO(EPROTONOSUPPORT),
- SCMP_SYS(socket),
- 1,
- SCMP_A0(SCMP_CMP_EQ, af));
- if (r < 0)
- goto finish;
- }
- }
-
- } else {
- void *af;
-
- /* If this is a blacklist, then generate one rule for
- * each address family that are then combined in OR
- * checks. */
-
- SET_FOREACH(af, c->address_families, i) {
-
- r = seccomp_rule_add(
- seccomp,
- SCMP_ACT_ERRNO(EPROTONOSUPPORT),
- SCMP_SYS(socket),
- 1,
- SCMP_A0(SCMP_CMP_EQ, PTR_TO_INT(af)));
- if (r < 0)
- goto finish;
- }
- }
-
- r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0);
- if (r < 0)
- goto finish;
-
- r = seccomp_load(seccomp);
-
-finish:
- seccomp_release(seccomp);
- return r;
-}
-
-#endif
-
-static void do_idle_pipe_dance(int idle_pipe[4]) {
- assert(idle_pipe);
-
-
- safe_close(idle_pipe[1]);
- safe_close(idle_pipe[2]);
-
- if (idle_pipe[0] >= 0) {
- int r;
-
- r = fd_wait_for_event(idle_pipe[0], POLLHUP, IDLE_TIMEOUT_USEC);
-
- if (idle_pipe[3] >= 0 && r == 0 /* timeout */) {
- /* Signal systemd that we are bored and want to continue. */
- r = write(idle_pipe[3], "x", 1);
- if (r > 0)
- /* Wait for systemd to react to the signal above. */
- fd_wait_for_event(idle_pipe[0], POLLHUP, IDLE_TIMEOUT2_USEC);
- }
-
- safe_close(idle_pipe[0]);
-
- }
-
- safe_close(idle_pipe[3]);
-}
-
-static int build_environment(
- const ExecContext *c,
- unsigned n_fds,
- usec_t watchdog_usec,
- const char *home,
- const char *username,
- const char *shell,
- char ***ret) {
-
- _cleanup_strv_free_ char **our_env = NULL;
- unsigned n_env = 0;
- char *x;
-
- assert(c);
- assert(ret);
-
- our_env = new0(char*, 10);
- if (!our_env)
- return -ENOMEM;
-
- if (n_fds > 0) {
- if (asprintf(&x, "LISTEN_PID="PID_FMT, getpid()) < 0)
- return -ENOMEM;
- our_env[n_env++] = x;
-
- if (asprintf(&x, "LISTEN_FDS=%u", n_fds) < 0)
- return -ENOMEM;
- our_env[n_env++] = x;
- }
-
- if (watchdog_usec > 0) {
- if (asprintf(&x, "WATCHDOG_PID="PID_FMT, getpid()) < 0)
- return -ENOMEM;
- our_env[n_env++] = x;
-
- if (asprintf(&x, "WATCHDOG_USEC="USEC_FMT, watchdog_usec) < 0)
- return -ENOMEM;
- our_env[n_env++] = x;
- }
-
- if (home) {
- x = strappend("HOME=", home);
- if (!x)
- return -ENOMEM;
- our_env[n_env++] = x;
- }
-
- if (username) {
- x = strappend("LOGNAME=", username);
- if (!x)
- return -ENOMEM;
- our_env[n_env++] = x;
-
- x = strappend("USER=", username);
- if (!x)
- return -ENOMEM;
- our_env[n_env++] = x;
- }
-
- if (shell) {
- x = strappend("SHELL=", shell);
- if (!x)
- return -ENOMEM;
- our_env[n_env++] = x;
- }
-
- if (is_terminal_input(c->std_input) ||
- c->std_output == EXEC_OUTPUT_TTY ||
- c->std_error == EXEC_OUTPUT_TTY ||
- c->tty_path) {
-
- x = strdup(default_term_for_tty(tty_path(c)));
- if (!x)
- return -ENOMEM;
- our_env[n_env++] = x;
- }
-
- our_env[n_env++] = NULL;
- assert(n_env <= 10);
-
- *ret = our_env;
- our_env = NULL;
-
- return 0;
-}
-
-static int exec_child(
- ExecCommand *command,
- const ExecContext *context,
- const ExecParameters *params,
- ExecRuntime *runtime,
- char **argv,
- int socket_fd,
- int *fds, unsigned n_fds,
- char **files_env,
- int *exit_status) {
-
- _cleanup_strv_free_ char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL;
- _cleanup_free_ char *mac_selinux_context_net = NULL;
- const char *username = NULL, *home = NULL, *shell = NULL;
- unsigned n_dont_close = 0;
- int dont_close[n_fds + 4];
- uid_t uid = UID_INVALID;
- gid_t gid = GID_INVALID;
- int i, r;
-
- assert(command);
- assert(context);
- assert(params);
- assert(exit_status);
-
- rename_process_from_path(command->path);
-
- /* We reset exactly these signals, since they are the
- * only ones we set to SIG_IGN in the main daemon. All
- * others we leave untouched because we set them to
- * SIG_DFL or a valid handler initially, both of which
- * will be demoted to SIG_DFL. */
- default_signals(SIGNALS_CRASH_HANDLER,
- SIGNALS_IGNORE, -1);
-
- if (context->ignore_sigpipe)
- ignore_signals(SIGPIPE, -1);
-
- r = reset_signal_mask();
- if (r < 0) {
- *exit_status = EXIT_SIGNAL_MASK;
- return r;
- }
-
- if (params->idle_pipe)
- do_idle_pipe_dance(params->idle_pipe);
-
- /* Close sockets very early to make sure we don't
- * block init reexecution because it cannot bind its
- * sockets */
-
- log_forget_fds();
-
- if (socket_fd >= 0)
- dont_close[n_dont_close++] = socket_fd;
- if (n_fds > 0) {
- memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds);
- n_dont_close += n_fds;
- }
- if (params->bus_endpoint_fd >= 0)
- dont_close[n_dont_close++] = params->bus_endpoint_fd;
- if (runtime) {
- if (runtime->netns_storage_socket[0] >= 0)
- dont_close[n_dont_close++] = runtime->netns_storage_socket[0];
- if (runtime->netns_storage_socket[1] >= 0)
- dont_close[n_dont_close++] = runtime->netns_storage_socket[1];
- }
-
- r = close_all_fds(dont_close, n_dont_close);
- if (r < 0) {
- *exit_status = EXIT_FDS;
- return r;
- }
-
- if (!context->same_pgrp)
- if (setsid() < 0) {
- *exit_status = EXIT_SETSID;
- return -errno;
- }
-
- exec_context_tty_reset(context);
-
- if (params->confirm_spawn) {
- char response;
-
- r = ask_for_confirmation(&response, argv);
- if (r == -ETIMEDOUT)
- write_confirm_message("Confirmation question timed out, assuming positive response.\n");
- else if (r < 0)
- write_confirm_message("Couldn't ask confirmation question, assuming positive response: %s\n", strerror(-r));
- else if (response == 's') {
- write_confirm_message("Skipping execution.\n");
- *exit_status = EXIT_CONFIRM;
- return -ECANCELED;
- } else if (response == 'n') {
- write_confirm_message("Failing execution.\n");
- *exit_status = 0;
- return 0;
- }
- }
-
- if (context->user) {
- username = context->user;
- r = get_user_creds(&username, &uid, &gid, &home, &shell);
- if (r < 0) {
- *exit_status = EXIT_USER;
- return r;
- }
- }
-
- /* If a socket is connected to STDIN/STDOUT/STDERR, we
- * must sure to drop O_NONBLOCK */
- if (socket_fd >= 0)
- fd_nonblock(socket_fd, false);
-
- r = setup_input(context, socket_fd, params->apply_tty_stdin);
- if (r < 0) {
- *exit_status = EXIT_STDIN;
- return r;
- }
-
- r = setup_output(context, STDOUT_FILENO, socket_fd, basename(command->path), params->unit_id, params->apply_tty_stdin, uid, gid);
- if (r < 0) {
- *exit_status = EXIT_STDOUT;
- return r;
- }
-
- r = setup_output(context, STDERR_FILENO, socket_fd, basename(command->path), params->unit_id, params->apply_tty_stdin, uid, gid);
- if (r < 0) {
- *exit_status = EXIT_STDERR;
- return r;
- }
-
- if (params->cgroup_path) {
- r = cg_attach_everywhere(params->cgroup_supported, params->cgroup_path, 0, NULL, NULL);
- if (r < 0) {
- *exit_status = EXIT_CGROUP;
- return r;
- }
- }
-
- 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);
- if (r == -EPERM || r == -EACCES) {
- log_open();
- log_unit_debug_errno(params->unit_id, r, "Failed to adjust OOM setting, assuming containerized execution, ignoring: %m");
- log_close();
- } else if (r < 0) {
- *exit_status = EXIT_OOM_ADJUST;
- return -errno;
- }
- }
-
- if (context->nice_set)
- if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) {
- *exit_status = EXIT_NICE;
- return -errno;
- }
-
- if (context->cpu_sched_set) {
- struct sched_param param = {
- .sched_priority = context->cpu_sched_priority,
- };
-
- r = sched_setscheduler(0,
- context->cpu_sched_policy |
- (context->cpu_sched_reset_on_fork ?
- SCHED_RESET_ON_FORK : 0),
- &param);
- if (r < 0) {
- *exit_status = EXIT_SETSCHEDULER;
- return -errno;
- }
- }
-
- if (context->cpuset)
- if (sched_setaffinity(0, CPU_ALLOC_SIZE(context->cpuset_ncpus), context->cpuset) < 0) {
- *exit_status = EXIT_CPUAFFINITY;
- return -errno;
- }
-
- if (context->ioprio_set)
- if (ioprio_set(IOPRIO_WHO_PROCESS, 0, context->ioprio) < 0) {
- *exit_status = EXIT_IOPRIO;
- return -errno;
- }
-
- if (context->timer_slack_nsec != NSEC_INFINITY)
- if (prctl(PR_SET_TIMERSLACK, context->timer_slack_nsec) < 0) {
- *exit_status = EXIT_TIMERSLACK;
- return -errno;
- }
-
- if (context->personality != 0xffffffffUL)
- if (personality(context->personality) < 0) {
- *exit_status = EXIT_PERSONALITY;
- return -errno;
- }
-
- if (context->utmp_id)
- utmp_put_init_process(context->utmp_id, getpid(), getsid(0), context->tty_path);
-
- if (context->user && is_terminal_input(context->std_input)) {
- r = chown_terminal(STDIN_FILENO, uid);
- if (r < 0) {
- *exit_status = EXIT_STDIN;
- return r;
- }
- }
-
-#ifdef ENABLE_KDBUS
- if (params->bus_endpoint_fd >= 0 && context->bus_endpoint) {
- uid_t ep_uid = (uid == UID_INVALID) ? 0 : uid;
-
- r = bus_kernel_set_endpoint_policy(params->bus_endpoint_fd, ep_uid, context->bus_endpoint);
- if (r < 0) {
- *exit_status = EXIT_BUS_ENDPOINT;
- return r;
- }
- }
-#endif
-
- /* If delegation is enabled we'll pass ownership of the cgroup
- * (but only in systemd's own controller hierarchy!) to the
- * user of the new process. */
- if (params->cgroup_path && context->user && params->cgroup_delegate) {
- r = cg_set_task_access(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, 0644, uid, gid);
- if (r < 0) {
- *exit_status = EXIT_CGROUP;
- return r;
- }
-
-
- r = cg_set_group_access(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, 0755, uid, gid);
- if (r < 0) {
- *exit_status = EXIT_CGROUP;
- return r;
- }
- }
-
- if (!strv_isempty(context->runtime_directory) && params->runtime_prefix) {
- char **rt;
-
- STRV_FOREACH(rt, context->runtime_directory) {
- _cleanup_free_ char *p;
-
- p = strjoin(params->runtime_prefix, "/", *rt, NULL);
- if (!p) {
- *exit_status = EXIT_RUNTIME_DIRECTORY;
- return -ENOMEM;
- }
-
- r = mkdir_safe_label(p, context->runtime_directory_mode, uid, gid);
- if (r < 0) {
- *exit_status = EXIT_RUNTIME_DIRECTORY;
- return r;
- }
- }
- }
-
- if (params->apply_permissions) {
- r = enforce_groups(context, username, gid);
- if (r < 0) {
- *exit_status = EXIT_GROUP;
- return r;
- }
- }
-
- umask(context->umask);
-
-#ifdef HAVE_PAM
- if (params->apply_permissions && context->pam_name && username) {
- r = setup_pam(context->pam_name, username, uid, context->tty_path, &pam_env, fds, n_fds);
- if (r < 0) {
- *exit_status = EXIT_PAM;
- return r;
- }
- }
-#endif
-
- if (context->private_network && runtime && runtime->netns_storage_socket[0] >= 0) {
- r = setup_netns(runtime->netns_storage_socket);
- if (r < 0) {
- *exit_status = EXIT_NETWORK;
- return r;
- }
- }
-
- if (!strv_isempty(context->read_write_dirs) ||
- !strv_isempty(context->read_only_dirs) ||
- !strv_isempty(context->inaccessible_dirs) ||
- context->mount_flags != 0 ||
- (context->private_tmp && runtime && (runtime->tmp_dir || runtime->var_tmp_dir)) ||
- params->bus_endpoint_path ||
- context->private_devices ||
- context->protect_system != PROTECT_SYSTEM_NO ||
- context->protect_home != PROTECT_HOME_NO) {
-
- char *tmp = NULL, *var = NULL;
-
- /* The runtime struct only contains the parent
- * of the private /tmp, which is
- * non-accessible to world users. Inside of it
- * there's a /tmp that is sticky, and that's
- * the one we want to use here. */
-
- if (context->private_tmp && runtime) {
- if (runtime->tmp_dir)
- tmp = strjoina(runtime->tmp_dir, "/tmp");
- if (runtime->var_tmp_dir)
- var = strjoina(runtime->var_tmp_dir, "/tmp");
- }
-
- r = setup_namespace(
- context->read_write_dirs,
- context->read_only_dirs,
- context->inaccessible_dirs,
- tmp,
- var,
- params->bus_endpoint_path,
- context->private_devices,
- context->protect_home,
- context->protect_system,
- context->mount_flags);
-
- /* If we couldn't set up the namespace this is
- * probably due to a missing capability. In this case,
- * silently proceeed. */
- if (r == -EPERM || r == -EACCES) {
- log_open();
- log_unit_debug_errno(params->unit_id, r, "Failed to set up namespace, assuming containerized execution, ignoring: %m");
- log_close();
- } else if (r < 0) {
- *exit_status = EXIT_NAMESPACE;
- return r;
- }
- }
-
- if (params->apply_chroot) {
- if (context->root_directory)
- if (chroot(context->root_directory) < 0) {
- *exit_status = EXIT_CHROOT;
- return -errno;
- }
-
- if (chdir(context->working_directory ?: "/") < 0 &&
- !context->working_directory_missing_ok) {
- *exit_status = EXIT_CHDIR;
- return -errno;
- }
- } else {
- _cleanup_free_ char *d = NULL;
-
- if (asprintf(&d, "%s/%s",
- context->root_directory ?: "",
- context->working_directory ?: "") < 0) {
- *exit_status = EXIT_MEMORY;
- return -ENOMEM;
- }
-
- if (chdir(d) < 0 &&
- !context->working_directory_missing_ok) {
- *exit_status = EXIT_CHDIR;
- return -errno;
- }
- }
-
-#ifdef HAVE_SELINUX
- if (params->apply_permissions && mac_selinux_use() && params->selinux_context_net && socket_fd >= 0) {
- r = mac_selinux_get_child_mls_label(socket_fd, command->path, context->selinux_context, &mac_selinux_context_net);
- if (r < 0) {
- *exit_status = EXIT_SELINUX_CONTEXT;
- return r;
- }
- }
-#endif
-
- /* We repeat the fd closing here, to make sure that
- * nothing is leaked from the PAM modules. Note that
- * we are more aggressive this time since socket_fd
- * and the netns fds we don't need anymore. The custom
- * endpoint fd was needed to upload the policy and can
- * now be closed as well. */
- r = close_all_fds(fds, n_fds);
- if (r >= 0)
- r = shift_fds(fds, n_fds);
- if (r >= 0)
- r = flags_fds(fds, n_fds, context->non_blocking);
- if (r < 0) {
- *exit_status = EXIT_FDS;
- return r;
- }
-
- if (params->apply_permissions) {
-
- for (i = 0; i < _RLIMIT_MAX; i++) {
- if (!context->rlimit[i])
- continue;
-
- if (setrlimit_closest(i, context->rlimit[i]) < 0) {
- *exit_status = EXIT_LIMITS;
- return -errno;
- }
- }
-
- if (context->capability_bounding_set_drop) {
- r = capability_bounding_set_drop(context->capability_bounding_set_drop, false);
- if (r < 0) {
- *exit_status = EXIT_CAPABILITIES;
- return r;
- }
- }
-
-#ifdef HAVE_SMACK
- if (context->smack_process_label) {
- r = mac_smack_apply_pid(0, context->smack_process_label);
- if (r < 0) {
- *exit_status = EXIT_SMACK_PROCESS_LABEL;
- return r;
- }
- }
-#endif
-
- if (context->user) {
- r = enforce_user(context, uid);
- if (r < 0) {
- *exit_status = EXIT_USER;
- return r;
- }
- }
-
- /* PR_GET_SECUREBITS is not privileged, while
- * PR_SET_SECUREBITS is. So to suppress
- * potential EPERMs we'll try not to call
- * PR_SET_SECUREBITS unless necessary. */
- if (prctl(PR_GET_SECUREBITS) != context->secure_bits)
- if (prctl(PR_SET_SECUREBITS, context->secure_bits) < 0) {
- *exit_status = EXIT_SECUREBITS;
- return -errno;
- }
-
- if (context->capabilities)
- if (cap_set_proc(context->capabilities) < 0) {
- *exit_status = EXIT_CAPABILITIES;
- return -errno;
- }
-
- if (context->no_new_privileges)
- if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
- *exit_status = EXIT_NO_NEW_PRIVILEGES;
- return -errno;
- }
-
-#ifdef HAVE_SECCOMP
- if (context->address_families_whitelist ||
- !set_isempty(context->address_families)) {
- r = apply_address_families(context);
- if (r < 0) {
- *exit_status = EXIT_ADDRESS_FAMILIES;
- return r;
- }
- }
-
- if (context->syscall_whitelist ||
- !set_isempty(context->syscall_filter) ||
- !set_isempty(context->syscall_archs)) {
- r = apply_seccomp(context);
- if (r < 0) {
- *exit_status = EXIT_SECCOMP;
- return r;
- }
- }
-#endif
-
-#ifdef HAVE_SELINUX
- if (mac_selinux_use()) {
- char *exec_context = mac_selinux_context_net ?: context->selinux_context;
-
- if (exec_context) {
- r = setexeccon(exec_context);
- if (r < 0) {
- *exit_status = EXIT_SELINUX_CONTEXT;
- return r;
- }
- }
- }
-#endif
-
-#ifdef HAVE_APPARMOR
- if (context->apparmor_profile && mac_apparmor_use()) {
- r = aa_change_onexec(context->apparmor_profile);
- if (r < 0 && !context->apparmor_profile_ignore) {
- *exit_status = EXIT_APPARMOR_PROFILE;
- return -errno;
- }
- }
-#endif
- }
-
- r = build_environment(context, n_fds, params->watchdog_usec, home, username, shell, &our_env);
- if (r < 0) {
- *exit_status = EXIT_MEMORY;
- return r;
- }
-
- final_env = strv_env_merge(5,
- params->environment,
- our_env,
- context->environment,
- files_env,
- pam_env,
- NULL);
- if (!final_env) {
- *exit_status = EXIT_MEMORY;
- return -ENOMEM;
- }
-
- final_argv = replace_env_argv(argv, final_env);
- if (!final_argv) {
- *exit_status = EXIT_MEMORY;
- return -ENOMEM;
- }
-
- final_env = strv_env_clean(final_env);
-
- if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
- _cleanup_free_ char *line;
-
- line = exec_command_line(final_argv);
- if (line) {
- log_open();
- log_unit_struct(params->unit_id,
- LOG_DEBUG,
- "EXECUTABLE=%s", command->path,
- LOG_MESSAGE("Executing: %s", line),
- NULL);
- log_close();
- }
- }
- execve(command->path, final_argv, final_env);
- *exit_status = EXIT_EXEC;
- return -errno;
-}
-
-int exec_spawn(ExecCommand *command,
- const ExecContext *context,
- const ExecParameters *params,
- ExecRuntime *runtime,
- pid_t *ret) {
-
- _cleanup_strv_free_ char **files_env = NULL;
- int *fds = NULL; unsigned n_fds = 0;
- _cleanup_free_ char *line = NULL;
- int socket_fd, r;
- char **argv;
- pid_t pid;
-
- assert(command);
- assert(context);
- assert(ret);
- assert(params);
- assert(params->fds || params->n_fds <= 0);
-
- if (context->std_input == EXEC_INPUT_SOCKET ||
- context->std_output == EXEC_OUTPUT_SOCKET ||
- context->std_error == EXEC_OUTPUT_SOCKET) {
-
- if (params->n_fds != 1) {
- log_unit_error(params->unit_id, "Got more than one socket.");
- return -EINVAL;
- }
-
- socket_fd = params->fds[0];
- } else {
- socket_fd = -1;
- fds = params->fds;
- n_fds = params->n_fds;
- }
-
- r = exec_context_load_environment(context, params->unit_id, &files_env);
- if (r < 0)
- return log_unit_error_errno(params->unit_id, r, "Failed to load environment files: %m");
-
- argv = params->argv ?: command->argv;
- line = exec_command_line(argv);
- if (!line)
- return log_oom();
-
- log_unit_struct(params->unit_id,
- LOG_DEBUG,
- "EXECUTABLE=%s", command->path,
- LOG_MESSAGE("About to execute: %s", line),
- NULL);
- pid = fork();
- if (pid < 0)
- return log_unit_error_errno(params->unit_id, r, "Failed to fork: %m");
-
- if (pid == 0) {
- int exit_status;
-
- r = exec_child(command,
- context,
- params,
- runtime,
- argv,
- socket_fd,
- fds, n_fds,
- files_env,
- &exit_status);
- if (r < 0) {
- log_open();
- log_unit_struct(params->unit_id,
- LOG_ERR,
- LOG_MESSAGE_ID(SD_MESSAGE_SPAWN_FAILED),
- "EXECUTABLE=%s", command->path,
- LOG_MESSAGE("Failed at step %s spawning %s: %s",
- exit_status_to_string(exit_status, EXIT_STATUS_SYSTEMD),
- command->path, strerror(-r)),
- LOG_ERRNO(r),
- NULL);
- }
-
- _exit(exit_status);
- }
-
- log_unit_debug(params->unit_id, "Forked %s as "PID_FMT, command->path, pid);
-
- /* We add the new process to the cgroup both in the child (so
- * that we can be sure that no user code is ever executed
- * outside of the cgroup) and in the parent (so that we can be
- * sure that when we kill the cgroup the process will be
- * killed too). */
- if (params->cgroup_path)
- cg_attach(SYSTEMD_CGROUP_CONTROLLER, params->cgroup_path, pid);
-
- exec_status_start(&command->exec_status, pid);
-
- *ret = pid;
- return 0;
-}
-
-void exec_context_init(ExecContext *c) {
- assert(c);
-
- c->umask = 0022;
- c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_CLASS_BE, 0);
- c->cpu_sched_policy = SCHED_OTHER;
- c->syslog_priority = LOG_DAEMON|LOG_INFO;
- c->syslog_level_prefix = true;
- c->ignore_sigpipe = true;
- c->timer_slack_nsec = NSEC_INFINITY;
- c->personality = 0xffffffffUL;
- c->runtime_directory_mode = 0755;
-}
-
-void exec_context_done(ExecContext *c) {
- unsigned l;
-
- assert(c);
-
- strv_free(c->environment);
- c->environment = NULL;
-
- strv_free(c->environment_files);
- c->environment_files = NULL;
-
- for (l = 0; l < ELEMENTSOF(c->rlimit); l++) {
- free(c->rlimit[l]);
- c->rlimit[l] = NULL;
- }
-
- free(c->working_directory);
- c->working_directory = NULL;
- free(c->root_directory);
- c->root_directory = NULL;
-
- free(c->tty_path);
- c->tty_path = NULL;
-
- free(c->syslog_identifier);
- c->syslog_identifier = NULL;
-
- free(c->user);
- c->user = NULL;
-
- free(c->group);
- c->group = NULL;
-
- strv_free(c->supplementary_groups);
- c->supplementary_groups = NULL;
-
- free(c->pam_name);
- c->pam_name = NULL;
-
- if (c->capabilities) {
- cap_free(c->capabilities);
- c->capabilities = NULL;
- }
-
- strv_free(c->read_only_dirs);
- c->read_only_dirs = NULL;
-
- strv_free(c->read_write_dirs);
- c->read_write_dirs = NULL;
-
- strv_free(c->inaccessible_dirs);
- c->inaccessible_dirs = NULL;
-
- if (c->cpuset)
- CPU_FREE(c->cpuset);
-
- free(c->utmp_id);
- c->utmp_id = NULL;
-
- free(c->selinux_context);
- c->selinux_context = NULL;
-
- free(c->apparmor_profile);
- c->apparmor_profile = NULL;
-
- set_free(c->syscall_filter);
- c->syscall_filter = NULL;
-
- set_free(c->syscall_archs);
- c->syscall_archs = NULL;
-
- set_free(c->address_families);
- c->address_families = NULL;
-
- strv_free(c->runtime_directory);
- c->runtime_directory = NULL;
-
- bus_endpoint_free(c->bus_endpoint);
- c->bus_endpoint = NULL;
-}
-
-int exec_context_destroy_runtime_directory(ExecContext *c, const char *runtime_prefix) {
- char **i;
-
- assert(c);
-
- if (!runtime_prefix)
- return 0;
-
- STRV_FOREACH(i, c->runtime_directory) {
- _cleanup_free_ char *p;
-
- p = strjoin(runtime_prefix, "/", *i, NULL);
- if (!p)
- return -ENOMEM;
-
- /* We execute this synchronously, since we need to be
- * sure this is gone when we start the service
- * next. */
- rm_rf(p, false, true, false);
- }
-
- return 0;
-}
-
-void exec_command_done(ExecCommand *c) {
- assert(c);
-
- free(c->path);
- c->path = NULL;
-
- strv_free(c->argv);
- c->argv = NULL;
-}
-
-void exec_command_done_array(ExecCommand *c, unsigned n) {
- unsigned i;
-
- for (i = 0; i < n; i++)
- exec_command_done(c+i);
-}
-
-ExecCommand* exec_command_free_list(ExecCommand *c) {
- ExecCommand *i;
-
- while ((i = c)) {
- LIST_REMOVE(command, c, i);
- exec_command_done(i);
- free(i);
- }
-
- return NULL;
-}
-
-void exec_command_free_array(ExecCommand **c, unsigned n) {
- unsigned i;
-
- for (i = 0; i < n; i++)
- c[i] = exec_command_free_list(c[i]);
-}
-
-typedef struct InvalidEnvInfo {
- const char *unit_id;
- const char *path;
-} InvalidEnvInfo;
-
-static void invalid_env(const char *p, void *userdata) {
- InvalidEnvInfo *info = userdata;
-
- log_unit_error(info->unit_id, "Ignoring invalid environment assignment '%s': %s", p, info->path);
-}
-
-int exec_context_load_environment(const ExecContext *c, const char *unit_id, char ***l) {
- char **i, **r = NULL;
-
- assert(c);
- assert(l);
-
- STRV_FOREACH(i, c->environment_files) {
- char *fn;
- int k;
- bool ignore = false;
- char **p;
- _cleanup_globfree_ glob_t pglob = {};
- int count, n;
-
- fn = *i;
-
- if (fn[0] == '-') {
- ignore = true;
- fn ++;
- }
-
- if (!path_is_absolute(fn)) {
- if (ignore)
- continue;
-
- strv_free(r);
- return -EINVAL;
- }
-
- /* Filename supports globbing, take all matching files */
- errno = 0;
- if (glob(fn, 0, NULL, &pglob) != 0) {
- if (ignore)
- continue;
-
- strv_free(r);
- return errno ? -errno : -EINVAL;
- }
- count = pglob.gl_pathc;
- if (count == 0) {
- if (ignore)
- continue;
-
- strv_free(r);
- return -EINVAL;
- }
- for (n = 0; n < count; n++) {
- k = load_env_file(NULL, pglob.gl_pathv[n], NULL, &p);
- if (k < 0) {
- if (ignore)
- continue;
-
- strv_free(r);
- return k;
- }
- /* Log invalid environment variables with filename */
- if (p) {
- InvalidEnvInfo info = {
- .unit_id = unit_id,
- .path = pglob.gl_pathv[n]
- };
-
- p = strv_env_clean_with_callback(p, invalid_env, &info);
- }
-
- if (r == NULL)
- r = p;
- else {
- char **m;
-
- m = strv_env_merge(2, r, p);
- strv_free(r);
- strv_free(p);
- if (!m)
- return -ENOMEM;
-
- r = m;
- }
- }
- }
-
- *l = r;
-
- return 0;
-}
-
-static bool tty_may_match_dev_console(const char *tty) {
- _cleanup_free_ char *active = NULL;
- char *console;
-
- if (startswith(tty, "/dev/"))
- tty += 5;
-
- /* trivial identity? */
- if (streq(tty, "console"))
- return true;
-
- console = resolve_dev_console(&active);
- /* if we could not resolve, assume it may */
- if (!console)
- return true;
-
- /* "tty0" means the active VC, so it may be the same sometimes */
- return streq(console, tty) || (streq(console, "tty0") && tty_is_vc(tty));
-}
-
-bool exec_context_may_touch_console(ExecContext *ec) {
- return (ec->tty_reset || ec->tty_vhangup || ec->tty_vt_disallocate ||
- is_terminal_input(ec->std_input) ||
- is_terminal_output(ec->std_output) ||
- is_terminal_output(ec->std_error)) &&
- tty_may_match_dev_console(tty_path(ec));
-}
-
-static void strv_fprintf(FILE *f, char **l) {
- char **g;
-
- assert(f);
-
- STRV_FOREACH(g, l)
- fprintf(f, " %s", *g);
-}
-
-void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
- char **e;
- unsigned i;
-
- assert(c);
- assert(f);
-
- prefix = strempty(prefix);
-
- fprintf(f,
- "%sUMask: %04o\n"
- "%sWorkingDirectory: %s\n"
- "%sRootDirectory: %s\n"
- "%sNonBlocking: %s\n"
- "%sPrivateTmp: %s\n"
- "%sPrivateNetwork: %s\n"
- "%sPrivateDevices: %s\n"
- "%sProtectHome: %s\n"
- "%sProtectSystem: %s\n"
- "%sIgnoreSIGPIPE: %s\n",
- prefix, c->umask,
- prefix, c->working_directory ? c->working_directory : "/",
- prefix, c->root_directory ? c->root_directory : "/",
- prefix, yes_no(c->non_blocking),
- prefix, yes_no(c->private_tmp),
- prefix, yes_no(c->private_network),
- prefix, yes_no(c->private_devices),
- prefix, protect_home_to_string(c->protect_home),
- prefix, protect_system_to_string(c->protect_system),
- prefix, yes_no(c->ignore_sigpipe));
-
- STRV_FOREACH(e, c->environment)
- fprintf(f, "%sEnvironment: %s\n", prefix, *e);
-
- STRV_FOREACH(e, c->environment_files)
- fprintf(f, "%sEnvironmentFile: %s\n", prefix, *e);
-
- if (c->nice_set)
- fprintf(f,
- "%sNice: %i\n",
- prefix, c->nice);
-
- if (c->oom_score_adjust_set)
- fprintf(f,
- "%sOOMScoreAdjust: %i\n",
- prefix, c->oom_score_adjust);
-
- for (i = 0; i < RLIM_NLIMITS; i++)
- if (c->rlimit[i])
- fprintf(f, "%s%s: "RLIM_FMT"\n",
- prefix, rlimit_to_string(i), c->rlimit[i]->rlim_max);
-
- if (c->ioprio_set) {
- _cleanup_free_ char *class_str = NULL;
-
- ioprio_class_to_string_alloc(IOPRIO_PRIO_CLASS(c->ioprio), &class_str);
- fprintf(f,
- "%sIOSchedulingClass: %s\n"
- "%sIOPriority: %i\n",
- prefix, strna(class_str),
- prefix, (int) IOPRIO_PRIO_DATA(c->ioprio));
- }
-
- if (c->cpu_sched_set) {
- _cleanup_free_ char *policy_str = NULL;
-
- sched_policy_to_string_alloc(c->cpu_sched_policy, &policy_str);
- fprintf(f,
- "%sCPUSchedulingPolicy: %s\n"
- "%sCPUSchedulingPriority: %i\n"
- "%sCPUSchedulingResetOnFork: %s\n",
- prefix, strna(policy_str),
- prefix, c->cpu_sched_priority,
- prefix, yes_no(c->cpu_sched_reset_on_fork));
- }
-
- if (c->cpuset) {
- fprintf(f, "%sCPUAffinity:", prefix);
- for (i = 0; i < c->cpuset_ncpus; i++)
- if (CPU_ISSET_S(i, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset))
- fprintf(f, " %u", i);
- fputs("\n", f);
- }
-
- if (c->timer_slack_nsec != NSEC_INFINITY)
- fprintf(f, "%sTimerSlackNSec: "NSEC_FMT "\n", prefix, c->timer_slack_nsec);
-
- fprintf(f,
- "%sStandardInput: %s\n"
- "%sStandardOutput: %s\n"
- "%sStandardError: %s\n",
- prefix, exec_input_to_string(c->std_input),
- prefix, exec_output_to_string(c->std_output),
- prefix, exec_output_to_string(c->std_error));
-
- if (c->tty_path)
- fprintf(f,
- "%sTTYPath: %s\n"
- "%sTTYReset: %s\n"
- "%sTTYVHangup: %s\n"
- "%sTTYVTDisallocate: %s\n",
- prefix, c->tty_path,
- prefix, yes_no(c->tty_reset),
- prefix, yes_no(c->tty_vhangup),
- prefix, yes_no(c->tty_vt_disallocate));
-
- if (c->std_output == EXEC_OUTPUT_SYSLOG ||
- c->std_output == EXEC_OUTPUT_KMSG ||
- c->std_output == EXEC_OUTPUT_JOURNAL ||
- c->std_output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE ||
- c->std_output == EXEC_OUTPUT_KMSG_AND_CONSOLE ||
- c->std_output == EXEC_OUTPUT_JOURNAL_AND_CONSOLE ||
- c->std_error == EXEC_OUTPUT_SYSLOG ||
- c->std_error == EXEC_OUTPUT_KMSG ||
- c->std_error == EXEC_OUTPUT_JOURNAL ||
- c->std_error == EXEC_OUTPUT_SYSLOG_AND_CONSOLE ||
- c->std_error == EXEC_OUTPUT_KMSG_AND_CONSOLE ||
- c->std_error == EXEC_OUTPUT_JOURNAL_AND_CONSOLE) {
-
- _cleanup_free_ char *fac_str = NULL, *lvl_str = NULL;
-
- log_facility_unshifted_to_string_alloc(c->syslog_priority >> 3, &fac_str);
- log_level_to_string_alloc(LOG_PRI(c->syslog_priority), &lvl_str);
-
- fprintf(f,
- "%sSyslogFacility: %s\n"
- "%sSyslogLevel: %s\n",
- prefix, strna(fac_str),
- prefix, strna(lvl_str));
- }
-
- if (c->capabilities) {
- _cleanup_cap_free_charp_ char *t;
-
- t = cap_to_text(c->capabilities, NULL);
- if (t)
- fprintf(f, "%sCapabilities: %s\n", prefix, t);
- }
-
- if (c->secure_bits)
- fprintf(f, "%sSecure Bits:%s%s%s%s%s%s\n",
- prefix,
- (c->secure_bits & 1<<SECURE_KEEP_CAPS) ? " keep-caps" : "",
- (c->secure_bits & 1<<SECURE_KEEP_CAPS_LOCKED) ? " keep-caps-locked" : "",
- (c->secure_bits & 1<<SECURE_NO_SETUID_FIXUP) ? " no-setuid-fixup" : "",
- (c->secure_bits & 1<<SECURE_NO_SETUID_FIXUP_LOCKED) ? " no-setuid-fixup-locked" : "",
- (c->secure_bits & 1<<SECURE_NOROOT) ? " noroot" : "",
- (c->secure_bits & 1<<SECURE_NOROOT_LOCKED) ? "noroot-locked" : "");
-
- if (c->capability_bounding_set_drop) {
- unsigned long l;
- fprintf(f, "%sCapabilityBoundingSet:", prefix);
-
- for (l = 0; l <= cap_last_cap(); l++)
- if (!(c->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) l)))
- fprintf(f, " %s", strna(capability_to_name(l)));
-
- fputs("\n", f);
- }
-
- if (c->user)
- fprintf(f, "%sUser: %s\n", prefix, c->user);
- if (c->group)
- fprintf(f, "%sGroup: %s\n", prefix, c->group);
-
- if (strv_length(c->supplementary_groups) > 0) {
- fprintf(f, "%sSupplementaryGroups:", prefix);
- strv_fprintf(f, c->supplementary_groups);
- fputs("\n", f);
- }
-
- if (c->pam_name)
- fprintf(f, "%sPAMName: %s\n", prefix, c->pam_name);
-
- if (strv_length(c->read_write_dirs) > 0) {
- fprintf(f, "%sReadWriteDirs:", prefix);
- strv_fprintf(f, c->read_write_dirs);
- fputs("\n", f);
- }
-
- if (strv_length(c->read_only_dirs) > 0) {
- fprintf(f, "%sReadOnlyDirs:", prefix);
- strv_fprintf(f, c->read_only_dirs);
- fputs("\n", f);
- }
-
- if (strv_length(c->inaccessible_dirs) > 0) {
- fprintf(f, "%sInaccessibleDirs:", prefix);
- strv_fprintf(f, c->inaccessible_dirs);
- fputs("\n", f);
- }
-
- if (c->utmp_id)
- fprintf(f,
- "%sUtmpIdentifier: %s\n",
- prefix, c->utmp_id);
-
- if (c->selinux_context)
- fprintf(f,
- "%sSELinuxContext: %s%s\n",
- prefix, c->selinux_context_ignore ? "-" : "", c->selinux_context);
-
- if (c->personality != 0xffffffffUL)
- fprintf(f,
- "%sPersonality: %s\n",
- prefix, strna(personality_to_string(c->personality)));
-
- if (c->syscall_filter) {
-#ifdef HAVE_SECCOMP
- Iterator j;
- void *id;
- bool first = true;
-#endif
-
- fprintf(f,
- "%sSystemCallFilter: ",
- prefix);
-
- if (!c->syscall_whitelist)
- fputc('~', f);
-
-#ifdef HAVE_SECCOMP
- SET_FOREACH(id, c->syscall_filter, j) {
- _cleanup_free_ char *name = NULL;
-
- if (first)
- first = false;
- else
- fputc(' ', f);
-
- name = seccomp_syscall_resolve_num_arch(SCMP_ARCH_NATIVE, PTR_TO_INT(id) - 1);
- fputs(strna(name), f);
- }
-#endif
-
- fputc('\n', f);
- }
-
- if (c->syscall_archs) {
-#ifdef HAVE_SECCOMP
- Iterator j;
- void *id;
-#endif
-
- fprintf(f,
- "%sSystemCallArchitectures:",
- prefix);
-
-#ifdef HAVE_SECCOMP
- SET_FOREACH(id, c->syscall_archs, j)
- fprintf(f, " %s", strna(seccomp_arch_to_string(PTR_TO_UINT32(id) - 1)));
-#endif
- fputc('\n', f);
- }
-
- if (c->syscall_errno != 0)
- fprintf(f,
- "%sSystemCallErrorNumber: %s\n",
- prefix, strna(errno_to_name(c->syscall_errno)));
-
- if (c->apparmor_profile)
- fprintf(f,
- "%sAppArmorProfile: %s%s\n",
- prefix, c->apparmor_profile_ignore ? "-" : "", c->apparmor_profile);
-}
-
-bool exec_context_maintains_privileges(ExecContext *c) {
- assert(c);
-
- /* Returns true if the process forked off would run run under
- * an unchanged UID or as root. */
-
- if (!c->user)
- return true;
-
- if (streq(c->user, "root") || streq(c->user, "0"))
- return true;
-
- return false;
-}
-
-void exec_status_start(ExecStatus *s, pid_t pid) {
- assert(s);
-
- zero(*s);
- s->pid = pid;
- dual_timestamp_get(&s->start_timestamp);
-}
-
-void exec_status_exit(ExecStatus *s, ExecContext *context, pid_t pid, int code, int status) {
- assert(s);
-
- if (s->pid && s->pid != pid)
- zero(*s);
-
- s->pid = pid;
- dual_timestamp_get(&s->exit_timestamp);
-
- s->code = code;
- s->status = status;
-
- if (context) {
- if (context->utmp_id)
- utmp_put_dead_process(context->utmp_id, pid, code, status);
-
- exec_context_tty_reset(context);
- }
-}
-
-void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix) {
- char buf[FORMAT_TIMESTAMP_MAX];
-
- assert(s);
- assert(f);
-
- if (s->pid <= 0)
- return;
-
- prefix = strempty(prefix);
-
- fprintf(f,
- "%sPID: "PID_FMT"\n",
- prefix, s->pid);
-
- if (s->start_timestamp.realtime > 0)
- fprintf(f,
- "%sStart Timestamp: %s\n",
- prefix, format_timestamp(buf, sizeof(buf), s->start_timestamp.realtime));
-
- if (s->exit_timestamp.realtime > 0)
- fprintf(f,
- "%sExit Timestamp: %s\n"
- "%sExit Code: %s\n"
- "%sExit Status: %i\n",
- prefix, format_timestamp(buf, sizeof(buf), s->exit_timestamp.realtime),
- prefix, sigchld_code_to_string(s->code),
- prefix, s->status);
-}
-
-char *exec_command_line(char **argv) {
- size_t k;
- char *n, *p, **a;
- bool first = true;
-
- assert(argv);
-
- k = 1;
- STRV_FOREACH(a, argv)
- k += strlen(*a)+3;
-
- if (!(n = new(char, k)))
- return NULL;
-
- p = n;
- STRV_FOREACH(a, argv) {
-
- if (!first)
- *(p++) = ' ';
- else
- first = false;
-
- if (strpbrk(*a, WHITESPACE)) {
- *(p++) = '\'';
- p = stpcpy(p, *a);
- *(p++) = '\'';
- } else
- p = stpcpy(p, *a);
-
- }
-
- *p = 0;
-
- /* FIXME: this doesn't really handle arguments that have
- * spaces and ticks in them */
-
- return n;
-}
-
-void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix) {
- _cleanup_free_ char *cmd = NULL;
- const char *prefix2;
-
- assert(c);
- assert(f);
-
- prefix = strempty(prefix);
- prefix2 = strjoina(prefix, "\t");
-
- cmd = exec_command_line(c->argv);
- fprintf(f,
- "%sCommand Line: %s\n",
- prefix, cmd ? cmd : strerror(ENOMEM));
-
- exec_status_dump(&c->exec_status, f, prefix2);
-}
-
-void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix) {
- assert(f);
-
- prefix = strempty(prefix);
-
- LIST_FOREACH(command, c, c)
- exec_command_dump(c, f, prefix);
-}
-
-void exec_command_append_list(ExecCommand **l, ExecCommand *e) {
- ExecCommand *end;
-
- assert(l);
- assert(e);
-
- if (*l) {
- /* It's kind of important, that we keep the order here */
- LIST_FIND_TAIL(command, *l, end);
- LIST_INSERT_AFTER(command, *l, end, e);
- } else
- *l = e;
-}
-
-int exec_command_set(ExecCommand *c, const char *path, ...) {
- va_list ap;
- char **l, *p;
-
- assert(c);
- assert(path);
-
- va_start(ap, path);
- l = strv_new_ap(path, ap);
- va_end(ap);
-
- if (!l)
- return -ENOMEM;
-
- p = strdup(path);
- if (!p) {
- strv_free(l);
- return -ENOMEM;
- }
-
- free(c->path);
- c->path = p;
-
- strv_free(c->argv);
- c->argv = l;
-
- return 0;
-}
-
-int exec_command_append(ExecCommand *c, const char *path, ...) {
- _cleanup_strv_free_ char **l = NULL;
- va_list ap;
- int r;
-
- assert(c);
- assert(path);
-
- va_start(ap, path);
- l = strv_new_ap(path, ap);
- va_end(ap);
-
- if (!l)
- return -ENOMEM;
-
- r = strv_extend_strv(&c->argv, l);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-
-static int exec_runtime_allocate(ExecRuntime **rt) {
-
- if (*rt)
- return 0;
-
- *rt = new0(ExecRuntime, 1);
- if (!*rt)
- return -ENOMEM;
-
- (*rt)->n_ref = 1;
- (*rt)->netns_storage_socket[0] = (*rt)->netns_storage_socket[1] = -1;
-
- return 0;
-}
-
-int exec_runtime_make(ExecRuntime **rt, ExecContext *c, const char *id) {
- int r;
-
- assert(rt);
- assert(c);
- assert(id);
-
- if (*rt)
- return 1;
-
- if (!c->private_network && !c->private_tmp)
- return 0;
-
- r = exec_runtime_allocate(rt);
- if (r < 0)
- return r;
-
- if (c->private_network && (*rt)->netns_storage_socket[0] < 0) {
- if (socketpair(AF_UNIX, SOCK_DGRAM, 0, (*rt)->netns_storage_socket) < 0)
- return -errno;
- }
-
- if (c->private_tmp && !(*rt)->tmp_dir) {
- r = setup_tmp_dirs(id, &(*rt)->tmp_dir, &(*rt)->var_tmp_dir);
- if (r < 0)
- return r;
- }
-
- return 1;
-}
-
-ExecRuntime *exec_runtime_ref(ExecRuntime *r) {
- assert(r);
- assert(r->n_ref > 0);
-
- r->n_ref++;
- return r;
-}
-
-ExecRuntime *exec_runtime_unref(ExecRuntime *r) {
-
- if (!r)
- return NULL;
-
- assert(r->n_ref > 0);
-
- r->n_ref--;
- if (r->n_ref <= 0) {
- free(r->tmp_dir);
- free(r->var_tmp_dir);
- safe_close_pair(r->netns_storage_socket);
- free(r);
- }
-
- return NULL;
-}
-
-int exec_runtime_serialize(ExecRuntime *rt, Unit *u, FILE *f, FDSet *fds) {
- assert(u);
- assert(f);
- assert(fds);
-
- if (!rt)
- return 0;
-
- if (rt->tmp_dir)
- unit_serialize_item(u, f, "tmp-dir", rt->tmp_dir);
-
- if (rt->var_tmp_dir)
- unit_serialize_item(u, f, "var-tmp-dir", rt->var_tmp_dir);
-
- if (rt->netns_storage_socket[0] >= 0) {
- int copy;
-
- copy = fdset_put_dup(fds, rt->netns_storage_socket[0]);
- if (copy < 0)
- return copy;
-
- unit_serialize_item_format(u, f, "netns-socket-0", "%i", copy);
- }
-
- if (rt->netns_storage_socket[1] >= 0) {
- int copy;
-
- copy = fdset_put_dup(fds, rt->netns_storage_socket[1]);
- if (copy < 0)
- return copy;
-
- unit_serialize_item_format(u, f, "netns-socket-1", "%i", copy);
- }
-
- return 0;
-}
-
-int exec_runtime_deserialize_item(ExecRuntime **rt, Unit *u, const char *key, const char *value, FDSet *fds) {
- int r;
-
- assert(rt);
- assert(key);
- assert(value);
-
- if (streq(key, "tmp-dir")) {
- char *copy;
-
- r = exec_runtime_allocate(rt);
- if (r < 0)
- return r;
-
- copy = strdup(value);
- if (!copy)
- return log_oom();
-
- free((*rt)->tmp_dir);
- (*rt)->tmp_dir = copy;
-
- } else if (streq(key, "var-tmp-dir")) {
- char *copy;
-
- r = exec_runtime_allocate(rt);
- if (r < 0)
- return r;
-
- copy = strdup(value);
- if (!copy)
- return log_oom();
-
- free((*rt)->var_tmp_dir);
- (*rt)->var_tmp_dir = copy;
-
- } else if (streq(key, "netns-socket-0")) {
- int fd;
-
- r = exec_runtime_allocate(rt);
- if (r < 0)
- return r;
-
- if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u->id, "Failed to parse netns socket value %s", value);
- else {
- safe_close((*rt)->netns_storage_socket[0]);
- (*rt)->netns_storage_socket[0] = fdset_remove(fds, fd);
- }
- } else if (streq(key, "netns-socket-1")) {
- int fd;
-
- r = exec_runtime_allocate(rt);
- if (r < 0)
- return r;
-
- if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u->id, "Failed to parse netns socket value %s", value);
- else {
- safe_close((*rt)->netns_storage_socket[1]);
- (*rt)->netns_storage_socket[1] = fdset_remove(fds, fd);
- }
- } else
- return 0;
-
- return 1;
-}
-
-static void *remove_tmpdir_thread(void *p) {
- _cleanup_free_ char *path = p;
-
- rm_rf_dangerous(path, false, true, false);
- return NULL;
-}
-
-void exec_runtime_destroy(ExecRuntime *rt) {
- int r;
-
- if (!rt)
- return;
-
- /* If there are multiple users of this, let's leave the stuff around */
- if (rt->n_ref > 1)
- return;
-
- if (rt->tmp_dir) {
- log_debug("Spawning thread to nuke %s", rt->tmp_dir);
-
- r = asynchronous_job(remove_tmpdir_thread, rt->tmp_dir);
- if (r < 0) {
- log_warning_errno(r, "Failed to nuke %s: %m", rt->tmp_dir);
- free(rt->tmp_dir);
- }
-
- rt->tmp_dir = NULL;
- }
-
- if (rt->var_tmp_dir) {
- log_debug("Spawning thread to nuke %s", rt->var_tmp_dir);
-
- r = asynchronous_job(remove_tmpdir_thread, rt->var_tmp_dir);
- if (r < 0) {
- log_warning_errno(r, "Failed to nuke %s: %m", rt->var_tmp_dir);
- free(rt->var_tmp_dir);
- }
-
- rt->var_tmp_dir = NULL;
- }
-
- safe_close_pair(rt->netns_storage_socket);
-}
-
-static const char* const exec_input_table[_EXEC_INPUT_MAX] = {
- [EXEC_INPUT_NULL] = "null",
- [EXEC_INPUT_TTY] = "tty",
- [EXEC_INPUT_TTY_FORCE] = "tty-force",
- [EXEC_INPUT_TTY_FAIL] = "tty-fail",
- [EXEC_INPUT_SOCKET] = "socket"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(exec_input, ExecInput);
-
-static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = {
- [EXEC_OUTPUT_INHERIT] = "inherit",
- [EXEC_OUTPUT_NULL] = "null",
- [EXEC_OUTPUT_TTY] = "tty",
- [EXEC_OUTPUT_SYSLOG] = "syslog",
- [EXEC_OUTPUT_SYSLOG_AND_CONSOLE] = "syslog+console",
- [EXEC_OUTPUT_KMSG] = "kmsg",
- [EXEC_OUTPUT_KMSG_AND_CONSOLE] = "kmsg+console",
- [EXEC_OUTPUT_JOURNAL] = "journal",
- [EXEC_OUTPUT_JOURNAL_AND_CONSOLE] = "journal+console",
- [EXEC_OUTPUT_SOCKET] = "socket"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput);
diff --git a/src/core/execute.h b/src/core/execute.h
deleted file mode 100644
index 1a43ac77b..000000000
--- a/src/core/execute.h
+++ /dev/null
@@ -1,267 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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;
-typedef struct ExecRuntime ExecRuntime;
-typedef struct ExecParameters ExecParameters;
-
-#include <sys/capability.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <sched.h>
-
-#include "list.h"
-#include "fdset.h"
-#include "missing.h"
-#include "namespace.h"
-#include "bus-endpoint.h"
-
-typedef enum ExecInput {
- EXEC_INPUT_NULL,
- EXEC_INPUT_TTY,
- EXEC_INPUT_TTY_FORCE,
- EXEC_INPUT_TTY_FAIL,
- EXEC_INPUT_SOCKET,
- _EXEC_INPUT_MAX,
- _EXEC_INPUT_INVALID = -1
-} ExecInput;
-
-typedef enum ExecOutput {
- EXEC_OUTPUT_INHERIT,
- EXEC_OUTPUT_NULL,
- EXEC_OUTPUT_TTY,
- EXEC_OUTPUT_SYSLOG,
- EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
- EXEC_OUTPUT_KMSG,
- EXEC_OUTPUT_KMSG_AND_CONSOLE,
- EXEC_OUTPUT_JOURNAL,
- EXEC_OUTPUT_JOURNAL_AND_CONSOLE,
- EXEC_OUTPUT_SOCKET,
- _EXEC_OUTPUT_MAX,
- _EXEC_OUTPUT_INVALID = -1
-} ExecOutput;
-
-struct ExecStatus {
- dual_timestamp start_timestamp;
- dual_timestamp exit_timestamp;
- pid_t pid;
- int code; /* as in siginfo_t::si_code */
- int status; /* as in sigingo_t::si_status */
-};
-
-struct ExecCommand {
- char *path;
- char **argv;
- ExecStatus exec_status;
- LIST_FIELDS(ExecCommand, command); /* useful for chaining commands */
- bool ignore;
-};
-
-struct ExecRuntime {
- int n_ref;
-
- char *tmp_dir;
- char *var_tmp_dir;
-
- int netns_storage_socket[2];
-};
-
-struct ExecContext {
- char **environment;
- char **environment_files;
-
- struct rlimit *rlimit[_RLIMIT_MAX];
- char *working_directory, *root_directory;
- bool working_directory_missing_ok;
-
- mode_t umask;
- int oom_score_adjust;
- int nice;
- int ioprio;
- int cpu_sched_policy;
- int cpu_sched_priority;
-
- cpu_set_t *cpuset;
- unsigned cpuset_ncpus;
-
- ExecInput std_input;
- ExecOutput std_output;
- ExecOutput std_error;
-
- nsec_t timer_slack_nsec;
-
- char *tty_path;
-
- bool tty_reset;
- bool tty_vhangup;
- bool tty_vt_disallocate;
-
- bool ignore_sigpipe;
-
- /* Since resolving these names might might involve socket
- * connections and we don't want to deadlock ourselves these
- * names are resolved on execution only and in the child
- * process. */
- char *user;
- char *group;
- char **supplementary_groups;
-
- char *pam_name;
-
- char *utmp_id;
-
- bool selinux_context_ignore;
- char *selinux_context;
-
- bool apparmor_profile_ignore;
- char *apparmor_profile;
-
- bool smack_process_label_ignore;
- char *smack_process_label;
-
- char **read_write_dirs, **read_only_dirs, **inaccessible_dirs;
- unsigned long mount_flags;
-
- uint64_t capability_bounding_set_drop;
-
- cap_t capabilities;
- int secure_bits;
-
- int syslog_priority;
- char *syslog_identifier;
- bool syslog_level_prefix;
-
- bool cpu_sched_reset_on_fork;
- bool non_blocking;
- bool private_tmp;
- bool private_network;
- bool private_devices;
- ProtectSystem protect_system;
- ProtectHome protect_home;
-
- bool no_new_privileges;
-
- /* This is not exposed to the user but available
- * internally. We need it to make sure that whenever we spawn
- * /bin/mount it is run in the same process group as us so
- * that the autofs logic detects that it belongs to us and we
- * don't enter a trigger loop. */
- bool same_pgrp;
-
- unsigned long personality;
-
- Set *syscall_filter;
- Set *syscall_archs;
- int syscall_errno;
- bool syscall_whitelist:1;
-
- Set *address_families;
- bool address_families_whitelist:1;
-
- char **runtime_directory;
- mode_t runtime_directory_mode;
-
- bool oom_score_adjust_set:1;
- bool nice_set:1;
- bool ioprio_set:1;
- bool cpu_sched_set:1;
- bool no_new_privileges_set:1;
-
- /* custom dbus enpoint */
- BusEndpoint *bus_endpoint;
-};
-
-#include "cgroup.h"
-#include "cgroup-util.h"
-
-struct ExecParameters {
- char **argv;
- int *fds; unsigned n_fds;
- char **environment;
- bool apply_permissions;
- bool apply_chroot;
- bool apply_tty_stdin;
- bool confirm_spawn;
- bool selinux_context_net;
- CGroupControllerMask cgroup_supported;
- const char *cgroup_path;
- bool cgroup_delegate;
- const char *runtime_prefix;
- const char *unit_id;
- usec_t watchdog_usec;
- int *idle_pipe;
- char *bus_endpoint_path;
- int bus_endpoint_fd;
-};
-
-int exec_spawn(ExecCommand *command,
- const ExecContext *context,
- const ExecParameters *exec_params,
- ExecRuntime *runtime,
- pid_t *ret);
-
-void exec_command_done(ExecCommand *c);
-void exec_command_done_array(ExecCommand *c, unsigned n);
-
-ExecCommand* exec_command_free_list(ExecCommand *c);
-void exec_command_free_array(ExecCommand **c, unsigned n);
-
-char *exec_command_line(char **argv);
-
-void exec_command_dump(ExecCommand *c, FILE *f, const char *prefix);
-void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix);
-void exec_command_append_list(ExecCommand **l, ExecCommand *e);
-int exec_command_set(ExecCommand *c, const char *path, ...);
-int exec_command_append(ExecCommand *c, const char *path, ...);
-
-void exec_context_init(ExecContext *c);
-void exec_context_done(ExecContext *c);
-void exec_context_dump(ExecContext *c, FILE* f, const char *prefix);
-
-int exec_context_destroy_runtime_directory(ExecContext *c, const char *runtime_root);
-
-int exec_context_load_environment(const ExecContext *c, const char *unit_id, char ***l);
-
-bool exec_context_may_touch_console(ExecContext *c);
-bool exec_context_maintains_privileges(ExecContext *c);
-
-void exec_status_start(ExecStatus *s, pid_t pid);
-void exec_status_exit(ExecStatus *s, ExecContext *context, pid_t pid, int code, int status);
-void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix);
-
-int exec_runtime_make(ExecRuntime **rt, ExecContext *c, const char *id);
-ExecRuntime *exec_runtime_ref(ExecRuntime *r);
-ExecRuntime *exec_runtime_unref(ExecRuntime *r);
-
-int exec_runtime_serialize(ExecRuntime *rt, Unit *u, FILE *f, FDSet *fds);
-int exec_runtime_deserialize_item(ExecRuntime **rt, Unit *u, const char *key, const char *value, FDSet *fds);
-
-void exec_runtime_destroy(ExecRuntime *rt);
-
-const char* exec_output_to_string(ExecOutput i) _const_;
-ExecOutput exec_output_from_string(const char *s) _pure_;
-
-const char* exec_input_to_string(ExecInput i) _const_;
-ExecInput exec_input_from_string(const char *s) _pure_;
diff --git a/src/core/failure-action.c b/src/core/failure-action.c
deleted file mode 100644
index ffeb5cd31..000000000
--- a/src/core/failure-action.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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/>.
-***/
-
-#include <sys/reboot.h>
-#include <linux/reboot.h>
-
-#include "bus-util.h"
-#include "bus-error.h"
-#include "special.h"
-#include "failure-action.h"
-
-static void log_and_status(Manager *m, const char *message) {
- log_warning("%s", message);
- manager_status_printf(m, STATUS_TYPE_EMERGENCY,
- ANSI_HIGHLIGHT_RED_ON " !! " ANSI_HIGHLIGHT_OFF,
- "%s", message);
-}
-
-int failure_action(
- Manager *m,
- FailureAction action,
- const char *reboot_arg) {
-
- int r;
-
- assert(m);
- assert(action >= 0);
- assert(action < _FAILURE_ACTION_MAX);
-
- if (action == FAILURE_ACTION_NONE)
- return -ECANCELED;
-
- if (m->running_as == SYSTEMD_USER) {
- /* Downgrade all options to simply exiting if we run
- * in user mode */
-
- log_warning("Exiting as result of failure.");
- m->exit_code = MANAGER_EXIT;
- return -ECANCELED;
- }
-
- switch (action) {
-
- case FAILURE_ACTION_REBOOT: {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-
- log_and_status(m, "Rebooting as result of failure.");
-
- update_reboot_param_file(reboot_arg);
- r = manager_add_job_by_name(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE, true, &error, NULL);
- if (r < 0)
- log_error("Failed to reboot: %s.", bus_error_message(&error, r));
-
- break;
- }
-
- case FAILURE_ACTION_REBOOT_FORCE:
- log_and_status(m, "Forcibly rebooting as result of failure.");
-
- update_reboot_param_file(reboot_arg);
- m->exit_code = MANAGER_REBOOT;
- break;
-
- case FAILURE_ACTION_REBOOT_IMMEDIATE:
- log_and_status(m, "Rebooting immediately as result of failure.");
-
- sync();
-
- if (reboot_arg) {
- log_info("Rebooting with argument '%s'.", reboot_arg);
- syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, reboot_arg);
- }
-
- log_info("Rebooting.");
- reboot(RB_AUTOBOOT);
- break;
-
- case FAILURE_ACTION_POWEROFF: {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-
- log_and_status(m, "Powering off as result of failure.");
-
- r = manager_add_job_by_name(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE, true, &error, NULL);
- if (r < 0)
- log_error("Failed to poweroff: %s.", bus_error_message(&error, r));
-
- break;
- }
-
- case FAILURE_ACTION_POWEROFF_FORCE:
- log_and_status(m, "Forcibly powering off as result of failure.");
- m->exit_code = MANAGER_POWEROFF;
- break;
-
- case FAILURE_ACTION_POWEROFF_IMMEDIATE:
- log_and_status(m, "Powering off immediately as result of failure.");
-
- sync();
-
- log_info("Powering off.");
- reboot(RB_POWER_OFF);
- break;
-
- default:
- assert_not_reached("Unknown failure action");
- }
-
- return -ECANCELED;
-}
-
-static const char* const failure_action_table[_FAILURE_ACTION_MAX] = {
- [FAILURE_ACTION_NONE] = "none",
- [FAILURE_ACTION_REBOOT] = "reboot",
- [FAILURE_ACTION_REBOOT_FORCE] = "reboot-force",
- [FAILURE_ACTION_REBOOT_IMMEDIATE] = "reboot-immediate",
- [FAILURE_ACTION_POWEROFF] = "poweroff",
- [FAILURE_ACTION_POWEROFF_FORCE] = "poweroff-force",
- [FAILURE_ACTION_POWEROFF_IMMEDIATE] = "poweroff-immediate"
-};
-DEFINE_STRING_TABLE_LOOKUP(failure_action, FailureAction);
diff --git a/src/core/failure-action.h b/src/core/failure-action.h
deleted file mode 100644
index 1af4dd987..000000000
--- a/src/core/failure-action.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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/>.
-***/
-
-typedef enum FailureAction {
- FAILURE_ACTION_NONE,
- FAILURE_ACTION_REBOOT,
- FAILURE_ACTION_REBOOT_FORCE,
- FAILURE_ACTION_REBOOT_IMMEDIATE,
- FAILURE_ACTION_POWEROFF,
- FAILURE_ACTION_POWEROFF_FORCE,
- FAILURE_ACTION_POWEROFF_IMMEDIATE,
- _FAILURE_ACTION_MAX,
- _FAILURE_ACTION_INVALID = -1
-} FailureAction;
-
-#include "macro.h"
-#include "manager.h"
-
-int failure_action(Manager *m, FailureAction action, const char *reboot_arg);
-
-const char* failure_action_to_string(FailureAction i) _const_;
-FailureAction failure_action_from_string(const char *s) _pure_;
diff --git a/src/core/hostname-setup.c b/src/core/hostname-setup.c
deleted file mode 100644
index 03b0ce3b4..000000000
--- a/src/core/hostname-setup.c
+++ /dev/null
@@ -1,88 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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.h>
-#include <errno.h>
-#include <stdlib.h>
-
-#include "hostname-setup.h"
-#include "macro.h"
-#include "util.h"
-#include "log.h"
-#include "fileio.h"
-
-static int read_and_strip_hostname(const char *path, char **hn) {
- char *s;
- int r;
-
- assert(path);
- assert(hn);
-
- r = read_one_line_file(path, &s);
- if (r < 0)
- return r;
-
- hostname_cleanup(s, false);
-
- if (isempty(s)) {
- free(s);
- return -ENOENT;
- }
-
- *hn = s;
- return 0;
-}
-
-int hostname_setup(void) {
- int r;
- _cleanup_free_ char *b = NULL;
- const char *hn;
- bool enoent = false;
-
- r = read_and_strip_hostname("/etc/hostname", &b);
- if (r < 0) {
- if (r == -ENOENT)
- enoent = true;
- else
- log_warning_errno(r, "Failed to read configured hostname: %m");
-
- hn = NULL;
- } else
- hn = b;
-
- if (isempty(hn)) {
- /* Don't override the hostname if it is already set
- * and not explicitly configured */
- if (hostname_is_set())
- return 0;
-
- if (enoent)
- log_info("No hostname configured.");
-
- hn = "localhost";
- }
-
- if (sethostname_idempotent(hn) < 0)
- return log_warning_errno(errno, "Failed to set hostname to <%s>: %m", hn);
-
- log_info("Set hostname to <%s>.", hn);
- return 0;
-}
diff --git a/src/core/hostname-setup.h b/src/core/hostname-setup.h
deleted file mode 100644
index 8dc3a9e1d..000000000
--- a/src/core/hostname-setup.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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
deleted file mode 100644
index 7721b3eca..000000000
--- a/src/core/ima-setup.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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/>.
-***/
-
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-
-#include "ima-setup.h"
-#include "copy.h"
-#include "util.h"
-#include "log.h"
-
-#define IMA_SECFS_DIR "/sys/kernel/security/ima"
-#define IMA_SECFS_POLICY IMA_SECFS_DIR "/policy"
-#define IMA_POLICY_PATH "/etc/ima/ima-policy"
-
-int ima_setup(void) {
- int r = 0;
-
-#ifdef HAVE_IMA
- _cleanup_close_ int policyfd = -1, imafd = -1;
-
- if (access(IMA_SECFS_DIR, F_OK) < 0) {
- log_debug("IMA support is disabled in the kernel, ignoring.");
- return 0;
- }
-
- policyfd = open(IMA_POLICY_PATH, O_RDONLY|O_CLOEXEC);
- if (policyfd < 0) {
- log_full_errno(errno == ENOENT ? LOG_DEBUG : LOG_WARNING, errno,
- "Failed to open the IMA custom policy file "IMA_POLICY_PATH", ignoring: %m");
- return 0;
- }
-
- if (access(IMA_SECFS_POLICY, F_OK) < 0) {
- log_warning("Another IMA custom policy has already been loaded, ignoring.");
- return 0;
- }
-
- imafd = open(IMA_SECFS_POLICY, O_WRONLY|O_CLOEXEC);
- if (imafd < 0) {
- log_error_errno(errno, "Failed to open the IMA kernel interface "IMA_SECFS_POLICY", ignoring: %m");
- return 0;
- }
-
- r = copy_bytes(policyfd, imafd, (off_t) -1, false);
- if (r < 0)
- log_error_errno(r, "Failed to load the IMA custom policy file "IMA_POLICY_PATH": %m");
- else
- log_info("Successfully loaded the IMA custom policy "IMA_POLICY_PATH".");
-
-#endif /* HAVE_IMA */
- return r;
-}
diff --git a/src/core/ima-setup.h b/src/core/ima-setup.h
deleted file mode 100644
index 14b56d1fc..000000000
--- a/src/core/ima-setup.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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/>.
-***/
-
-int ima_setup(void);
diff --git a/src/core/job.c b/src/core/job.c
deleted file mode 100644
index bd63eb16b..000000000
--- a/src/core/job.c
+++ /dev/null
@@ -1,1238 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 "sd-id128.h"
-#include "sd-messages.h"
-#include "set.h"
-#include "unit.h"
-#include "macro.h"
-#include "strv.h"
-#include "log.h"
-#include "dbus-job.h"
-#include "special.h"
-#include "async.h"
-#include "virt.h"
-#include "dbus.h"
-
-Job* job_new_raw(Unit *unit) {
- Job *j;
-
- /* used for deserialization */
-
- assert(unit);
-
- j = new0(Job, 1);
- if (!j)
- return NULL;
-
- j->manager = unit->manager;
- j->unit = unit;
- j->type = _JOB_TYPE_INVALID;
-
- return j;
-}
-
-Job* job_new(Unit *unit, JobType type) {
- Job *j;
-
- assert(type < _JOB_TYPE_MAX);
-
- j = job_new_raw(unit);
- if (!j)
- return NULL;
-
- j->id = j->manager->current_job_id++;
- j->type = type;
-
- /* We don't link it here, that's what job_dependency() is for */
-
- return j;
-}
-
-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);
-
- if (j->in_run_queue)
- LIST_REMOVE(run_queue, j->manager->run_queue, j);
-
- if (j->in_dbus_queue)
- LIST_REMOVE(dbus_queue, j->manager->dbus_job_queue, j);
-
- sd_event_source_unref(j->timer_event_source);
-
- sd_bus_track_unref(j->clients);
- strv_free(j->deserialized_clients);
-
- free(j);
-}
-
-static void job_set_state(Job *j, JobState state) {
- assert(j);
- assert(state >= 0);
- assert(state < _JOB_STATE_MAX);
-
- if (j->state == state)
- return;
-
- j->state = state;
-
- if (!j->installed)
- return;
-
- if (j->state == JOB_RUNNING)
- j->unit->manager->n_running_jobs++;
- else {
- assert(j->state == JOB_WAITING);
- assert(j->unit->manager->n_running_jobs > 0);
-
- j->unit->manager->n_running_jobs--;
-
- if (j->unit->manager->n_running_jobs <= 0)
- j->unit->manager->jobs_in_progress_event_source = sd_event_source_unref(j->unit->manager->jobs_in_progress_event_source);
- }
-}
-
-void job_uninstall(Job *j) {
- Job **pj;
-
- assert(j->installed);
-
- job_set_state(j, JOB_WAITING);
-
- pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
- assert(*pj == j);
-
- /* Detach from next 'bigger' objects */
-
- /* daemon-reload should be transparent to job observers */
- if (j->manager->n_reloading <= 0)
- bus_job_send_removed_signal(j);
-
- *pj = NULL;
-
- unit_add_to_gc_queue(j->unit);
-
- hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id));
- j->installed = false;
-}
-
-static bool job_type_allows_late_merge(JobType t) {
- /* Tells whether it is OK to merge a job of type 't' with an already
- * running job.
- * Reloads cannot be merged this way. Think of the sequence:
- * 1. Reload of a daemon is in progress; the daemon has already loaded
- * its config file, but hasn't completed the reload operation yet.
- * 2. Edit foo's config file.
- * 3. Trigger another reload to have the daemon use the new config.
- * Should the second reload job be merged into the first one, the daemon
- * would not know about the new config.
- * JOB_RESTART jobs on the other hand can be merged, because they get
- * patched into JOB_START after stopping the unit. So if we see a
- * JOB_RESTART running, it means the unit hasn't stopped yet and at
- * this time the merge is still allowed. */
- return t != JOB_RELOAD;
-}
-
-static void job_merge_into_installed(Job *j, Job *other) {
- assert(j->installed);
- assert(j->unit == other->unit);
-
- if (j->type != JOB_NOP)
- job_type_merge_and_collapse(&j->type, other->type, j->unit);
- else
- assert(other->type == JOB_NOP);
-
- j->override = j->override || other->override;
- j->irreversible = j->irreversible || other->irreversible;
- j->ignore_order = j->ignore_order || other->ignore_order;
-}
-
-Job* job_install(Job *j) {
- Job **pj;
- Job *uj;
-
- assert(!j->installed);
- assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
- assert(j->state == JOB_WAITING);
-
- pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
- uj = *pj;
-
- if (uj) {
- if (job_type_is_conflicting(uj->type, j->type))
- job_finish_and_invalidate(uj, JOB_CANCELED, false);
- else {
- /* not conflicting, i.e. mergeable */
-
- if (uj->state == JOB_WAITING ||
- (job_type_allows_late_merge(j->type) && job_type_is_superset(uj->type, j->type))) {
- job_merge_into_installed(uj, j);
- log_unit_debug(uj->unit->id,
- "Merged into installed job %s/%s as %u",
- uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
- return uj;
- } else {
- /* already running and not safe to merge into */
- /* Patch uj to become a merged job and re-run it. */
- /* XXX It should be safer to queue j to run after uj finishes, but it is
- * not currently possible to have more than one installed job per unit. */
- job_merge_into_installed(uj, j);
- log_unit_debug(uj->unit->id,
- "Merged into running job, re-running: %s/%s as %u",
- uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
-
- job_set_state(uj, JOB_WAITING);
- return uj;
- }
- }
- }
-
- /* Install the job */
- *pj = j;
- j->installed = true;
-
- j->manager->n_installed_jobs ++;
- log_unit_debug(j->unit->id,
- "Installed new job %s/%s as %u",
- j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
- return j;
-}
-
-int job_install_deserialized(Job *j) {
- Job **pj;
-
- assert(!j->installed);
-
- if (j->type < 0 || j->type >= _JOB_TYPE_MAX_IN_TRANSACTION) {
- log_debug("Invalid job type %s in deserialization.", strna(job_type_to_string(j->type)));
- return -EINVAL;
- }
-
- pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
- if (*pj) {
- log_unit_debug(j->unit->id, "Unit %s already has a job installed. Not installing deserialized job.", j->unit->id);
- return -EEXIST;
- }
-
- *pj = j;
- j->installed = true;
-
- if (j->state == JOB_RUNNING)
- j->unit->manager->n_running_jobs++;
-
- log_unit_debug(j->unit->id,
- "Reinstalled deserialized job %s/%s as %u",
- j->unit->id, job_type_to_string(j->type), (unsigned) j->id);
- return 0;
-}
-
-JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts) {
- JobDependency *l;
-
- assert(object);
-
- /* Adds a new job link, which encodes that the 'subject' job
- * needs the 'object' job in some way. If 'subject' is NULL
- * this means the 'anchor' job (i.e. the one the user
- * explicitly asked for) is the requester. */
-
- if (!(l = new0(JobDependency, 1)))
- return NULL;
-
- l->subject = subject;
- l->object = object;
- l->matters = matters;
- l->conflicts = conflicts;
-
- if (subject)
- LIST_PREPEND(subject, subject->subject_list, l);
-
- LIST_PREPEND(object, object->object_list, l);
-
- return l;
-}
-
-void job_dependency_free(JobDependency *l) {
- assert(l);
-
- if (l->subject)
- LIST_REMOVE(subject, l->subject->subject_list, l);
-
- LIST_REMOVE(object, l->object->object_list, l);
-
- free(l);
-}
-
-void job_dump(Job *j, FILE*f, const char *prefix) {
- assert(j);
- assert(f);
-
- if (!prefix)
- prefix = "";
-
- fprintf(f,
- "%s-> Job %u:\n"
- "%s\tAction: %s -> %s\n"
- "%s\tState: %s\n"
- "%s\tForced: %s\n"
- "%s\tIrreversible: %s\n",
- prefix, j->id,
- prefix, j->unit->id, job_type_to_string(j->type),
- prefix, job_state_to_string(j->state),
- prefix, yes_no(j->override),
- prefix, yes_no(j->irreversible));
-}
-
-/*
- * Merging is commutative, so imagine the matrix as symmetric. We store only
- * its lower triangle to avoid duplication. We don't store the main diagonal,
- * because A merged with A is simply A.
- *
- * If the resulting type is collapsed immediately afterwards (to get rid of
- * the JOB_RELOAD_OR_START, which lies outside the lookup function's domain),
- * the following properties hold:
- *
- * Merging is associative! A merged with B, and then merged with C is the same
- * as A merged with the result of B merged with C.
- *
- * Mergeability is transitive! If A can be merged with B and B with C then
- * A also with C.
- *
- * Also, if A merged with B cannot be merged with C, then either A or B cannot
- * be merged with C either.
- */
-static const JobType job_merging_table[] = {
-/* What \ With * JOB_START JOB_VERIFY_ACTIVE JOB_STOP JOB_RELOAD */
-/*********************************************************************************/
-/*JOB_START */
-/*JOB_VERIFY_ACTIVE */ JOB_START,
-/*JOB_STOP */ -1, -1,
-/*JOB_RELOAD */ JOB_RELOAD_OR_START, JOB_RELOAD, -1,
-/*JOB_RESTART */ JOB_RESTART, JOB_RESTART, -1, JOB_RESTART,
-};
-
-JobType job_type_lookup_merge(JobType a, JobType b) {
- assert_cc(ELEMENTSOF(job_merging_table) == _JOB_TYPE_MAX_MERGING * (_JOB_TYPE_MAX_MERGING - 1) / 2);
- assert(a >= 0 && a < _JOB_TYPE_MAX_MERGING);
- assert(b >= 0 && b < _JOB_TYPE_MAX_MERGING);
-
- if (a == b)
- return a;
-
- if (a < b) {
- JobType tmp = a;
- a = b;
- b = tmp;
- }
-
- return job_merging_table[(a - 1) * a / 2 + b];
-}
-
-bool job_type_is_redundant(JobType a, UnitActiveState b) {
- switch (a) {
-
- case JOB_START:
- return
- b == UNIT_ACTIVE ||
- b == UNIT_RELOADING;
-
- case JOB_STOP:
- return
- b == UNIT_INACTIVE ||
- b == UNIT_FAILED;
-
- case JOB_VERIFY_ACTIVE:
- return
- b == UNIT_ACTIVE ||
- b == UNIT_RELOADING;
-
- case JOB_RELOAD:
- return
- b == UNIT_RELOADING;
-
- case JOB_RESTART:
- return
- b == UNIT_ACTIVATING;
-
- case JOB_NOP:
- return true;
-
- default:
- assert_not_reached("Invalid job type");
- }
-}
-
-void job_type_collapse(JobType *t, Unit *u) {
- UnitActiveState s;
-
- switch (*t) {
-
- case JOB_TRY_RESTART:
- s = unit_active_state(u);
- if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
- *t = JOB_NOP;
- else
- *t = JOB_RESTART;
- break;
-
- case JOB_RELOAD_OR_START:
- s = unit_active_state(u);
- if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
- *t = JOB_START;
- else
- *t = JOB_RELOAD;
- break;
-
- default:
- ;
- }
-}
-
-int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u) {
- JobType t = job_type_lookup_merge(*a, b);
- if (t < 0)
- return -EEXIST;
- *a = t;
- job_type_collapse(a, u);
- return 0;
-}
-
-static bool job_is_runnable(Job *j) {
- Iterator i;
- Unit *other;
-
- assert(j);
- assert(j->installed);
-
- /* Checks whether there is any job running for the units this
- * job needs to be running after (in the case of a 'positive'
- * job type) or before (in the case of a 'negative' job
- * type. */
-
- /* Note that unit types have a say in what is runnable,
- * too. For example, if they return -EAGAIN from
- * unit_start() they can indicate they are not
- * runnable yet. */
-
- /* First check if there is an override */
- if (j->ignore_order)
- return true;
-
- if (j->type == JOB_NOP)
- return true;
-
- if (j->type == JOB_START ||
- j->type == JOB_VERIFY_ACTIVE ||
- j->type == JOB_RELOAD) {
-
- /* Immediate result is that the job is or might be
- * started. In this case lets wait for the
- * dependencies, regardless whether they are
- * starting or stopping something. */
-
- SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i)
- if (other->job)
- return false;
- }
-
- /* Also, if something else is being stopped and we should
- * change state after it, then lets wait. */
-
- SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i)
- if (other->job &&
- (other->job->type == JOB_STOP ||
- other->job->type == JOB_RESTART))
- return false;
-
- /* This means that for a service a and a service b where b
- * shall be started after a:
- *
- * start a + start b → 1st step start a, 2nd step start b
- * start a + stop b → 1st step stop b, 2nd step start a
- * stop a + start b → 1st step stop a, 2nd step start b
- * stop a + stop b → 1st step stop b, 2nd step stop a
- *
- * This has the side effect that restarts are properly
- * synchronized too. */
-
- return true;
-}
-
-static void job_change_type(Job *j, JobType newtype) {
- log_unit_debug(j->unit->id,
- "Converting job %s/%s -> %s/%s",
- j->unit->id, job_type_to_string(j->type),
- j->unit->id, job_type_to_string(newtype));
-
- j->type = newtype;
-}
-
-int job_run_and_invalidate(Job *j) {
- int r;
- uint32_t id;
- Manager *m = j->manager;
-
- assert(j);
- assert(j->installed);
- assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
- assert(j->in_run_queue);
-
- LIST_REMOVE(run_queue, j->manager->run_queue, j);
- j->in_run_queue = false;
-
- if (j->state != JOB_WAITING)
- return 0;
-
- if (!job_is_runnable(j))
- return -EAGAIN;
-
- job_set_state(j, JOB_RUNNING);
- job_add_to_dbus_queue(j);
-
- /* While we execute this operation the job might go away (for
- * example: because it is replaced by a new, conflicting
- * job.) To make sure we don't access a freed job later on we
- * store the id here, so that we can verify the job is still
- * valid. */
- id = j->id;
-
- switch (j->type) {
-
- case JOB_START:
- r = unit_start(j->unit);
-
- /* If this unit cannot be started, then simply wait */
- if (r == -EBADR)
- r = 0;
- break;
-
- case JOB_VERIFY_ACTIVE: {
- UnitActiveState t = unit_active_state(j->unit);
- if (UNIT_IS_ACTIVE_OR_RELOADING(t))
- r = -EALREADY;
- else if (t == UNIT_ACTIVATING)
- r = -EAGAIN;
- else
- r = -EBADR;
- break;
- }
-
- case JOB_STOP:
- case JOB_RESTART:
- r = unit_stop(j->unit);
-
- /* If this unit cannot stopped, then simply wait. */
- if (r == -EBADR)
- r = 0;
- break;
-
- case JOB_RELOAD:
- r = unit_reload(j->unit);
- break;
-
- case JOB_NOP:
- r = -EALREADY;
- break;
-
- default:
- assert_not_reached("Unknown job type");
- }
-
- j = manager_get_job(m, id);
- if (j) {
- if (r == -EALREADY)
- r = job_finish_and_invalidate(j, JOB_DONE, true);
- else if (r == -EBADR)
- r = job_finish_and_invalidate(j, JOB_SKIPPED, true);
- else if (r == -ENOEXEC)
- r = job_finish_and_invalidate(j, JOB_INVALID, true);
- else if (r == -EPROTO)
- r = job_finish_and_invalidate(j, JOB_ASSERT, true);
- else if (r == -EOPNOTSUPP)
- r = job_finish_and_invalidate(j, JOB_UNSUPPORTED, true);
- else if (r == -EAGAIN)
- job_set_state(j, JOB_WAITING);
- else if (r < 0)
- r = job_finish_and_invalidate(j, JOB_FAILED, true);
- }
-
- return r;
-}
-
-_pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobResult result) {
- const UnitStatusMessageFormats *format_table;
-
- assert(u);
- assert(t >= 0);
- assert(t < _JOB_TYPE_MAX);
-
- format_table = &UNIT_VTABLE(u)->status_message_formats;
- if (!format_table)
- return NULL;
-
- if (t == JOB_START)
- return format_table->finished_start_job[result];
- else if (t == JOB_STOP || t == JOB_RESTART)
- return format_table->finished_stop_job[result];
-
- return NULL;
-}
-
-_pure_ static const char *job_get_status_message_format_try_harder(Unit *u, JobType t, JobResult result) {
- const char *format;
-
- assert(u);
- assert(t >= 0);
- assert(t < _JOB_TYPE_MAX);
-
- format = job_get_status_message_format(u, t, result);
- if (format)
- return format;
-
- /* Return generic strings */
- if (t == JOB_START) {
- if (result == JOB_DONE)
- return "Started %s.";
- else if (result == JOB_TIMEOUT)
- return "Timed out starting %s.";
- else if (result == JOB_FAILED)
- return "Failed to start %s.";
- else if (result == JOB_DEPENDENCY)
- return "Dependency failed for %s.";
- else if (result == JOB_ASSERT)
- return "Assertion failed for %s.";
- else if (result == JOB_UNSUPPORTED)
- return "Starting of %s not supported.";
- } else if (t == JOB_STOP || t == JOB_RESTART) {
- if (result == JOB_DONE)
- return "Stopped %s.";
- else if (result == JOB_FAILED)
- return "Stopped (with error) %s.";
- else if (result == JOB_TIMEOUT)
- return "Timed out stoppping %s.";
- } else if (t == JOB_RELOAD) {
- if (result == JOB_DONE)
- return "Reloaded %s.";
- else if (result == JOB_FAILED)
- return "Reload failed for %s.";
- else if (result == JOB_TIMEOUT)
- return "Timed out reloading %s.";
- }
-
- return NULL;
-}
-
-static void job_print_status_message(Unit *u, JobType t, JobResult result) {
- const char *format;
-
- assert(u);
- assert(t >= 0);
- assert(t < _JOB_TYPE_MAX);
-
- DISABLE_WARNING_FORMAT_NONLITERAL;
-
- if (t == JOB_START) {
- format = job_get_status_message_format(u, t, result);
- if (!format)
- return;
-
- switch (result) {
-
- case JOB_DONE:
- if (u->condition_result)
- unit_status_printf(u, ANSI_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, format);
- break;
-
- case JOB_TIMEOUT:
- manager_flip_auto_status(u->manager, true);
- unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format);
- break;
-
- case JOB_FAILED: {
- bool quotes;
-
- quotes = chars_intersect(u->id, SHELL_NEED_QUOTES);
-
- manager_flip_auto_status(u->manager, true);
- unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, format);
- manager_status_printf(u->manager, STATUS_TYPE_NORMAL, NULL,
- "See \"systemctl status %s%s%s\" for details.",
- quotes ? "'" : "", u->id, quotes ? "'" : "");
- break;
- }
-
- case JOB_DEPENDENCY:
- manager_flip_auto_status(u->manager, true);
- unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "DEPEND" ANSI_HIGHLIGHT_OFF, format);
- break;
-
- case JOB_ASSERT:
- manager_flip_auto_status(u->manager, true);
- unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "ASSERT" ANSI_HIGHLIGHT_OFF, format);
- break;
-
- case JOB_UNSUPPORTED:
- manager_flip_auto_status(u->manager, true);
- unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "UNSUPP" ANSI_HIGHLIGHT_OFF, format);
- break;
-
- default:
- ;
- }
-
- } else if (t == JOB_STOP || t == JOB_RESTART) {
-
- format = job_get_status_message_format(u, t, result);
- if (!format)
- return;
-
- switch (result) {
-
- case JOB_TIMEOUT:
- manager_flip_auto_status(u->manager, true);
- unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format);
- break;
-
- case JOB_DONE:
- case JOB_FAILED:
- unit_status_printf(u, ANSI_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, format);
- break;
-
- default:
- ;
- }
-
- } else if (t == JOB_VERIFY_ACTIVE) {
-
- /* When verify-active detects the unit is inactive, report it.
- * Most likely a DEPEND warning from a requisiting unit will
- * occur next and it's nice to see what was requisited. */
- if (result == JOB_SKIPPED)
- unit_status_printf(u, ANSI_HIGHLIGHT_ON " INFO " ANSI_HIGHLIGHT_OFF, "%s is not active.");
- }
-
- REENABLE_WARNING;
-}
-
-static void job_log_status_message(Unit *u, JobType t, JobResult result) {
- const char *format;
- char buf[LINE_MAX];
-
- assert(u);
- assert(t >= 0);
- assert(t < _JOB_TYPE_MAX);
-
- /* Skip this if it goes to the console. since we already print
- * to the console anyway... */
-
- if (log_on_console())
- return;
-
- format = job_get_status_message_format_try_harder(u, t, result);
- if (!format)
- return;
-
- DISABLE_WARNING_FORMAT_NONLITERAL;
- snprintf(buf, sizeof(buf), format, unit_description(u));
- REENABLE_WARNING;
-
- if (t == JOB_START) {
- sd_id128_t mid;
-
- mid = result == JOB_DONE ? SD_MESSAGE_UNIT_STARTED : SD_MESSAGE_UNIT_FAILED;
- log_unit_struct(u->id,
- result == JOB_DONE ? LOG_INFO : LOG_ERR,
- LOG_MESSAGE_ID(mid),
- LOG_MESSAGE("%s", buf),
- "RESULT=%s", job_result_to_string(result),
- NULL);
-
- } else if (t == JOB_STOP)
- log_unit_struct(u->id,
- result == JOB_DONE ? LOG_INFO : LOG_ERR,
- LOG_MESSAGE_ID(SD_MESSAGE_UNIT_STOPPED),
- LOG_MESSAGE("%s", buf),
- "RESULT=%s", job_result_to_string(result),
- NULL);
-
- else if (t == JOB_RELOAD)
- log_unit_struct(u->id,
- result == JOB_DONE ? LOG_INFO : LOG_ERR,
- LOG_MESSAGE_ID(SD_MESSAGE_UNIT_RELOADED),
- LOG_MESSAGE("%s", buf),
- "RESULT=%s", job_result_to_string(result),
- NULL);
-}
-
-int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
- Unit *u;
- Unit *other;
- JobType t;
- Iterator i;
-
- assert(j);
- assert(j->installed);
- assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
-
- u = j->unit;
- t = j->type;
-
- j->result = result;
-
- log_unit_debug(u->id, "Job %s/%s finished, result=%s",
- u->id, job_type_to_string(t), job_result_to_string(result));
-
- job_print_status_message(u, t, result);
- job_log_status_message(u, t, result);
-
- job_add_to_dbus_queue(j);
-
- /* Patch restart jobs so that they become normal start jobs */
- if (result == JOB_DONE && t == JOB_RESTART) {
-
- job_change_type(j, JOB_START);
- job_set_state(j, JOB_WAITING);
-
- job_add_to_run_queue(j);
-
- goto finish;
- }
-
- if (result == JOB_FAILED || result == JOB_INVALID)
- j->manager->n_failed_jobs ++;
-
- job_uninstall(j);
- job_free(j);
-
- /* Fail depending jobs on failure */
- if (result != JOB_DONE && recursive) {
-
- if (t == JOB_START ||
- t == JOB_VERIFY_ACTIVE) {
-
- SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i)
- if (other->job &&
- (other->job->type == JOB_START ||
- other->job->type == JOB_VERIFY_ACTIVE))
- job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true);
-
- SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
- if (other->job &&
- (other->job->type == JOB_START ||
- other->job->type == JOB_VERIFY_ACTIVE))
- job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true);
-
- SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
- if (other->job &&
- !other->job->override &&
- (other->job->type == JOB_START ||
- other->job->type == JOB_VERIFY_ACTIVE))
- job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true);
-
- } else if (t == JOB_STOP) {
-
- SET_FOREACH(other, u->dependencies[UNIT_CONFLICTED_BY], i)
- if (other->job &&
- (other->job->type == JOB_START ||
- other->job->type == JOB_VERIFY_ACTIVE))
- job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true);
- }
- }
-
- /* Trigger OnFailure dependencies that are not generated by
- * the unit itself. We don't treat JOB_CANCELED as failure in
- * this context. And JOB_FAILURE is already handled by the
- * unit itself. */
- if (result == JOB_TIMEOUT || result == JOB_DEPENDENCY) {
- log_unit_struct(u->id,
- LOG_NOTICE,
- "JOB_TYPE=%s", job_type_to_string(t),
- "JOB_RESULT=%s", job_result_to_string(result),
- LOG_MESSAGE("Job %s/%s failed with result '%s'.",
- u->id,
- job_type_to_string(t),
- job_result_to_string(result)),
- NULL);
-
- unit_start_on_failure(u);
- }
-
- unit_trigger_notify(u);
-
-finish:
- /* Try to start the next jobs that can be started */
- SET_FOREACH(other, u->dependencies[UNIT_AFTER], i)
- if (other->job)
- job_add_to_run_queue(other->job);
- SET_FOREACH(other, u->dependencies[UNIT_BEFORE], i)
- if (other->job)
- job_add_to_run_queue(other->job);
-
- manager_check_finished(u->manager);
-
- return 0;
-}
-
-static int job_dispatch_timer(sd_event_source *s, uint64_t monotonic, void *userdata) {
- Job *j = userdata;
- Unit *u;
-
- assert(j);
- assert(s == j->timer_event_source);
-
- log_unit_warning(j->unit->id, "Job %s/%s timed out.", j->unit->id, job_type_to_string(j->type));
-
- u = j->unit;
- job_finish_and_invalidate(j, JOB_TIMEOUT, true);
-
- failure_action(u->manager, u->job_timeout_action, u->job_timeout_reboot_arg);
-
- return 0;
-}
-
-int job_start_timer(Job *j) {
- int r;
-
- if (j->timer_event_source)
- return 0;
-
- j->begin_usec = now(CLOCK_MONOTONIC);
-
- if (j->unit->job_timeout <= 0)
- return 0;
-
- r = sd_event_add_time(
- j->manager->event,
- &j->timer_event_source,
- CLOCK_MONOTONIC,
- j->begin_usec + j->unit->job_timeout, 0,
- job_dispatch_timer, j);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-void job_add_to_run_queue(Job *j) {
- assert(j);
- assert(j->installed);
-
- if (j->in_run_queue)
- return;
-
- if (!j->manager->run_queue)
- sd_event_source_set_enabled(j->manager->run_queue_event_source, SD_EVENT_ONESHOT);
-
- LIST_PREPEND(run_queue, j->manager->run_queue, j);
- j->in_run_queue = true;
-}
-
-void job_add_to_dbus_queue(Job *j) {
- assert(j);
- assert(j->installed);
-
- if (j->in_dbus_queue)
- return;
-
- /* We don't check if anybody is subscribed here, since this
- * job might just have been created and not yet assigned to a
- * connection/client. */
-
- LIST_PREPEND(dbus_queue, j->manager->dbus_job_queue, j);
- j->in_dbus_queue = true;
-}
-
-char *job_dbus_path(Job *j) {
- char *p;
-
- assert(j);
-
- if (asprintf(&p, "/org/freedesktop/systemd1/job/%"PRIu32, j->id) < 0)
- return NULL;
-
- return p;
-}
-
-int job_serialize(Job *j, FILE *f, FDSet *fds) {
- fprintf(f, "job-id=%u\n", j->id);
- fprintf(f, "job-type=%s\n", job_type_to_string(j->type));
- fprintf(f, "job-state=%s\n", job_state_to_string(j->state));
- fprintf(f, "job-override=%s\n", yes_no(j->override));
- fprintf(f, "job-irreversible=%s\n", yes_no(j->irreversible));
- fprintf(f, "job-sent-dbus-new-signal=%s\n", yes_no(j->sent_dbus_new_signal));
- fprintf(f, "job-ignore-order=%s\n", yes_no(j->ignore_order));
-
- if (j->begin_usec > 0)
- fprintf(f, "job-begin="USEC_FMT"\n", j->begin_usec);
-
- bus_track_serialize(j->clients, f);
-
- /* End marker */
- fputc('\n', f);
- return 0;
-}
-
-int job_deserialize(Job *j, FILE *f, FDSet *fds) {
- assert(j);
-
- for (;;) {
- char line[LINE_MAX], *l, *v;
- size_t k;
-
- if (!fgets(line, sizeof(line), f)) {
- if (feof(f))
- return 0;
- return -errno;
- }
-
- char_array_0(line);
- l = strstrip(line);
-
- /* End marker */
- if (l[0] == 0)
- return 0;
-
- k = strcspn(l, "=");
-
- if (l[k] == '=') {
- l[k] = 0;
- v = l+k+1;
- } else
- v = l+k;
-
- if (streq(l, "job-id")) {
-
- if (safe_atou32(v, &j->id) < 0)
- log_debug("Failed to parse job id value %s", v);
-
- } else if (streq(l, "job-type")) {
- JobType t;
-
- t = job_type_from_string(v);
- if (t < 0)
- log_debug("Failed to parse job type %s", v);
- else if (t >= _JOB_TYPE_MAX_IN_TRANSACTION)
- log_debug("Cannot deserialize job of type %s", v);
- else
- j->type = t;
-
- } else if (streq(l, "job-state")) {
- JobState s;
-
- s = job_state_from_string(v);
- if (s < 0)
- log_debug("Failed to parse job state %s", v);
- else
- job_set_state(j, s);
-
- } else if (streq(l, "job-override")) {
- int b;
-
- b = parse_boolean(v);
- if (b < 0)
- log_debug("Failed to parse job override flag %s", v);
- else
- j->override = j->override || b;
-
- } else if (streq(l, "job-irreversible")) {
- int b;
-
- b = parse_boolean(v);
- if (b < 0)
- log_debug("Failed to parse job irreversible flag %s", v);
- else
- j->irreversible = j->irreversible || b;
-
- } else if (streq(l, "job-sent-dbus-new-signal")) {
- int b;
-
- b = parse_boolean(v);
- if (b < 0)
- log_debug("Failed to parse job sent_dbus_new_signal flag %s", v);
- else
- j->sent_dbus_new_signal = j->sent_dbus_new_signal || b;
-
- } else if (streq(l, "job-ignore-order")) {
- int b;
-
- b = parse_boolean(v);
- if (b < 0)
- log_debug("Failed to parse job ignore_order flag %s", v);
- else
- j->ignore_order = j->ignore_order || b;
-
- } else if (streq(l, "job-begin")) {
- unsigned long long ull;
-
- if (sscanf(v, "%llu", &ull) != 1)
- log_debug("Failed to parse job-begin value %s", v);
- else
- j->begin_usec = ull;
-
- } else if (streq(l, "subscribed")) {
-
- if (strv_extend(&j->deserialized_clients, v) < 0)
- return log_oom();
- }
- }
-}
-
-int job_coldplug(Job *j) {
- int r;
-
- assert(j);
-
- /* After deserialization is complete and the bus connection
- * set up again, let's start watching our subscribers again */
- r = bus_track_coldplug(j->manager, &j->clients, &j->deserialized_clients);
- if (r < 0)
- return r;
-
- if (j->state == JOB_WAITING)
- job_add_to_run_queue(j);
-
- if (j->begin_usec == 0 || j->unit->job_timeout == 0)
- return 0;
-
- if (j->timer_event_source)
- j->timer_event_source = sd_event_source_unref(j->timer_event_source);
-
- r = sd_event_add_time(
- j->manager->event,
- &j->timer_event_source,
- CLOCK_MONOTONIC,
- j->begin_usec + j->unit->job_timeout, 0,
- job_dispatch_timer, j);
- if (r < 0)
- log_debug_errno(r, "Failed to restart timeout for job: %m");
-
- return r;
-}
-
-void job_shutdown_magic(Job *j) {
- assert(j);
-
- /* The shutdown target gets some special treatment here: we
- * tell the kernel to begin with flushing its disk caches, to
- * optimize shutdown time a bit. Ideally we wouldn't hardcode
- * this magic into PID 1. However all other processes aren't
- * options either since they'd exit much sooner than PID 1 and
- * asynchronous sync() would cause their exit to be
- * delayed. */
-
- if (j->type != JOB_START)
- return;
-
- if (j->unit->manager->running_as != SYSTEMD_SYSTEM)
- return;
-
- if (!unit_has_name(j->unit, SPECIAL_SHUTDOWN_TARGET))
- return;
-
- /* In case messages on console has been disabled on boot */
- j->unit->manager->no_console_output = false;
-
- if (detect_container(NULL) > 0)
- return;
-
- asynchronous_sync();
-}
-
-int job_get_timeout(Job *j, uint64_t *timeout) {
- Unit *u = j->unit;
- uint64_t x = -1, y = -1;
- int r = 0, q = 0;
-
- assert(u);
-
- if (j->timer_event_source) {
- r = sd_event_source_get_time(j->timer_event_source, &x);
- if (r < 0)
- return r;
- r = 1;
- }
-
- if (UNIT_VTABLE(u)->get_timeout) {
- q = UNIT_VTABLE(u)->get_timeout(u, &y);
- if (q < 0)
- return q;
- }
-
- if (r == 0 && q == 0)
- return 0;
-
- *timeout = MIN(x, y);
-
- return 1;
-}
-
-static const char* const job_state_table[_JOB_STATE_MAX] = {
- [JOB_WAITING] = "waiting",
- [JOB_RUNNING] = "running"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(job_state, JobState);
-
-static const char* const job_type_table[_JOB_TYPE_MAX] = {
- [JOB_START] = "start",
- [JOB_VERIFY_ACTIVE] = "verify-active",
- [JOB_STOP] = "stop",
- [JOB_RELOAD] = "reload",
- [JOB_RELOAD_OR_START] = "reload-or-start",
- [JOB_RESTART] = "restart",
- [JOB_TRY_RESTART] = "try-restart",
- [JOB_NOP] = "nop",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(job_type, JobType);
-
-static const char* const job_mode_table[_JOB_MODE_MAX] = {
- [JOB_FAIL] = "fail",
- [JOB_REPLACE] = "replace",
- [JOB_REPLACE_IRREVERSIBLY] = "replace-irreversibly",
- [JOB_ISOLATE] = "isolate",
- [JOB_FLUSH] = "flush",
- [JOB_IGNORE_DEPENDENCIES] = "ignore-dependencies",
- [JOB_IGNORE_REQUIREMENTS] = "ignore-requirements",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(job_mode, JobMode);
-
-static const char* const job_result_table[_JOB_RESULT_MAX] = {
- [JOB_DONE] = "done",
- [JOB_CANCELED] = "canceled",
- [JOB_TIMEOUT] = "timeout",
- [JOB_FAILED] = "failed",
- [JOB_DEPENDENCY] = "dependency",
- [JOB_SKIPPED] = "skipped",
- [JOB_INVALID] = "invalid",
- [JOB_ASSERT] = "assert",
- [JOB_UNSUPPORTED] = "unsupported",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(job_result, JobResult);
diff --git a/src/core/job.h b/src/core/job.h
deleted file mode 100644
index 9119e4834..000000000
--- a/src/core/job.h
+++ /dev/null
@@ -1,237 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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>
-
-typedef struct Job Job;
-typedef struct JobDependency JobDependency;
-typedef enum JobType JobType;
-typedef enum JobState JobState;
-typedef enum JobMode JobMode;
-typedef enum JobResult JobResult;
-
-/* Be careful when changing the job types! Adjust job_merging_table[] accordingly! */
-enum JobType {
- JOB_START, /* if a unit does not support being started, we'll just wait until it becomes active */
- JOB_VERIFY_ACTIVE,
-
- JOB_STOP,
-
- JOB_RELOAD, /* if running, reload */
-
- /* Note that restarts are first treated like JOB_STOP, but
- * then instead of finishing are patched to become
- * JOB_START. */
- JOB_RESTART, /* If running, stop. Then start unconditionally. */
-
- _JOB_TYPE_MAX_MERGING,
-
- /* JOB_NOP can enter into a transaction, but as it won't pull in
- * any dependencies and it uses the special 'nop_job' slot in Unit,
- * it won't have to merge with anything (except possibly into another
- * JOB_NOP, previously installed). JOB_NOP is special-cased in
- * job_type_is_*() functions so that the transaction can be
- * activated. */
- JOB_NOP = _JOB_TYPE_MAX_MERGING, /* do nothing */
-
- _JOB_TYPE_MAX_IN_TRANSACTION,
-
- /* JOB_TRY_RESTART can never appear in a transaction, because
- * it always collapses into JOB_RESTART or JOB_NOP before entering.
- * Thus we never need to merge it with anything. */
- JOB_TRY_RESTART = _JOB_TYPE_MAX_IN_TRANSACTION, /* if running, stop and then start */
-
- /* JOB_RELOAD_OR_START won't enter into a transaction and cannot result
- * from transaction merging (there's no way for JOB_RELOAD and
- * JOB_START to meet in one transaction). It can result from a merge
- * during job installation, but then it will immediately collapse into
- * one of the two simpler types. */
- JOB_RELOAD_OR_START, /* if running, reload, otherwise start */
-
- _JOB_TYPE_MAX,
- _JOB_TYPE_INVALID = -1
-};
-
-enum JobState {
- JOB_WAITING,
- JOB_RUNNING,
- _JOB_STATE_MAX,
- _JOB_STATE_INVALID = -1
-};
-
-enum JobMode {
- JOB_FAIL, /* Fail if a conflicting job is already queued */
- JOB_REPLACE, /* Replace an existing conflicting job */
- JOB_REPLACE_IRREVERSIBLY,/* Like JOB_REPLACE + produce irreversible jobs */
- JOB_ISOLATE, /* Start a unit, and stop all others */
- JOB_FLUSH, /* Flush out all other queued jobs when queing this one */
- JOB_IGNORE_DEPENDENCIES, /* Ignore both requirement and ordering dependencies */
- JOB_IGNORE_REQUIREMENTS, /* Ignore requirement dependencies */
- _JOB_MODE_MAX,
- _JOB_MODE_INVALID = -1
-};
-
-enum JobResult {
- JOB_DONE, /* Job completed successfully */
- JOB_CANCELED, /* Job canceled by a conflicting job installation or by explicit cancel request */
- JOB_TIMEOUT, /* Job timeout elapsed */
- JOB_FAILED, /* Job failed */
- JOB_DEPENDENCY, /* A required dependency job did not result in JOB_DONE */
- JOB_SKIPPED, /* Negative result of JOB_VERIFY_ACTIVE */
- JOB_INVALID, /* JOB_RELOAD of inactive unit */
- 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_RESULT_MAX,
- _JOB_RESULT_INVALID = -1
-};
-
-#include "sd-event.h"
-#include "unit.h"
-#include "list.h"
-
-struct JobDependency {
- /* Encodes that the 'subject' job needs the 'object' job in
- * some way. This structure is used only while building a transaction. */
- Job *subject;
- Job *object;
-
- LIST_FIELDS(JobDependency, subject);
- LIST_FIELDS(JobDependency, object);
-
- bool matters;
- bool conflicts;
-};
-
-struct Job {
- Manager *manager;
- Unit *unit;
-
- LIST_FIELDS(Job, transaction);
- LIST_FIELDS(Job, run_queue);
- LIST_FIELDS(Job, dbus_queue);
-
- LIST_HEAD(JobDependency, subject_list);
- LIST_HEAD(JobDependency, object_list);
-
- /* Used for graph algs as a "I have been here" marker */
- Job* marker;
- unsigned generation;
-
- uint32_t id;
-
- JobType type;
- JobState state;
-
- sd_event_source *timer_event_source;
- usec_t begin_usec;
-
- /*
- * This tracks where to send signals, and also which clients
- * are allowed to call DBus methods on the job (other than
- * root).
- *
- * There can be more than one client, because of job merging.
- */
- sd_bus_track *clients;
- char **deserialized_clients;
-
- JobResult result;
-
- bool installed:1;
- bool in_run_queue:1;
- bool matters_to_anchor:1;
- bool override:1;
- bool in_dbus_queue:1;
- bool sent_dbus_new_signal:1;
- bool ignore_order:1;
- bool irreversible:1;
-};
-
-Job* job_new(Unit *unit, JobType type);
-Job* job_new_raw(Unit *unit);
-void job_free(Job *job);
-Job* job_install(Job *j);
-int job_install_deserialized(Job *j);
-void job_uninstall(Job *j);
-void job_dump(Job *j, FILE*f, const char *prefix);
-int job_serialize(Job *j, FILE *f, FDSet *fds);
-int job_deserialize(Job *j, FILE *f, FDSet *fds);
-int job_coldplug(Job *j);
-
-JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool conflicts);
-void job_dependency_free(JobDependency *l);
-
-int job_merge(Job *j, Job *other);
-
-JobType job_type_lookup_merge(JobType a, JobType b) _pure_;
-
-_pure_ static inline bool job_type_is_mergeable(JobType a, JobType b) {
- return job_type_lookup_merge(a, b) >= 0;
-}
-
-_pure_ static inline bool job_type_is_conflicting(JobType a, JobType b) {
- return a != JOB_NOP && b != JOB_NOP && !job_type_is_mergeable(a, b);
-}
-
-_pure_ static inline bool job_type_is_superset(JobType a, JobType b) {
- /* Checks whether operation a is a "superset" of b in its actions */
- if (b == JOB_NOP)
- return true;
- if (a == JOB_NOP)
- return false;
- return a == job_type_lookup_merge(a, b);
-}
-
-bool job_type_is_redundant(JobType a, UnitActiveState b) _pure_;
-
-/* Collapses a state-dependent job type into a simpler type by observing
- * the state of the unit which it is going to be applied to. */
-void job_type_collapse(JobType *t, Unit *u);
-
-int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u);
-
-void job_add_to_run_queue(Job *j);
-void job_add_to_dbus_queue(Job *j);
-
-int job_start_timer(Job *j);
-
-int job_run_and_invalidate(Job *j);
-int job_finish_and_invalidate(Job *j, JobResult result, bool recursive);
-
-char *job_dbus_path(Job *j);
-
-void job_shutdown_magic(Job *j);
-
-const char* job_type_to_string(JobType t) _const_;
-JobType job_type_from_string(const char *s) _pure_;
-
-const char* job_state_to_string(JobState t) _const_;
-JobState job_state_from_string(const char *s) _pure_;
-
-const char* job_mode_to_string(JobMode t) _const_;
-JobMode job_mode_from_string(const char *s) _pure_;
-
-const char* job_result_to_string(JobResult t) _const_;
-JobResult job_result_from_string(const char *s) _pure_;
-
-int job_get_timeout(Job *j, uint64_t *timeout) _pure_;
diff --git a/src/core/kill.c b/src/core/kill.c
deleted file mode 100644
index 60a510eae..000000000
--- a/src/core/kill.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 "util.h"
-
-void kill_context_init(KillContext *c) {
- assert(c);
-
- c->kill_signal = SIGTERM;
- c->send_sigkill = true;
- c->send_sighup = false;
-}
-
-void kill_context_dump(KillContext *c, FILE *f, const char *prefix) {
- assert(c);
-
- if (!prefix)
- prefix = "";
-
- fprintf(f,
- "%sKillMode: %s\n"
- "%sKillSignal: SIG%s\n"
- "%sSendSIGKILL: %s\n"
- "%sSendSIGHUP: %s\n",
- prefix, kill_mode_to_string(c->kill_mode),
- prefix, signal_to_string(c->kill_signal),
- prefix, yes_no(c->send_sigkill),
- prefix, yes_no(c->send_sighup));
-}
-
-static const char* const kill_mode_table[_KILL_MODE_MAX] = {
- [KILL_CONTROL_GROUP] = "control-group",
- [KILL_PROCESS] = "process",
- [KILL_MIXED] = "mixed",
- [KILL_NONE] = "none"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(kill_mode, KillMode);
-
-static const char* const kill_who_table[_KILL_WHO_MAX] = {
- [KILL_MAIN] = "main",
- [KILL_CONTROL] = "control",
- [KILL_ALL] = "all"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);
diff --git a/src/core/kill.h b/src/core/kill.h
deleted file mode 100644
index d5f125fa4..000000000
--- a/src/core/kill.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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>
-#include <stdio.h>
-
-#include "macro.h"
-
-typedef enum KillMode {
- /* The kill mode is a property of a unit. */
- KILL_CONTROL_GROUP = 0,
- KILL_PROCESS,
- KILL_MIXED,
- KILL_NONE,
- _KILL_MODE_MAX,
- _KILL_MODE_INVALID = -1
-} KillMode;
-
-struct KillContext {
- KillMode kill_mode;
- int kill_signal;
- bool send_sigkill;
- bool send_sighup;
-};
-
-typedef enum KillWho {
- /* Kill who is a property of an operation */
- KILL_MAIN,
- KILL_CONTROL,
- KILL_ALL,
- _KILL_WHO_MAX,
- _KILL_WHO_INVALID = -1
-} KillWho;
-
-void kill_context_init(KillContext *c);
-void kill_context_dump(KillContext *c, FILE *f, const char *prefix);
-
-const char *kill_mode_to_string(KillMode k) _const_;
-KillMode kill_mode_from_string(const char *s) _pure_;
-
-const char *kill_who_to_string(KillWho k) _const_;
-KillWho kill_who_from_string(const char *s) _pure_;
diff --git a/src/core/killall.c b/src/core/killall.c
deleted file mode 100644
index c6f1ddfec..000000000
--- a/src/core/killall.c
+++ /dev/null
@@ -1,225 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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/>.
-***/
-
-#include <sys/wait.h>
-#include <signal.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include "util.h"
-#include "killall.h"
-#include "set.h"
-
-#define TIMEOUT_USEC (10 * USEC_PER_SEC)
-
-static bool ignore_proc(pid_t pid) {
- _cleanup_fclose_ FILE *f = NULL;
- char c;
- const char *p;
- size_t count;
- uid_t uid;
- int r;
-
- /* We are PID 1, let's not commit suicide */
- if (pid == 1)
- return true;
-
- r = get_process_uid(pid, &uid);
- if (r < 0)
- return true; /* not really, but better safe than sorry */
-
- /* Non-root processes otherwise are always subject to be killed */
- if (uid != 0)
- return false;
-
- p = procfs_file_alloca(pid, "cmdline");
- f = fopen(p, "re");
- if (!f)
- return true; /* not really, but has the desired effect */
-
- count = fread(&c, 1, 1, f);
-
- /* Kernel threads have an empty cmdline */
- if (count <= 0)
- return true;
-
- /* Processes with argv[0][0] = '@' we ignore from the killing
- * spree.
- *
- * http://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons */
- if (count == 1 && c == '@')
- return true;
-
- return false;
-}
-
-static void wait_for_children(Set *pids, sigset_t *mask) {
- usec_t until;
-
- assert(mask);
-
- if (set_isempty(pids))
- return;
-
- until = now(CLOCK_MONOTONIC) + TIMEOUT_USEC;
- for (;;) {
- struct timespec ts;
- int k;
- usec_t n;
- void *p;
- Iterator i;
-
- /* First, let the kernel inform us about killed
- * children. Most processes will probably be our
- * children, but some are not (might be our
- * grandchildren instead...). */
- for (;;) {
- pid_t pid;
-
- pid = waitpid(-1, NULL, WNOHANG);
- if (pid == 0)
- break;
- if (pid < 0) {
- if (errno == ECHILD)
- break;
-
- log_error_errno(errno, "waitpid() failed: %m");
- return;
- }
-
- set_remove(pids, ULONG_TO_PTR(pid));
- }
-
- /* Now explicitly check who might be remaining, who
- * might not be our child. */
- SET_FOREACH(p, pids, i) {
-
- /* We misuse getpgid as a check whether a
- * process still exists. */
- if (getpgid((pid_t) PTR_TO_ULONG(p)) >= 0)
- continue;
-
- if (errno != ESRCH)
- continue;
-
- set_remove(pids, p);
- }
-
- if (set_isempty(pids))
- return;
-
- n = now(CLOCK_MONOTONIC);
- if (n >= until)
- return;
-
- timespec_store(&ts, until - n);
- k = sigtimedwait(mask, NULL, &ts);
- if (k != SIGCHLD) {
-
- if (k < 0 && errno != EAGAIN) {
- log_error_errno(errno, "sigtimedwait() failed: %m");
- return;
- }
-
- if (k >= 0)
- log_warning("sigtimedwait() returned unexpected signal.");
- }
- }
-}
-
-static int killall(int sig, Set *pids, bool send_sighup) {
- _cleanup_closedir_ DIR *dir = NULL;
- struct dirent *d;
-
- dir = opendir("/proc");
- if (!dir)
- return -errno;
-
- while ((d = readdir(dir))) {
- pid_t pid;
-
- if (d->d_type != DT_DIR &&
- d->d_type != DT_UNKNOWN)
- continue;
-
- if (parse_pid(d->d_name, &pid) < 0)
- continue;
-
- if (ignore_proc(pid))
- continue;
-
- if (sig == SIGKILL) {
- _cleanup_free_ char *s = NULL;
-
- get_process_comm(pid, &s);
- log_notice("Sending SIGKILL to PID "PID_FMT" (%s).", pid, strna(s));
- }
-
- if (kill(pid, sig) >= 0) {
- if (pids)
- set_put(pids, ULONG_TO_PTR(pid));
- } else if (errno != ENOENT)
- log_warning_errno(errno, "Could not kill %d: %m", pid);
-
- if (send_sighup) {
- /* Optionally, also send a SIGHUP signal, but
- only if the process has a controlling
- tty. This is useful to allow handling of
- shells which ignore SIGTERM but react to
- SIGHUP. We do not send this to processes that
- have no controlling TTY since we don't want to
- trigger reloads of daemon processes. Also we
- make sure to only send this after SIGTERM so
- that SIGTERM is always first in the queue. */
-
-
- if (get_ctty_devnr(pid, NULL) >= 0)
- kill(pid, SIGHUP);
- }
- }
-
- return set_size(pids);
-}
-
-void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup) {
- sigset_t mask, oldmask;
- _cleanup_set_free_ Set *pids = NULL;
-
- if (wait_for_exit)
- pids = set_new(NULL);
-
- assert_se(sigemptyset(&mask) == 0);
- assert_se(sigaddset(&mask, SIGCHLD) == 0);
- assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) == 0);
-
- if (kill(-1, SIGSTOP) < 0 && errno != ESRCH)
- log_warning_errno(errno, "kill(-1, SIGSTOP) failed: %m");
-
- killall(sig, pids, send_sighup);
-
- if (kill(-1, SIGCONT) < 0 && errno != ESRCH)
- log_warning_errno(errno, "kill(-1, SIGCONT) failed: %m");
-
- if (wait_for_exit)
- wait_for_children(pids, &mask);
-
- assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0);
-}
diff --git a/src/core/killall.h b/src/core/killall.h
deleted file mode 100644
index 986cf432c..000000000
--- a/src/core/killall.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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/>.
-***/
-
-void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup);
diff --git a/src/core/kmod-setup.c b/src/core/kmod-setup.c
deleted file mode 100644
index efbdf3168..000000000
--- a/src/core/kmod-setup.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 <unistd.h>
-#include <string.h>
-
-#ifdef HAVE_KMOD
-#include <libkmod.h>
-#endif
-
-#include "macro.h"
-#include "capability.h"
-#include "kmod-setup.h"
-
-#ifdef HAVE_KMOD
-static void systemd_kmod_log(
- void *data,
- int priority,
- const char *file, int line,
- const char *fn,
- const char *format,
- va_list args) {
-
- /* library logging is enabled at debug only */
- DISABLE_WARNING_FORMAT_NONLITERAL;
- log_internalv(LOG_DEBUG, 0, file, line, fn, format, args);
- REENABLE_WARNING;
-}
-
-static bool cmdline_check_kdbus(void) {
- return get_proc_cmdline_key("kdbus", NULL) > 0;
-}
-#endif
-
-int kmod_setup(void) {
-#ifdef HAVE_KMOD
-
- static const struct {
- const char *module;
- const char *path;
- bool warn;
- bool (*condition_fn)(void);
- } kmod_table[] = {
- /* auto-loading on use doesn't work before udev is up */
- { "autofs4", "/sys/class/misc/autofs", true, NULL },
-
- /* early configure of ::1 on the loopback device */
- { "ipv6", "/sys/module/ipv6", true, NULL },
-
- /* this should never be a module */
- { "unix", "/proc/net/unix", true, NULL },
-
- /* IPC is needed before we bring up any other services */
- { "kdbus", "/sys/fs/kdbus", false, cmdline_check_kdbus },
- };
- struct kmod_ctx *ctx = NULL;
- unsigned int i;
- int r;
-
- if (have_effective_cap(CAP_SYS_MODULE) == 0)
- return 0;
-
- for (i = 0; i < ELEMENTSOF(kmod_table); i++) {
- struct kmod_module *mod;
-
- if (kmod_table[i].path && access(kmod_table[i].path, F_OK) >= 0)
- continue;
-
- if (kmod_table[i].condition_fn && !kmod_table[i].condition_fn())
- continue;
-
- if (kmod_table[i].warn)
- log_debug("Your kernel apparently lacks built-in %s support. Might be "
- "a good idea to compile it in. We'll now try to work around "
- "this by loading the module...", kmod_table[i].module);
-
- if (!ctx) {
- ctx = kmod_new(NULL, NULL);
- if (!ctx)
- return log_oom();
-
- kmod_set_log_fn(ctx, systemd_kmod_log, NULL);
- kmod_load_resources(ctx);
- }
-
- r = kmod_module_new_from_name(ctx, kmod_table[i].module, &mod);
- if (r < 0) {
- log_error("Failed to lookup module '%s'", kmod_table[i].module);
- continue;
- }
-
- r = kmod_module_probe_insert_module(mod, KMOD_PROBE_APPLY_BLACKLIST, NULL, NULL, NULL, NULL);
- if (r == 0)
- log_info("Inserted module '%s'", kmod_module_get_name(mod));
- else if (r == KMOD_PROBE_APPLY_BLACKLIST)
- log_info("Module '%s' is blacklisted", kmod_module_get_name(mod));
- else if (kmod_table[i].warn)
- log_error("Failed to insert module '%s'", kmod_module_get_name(mod));
-
- kmod_module_unref(mod);
- }
-
- if (ctx)
- kmod_unref(ctx);
-
-#endif
- return 0;
-}
diff --git a/src/core/kmod-setup.h b/src/core/kmod-setup.h
deleted file mode 100644
index 24dcdddfa..000000000
--- a/src/core/kmod-setup.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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
deleted file mode 100644
index 11566af51..000000000
--- a/src/core/load-dropin.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 "load-dropin.h"
-#include "log.h"
-#include "strv.h"
-#include "unit-name.h"
-#include "conf-parser.h"
-#include "load-fragment.h"
-
-static int add_dependency_consumer(
- UnitDependency dependency,
- const char *entry,
- const char* filepath,
- void *arg) {
- Unit *u = arg;
- int r;
-
- assert(u);
-
- r = unit_add_dependency_by_name(u, dependency, entry, filepath, true);
- if (r < 0)
- log_error_errno(r, "Cannot add dependency %s to %s, ignoring: %m", entry, u->id);
-
- return 0;
-}
-
-int unit_load_dropin(Unit *u) {
- Iterator i;
- char *t, **f;
- int r;
-
- assert(u);
-
- /* Load dependencies from supplementary drop-in directories */
-
- SET_FOREACH(t, u->names, i) {
- char **p;
-
- STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
- unit_file_process_dir(u->manager->unit_path_cache, *p, t, ".wants", UNIT_WANTS,
- add_dependency_consumer, u, NULL);
- unit_file_process_dir(u->manager->unit_path_cache, *p, t, ".requires", UNIT_REQUIRES,
- add_dependency_consumer, u, NULL);
- }
- }
-
- r = unit_find_dropin_paths(u, &u->dropin_paths);
- if (r <= 0)
- return 0;
-
- STRV_FOREACH(f, u->dropin_paths) {
- config_parse(u->id, *f, NULL,
- UNIT_VTABLE(u)->sections,
- config_item_perf_lookup, load_fragment_gperf_lookup,
- false, false, false, u);
- }
-
- u->dropin_mtime = now(CLOCK_REALTIME);
-
- return 0;
-}
diff --git a/src/core/load-dropin.h b/src/core/load-dropin.h
deleted file mode 100644
index 1e018c452..000000000
--- a/src/core/load-dropin.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 "dropin.h"
-
-/* Read service data supplementary drop-in directories */
-
-static inline int unit_find_dropin_paths(Unit *u, char ***paths) {
- return unit_file_find_dropin_paths(u->manager->lookup_paths.unit_path,
- u->manager->unit_path_cache,
- u->names,
- paths);
-}
-
-int unit_load_dropin(Unit *u);
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
deleted file mode 100644
index 53059845e..000000000
--- a/src/core/load-fragment-gperf.gperf.m4
+++ /dev/null
@@ -1,360 +0,0 @@
-%{
-#include <stddef.h>
-#include "conf-parser.h"
-#include "load-fragment.h"
-#include "missing.h"
-%}
-struct ConfigPerfItem;
-%null_strings
-%language=ANSI-C
-%define slot-name section_and_lvalue
-%define hash-function-name load_fragment_gperf_hash
-%define lookup-function-name load_fragment_gperf_lookup
-%readonly-tables
-%omit-struct-type
-%struct-type
-%includes
-%%
-m4_dnl Define the context options only once
-m4_define(`EXEC_CONTEXT_CONFIG_ITEMS',
-`$1.WorkingDirectory, config_parse_unit_path_printf, 0, offsetof($1, exec_context.working_directory)
-$1.RootDirectory, config_parse_unit_path_printf, 0, offsetof($1, exec_context.root_directory)
-$1.User, config_parse_unit_string_printf, 0, offsetof($1, exec_context.user)
-$1.Group, config_parse_unit_string_printf, 0, offsetof($1, exec_context.group)
-$1.SupplementaryGroups, config_parse_strv, 0, offsetof($1, exec_context.supplementary_groups)
-$1.Nice, config_parse_exec_nice, 0, offsetof($1, exec_context)
-$1.OOMScoreAdjust, config_parse_exec_oom_score_adjust, 0, offsetof($1, exec_context)
-$1.IOSchedulingClass, config_parse_exec_io_class, 0, offsetof($1, exec_context)
-$1.IOSchedulingPriority, config_parse_exec_io_priority, 0, offsetof($1, exec_context)
-$1.CPUSchedulingPolicy, config_parse_exec_cpu_sched_policy, 0, offsetof($1, exec_context)
-$1.CPUSchedulingPriority, config_parse_exec_cpu_sched_prio, 0, offsetof($1, exec_context)
-$1.CPUSchedulingResetOnFork, config_parse_bool, 0, offsetof($1, exec_context.cpu_sched_reset_on_fork)
-$1.CPUAffinity, config_parse_exec_cpu_affinity, 0, offsetof($1, exec_context)
-$1.UMask, config_parse_mode, 0, offsetof($1, exec_context.umask)
-$1.Environment, config_parse_environ, 0, offsetof($1, exec_context.environment)
-$1.EnvironmentFile, config_parse_unit_env_file, 0, offsetof($1, exec_context.environment_files)
-$1.StandardInput, config_parse_input, 0, offsetof($1, exec_context.std_input)
-$1.StandardOutput, config_parse_output, 0, offsetof($1, exec_context.std_output)
-$1.StandardError, config_parse_output, 0, offsetof($1, exec_context.std_error)
-$1.TTYPath, config_parse_unit_path_printf, 0, offsetof($1, exec_context.tty_path)
-$1.TTYReset, config_parse_bool, 0, offsetof($1, exec_context.tty_reset)
-$1.TTYVHangup, config_parse_bool, 0, offsetof($1, exec_context.tty_vhangup)
-$1.TTYVTDisallocate, config_parse_bool, 0, offsetof($1, exec_context.tty_vt_disallocate)
-$1.SyslogIdentifier, config_parse_unit_string_printf, 0, offsetof($1, exec_context.syslog_identifier)
-$1.SyslogFacility, config_parse_log_facility, 0, offsetof($1, exec_context.syslog_priority)
-$1.SyslogLevel, config_parse_log_level, 0, offsetof($1, exec_context.syslog_priority)
-$1.SyslogLevelPrefix, config_parse_bool, 0, offsetof($1, exec_context.syslog_level_prefix)
-$1.Capabilities, config_parse_exec_capabilities, 0, offsetof($1, exec_context)
-$1.SecureBits, config_parse_exec_secure_bits, 0, offsetof($1, exec_context)
-$1.CapabilityBoundingSet, config_parse_bounding_set, 0, offsetof($1, exec_context.capability_bounding_set_drop)
-$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)
-m4_ifdef(`HAVE_SECCOMP',
-`$1.SystemCallFilter, config_parse_syscall_filter, 0, offsetof($1, exec_context)
-$1.SystemCallArchitectures, config_parse_syscall_archs, 0, offsetof($1, exec_context.syscall_archs)
-$1.SystemCallErrorNumber, config_parse_syscall_errno, 0, offsetof($1, exec_context)
-$1.RestrictAddressFamilies, config_parse_address_families, 0, offsetof($1, exec_context)',
-`$1.SystemCallFilter, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
-$1.SystemCallArchitectures, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
-$1.SystemCallErrorNumber, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
-$1.RestrictAddressFamilies, 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.ReadWriteDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_dirs)
-$1.ReadOnlyDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_dirs)
-$1.InaccessibleDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_dirs)
-$1.PrivateTmp, config_parse_bool, 0, offsetof($1, exec_context.private_tmp)
-$1.PrivateNetwork, config_parse_bool, 0, offsetof($1, exec_context.private_network)
-$1.PrivateDevices, config_parse_bool, 0, offsetof($1, exec_context.private_devices)
-$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.Personality, config_parse_personality, 0, offsetof($1, exec_context.personality)
-$1.RuntimeDirectoryMode, config_parse_mode, 0, offsetof($1, exec_context.runtime_directory_mode)
-$1.RuntimeDirectory, config_parse_runtime_directory, 0, offsetof($1, exec_context.runtime_directory)
-m4_ifdef(`HAVE_PAM',
-`$1.PAMName, config_parse_unit_string_printf, 0, offsetof($1, exec_context.pam_name)',
-`$1.PAMName, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
-$1.IgnoreSIGPIPE, config_parse_bool, 0, offsetof($1, exec_context.ignore_sigpipe)
-$1.UtmpIdentifier, config_parse_unit_string_printf, 0, offsetof($1, exec_context.utmp_id)
-m4_ifdef(`HAVE_SELINUX',
-`$1.SELinuxContext, config_parse_exec_selinux_context, 0, offsetof($1, exec_context)',
-`$1.SELinuxContext, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
-m4_ifdef(`HAVE_APPARMOR',
-`$1.AppArmorProfile, config_parse_exec_apparmor_profile, 0, offsetof($1, exec_context)',
-`$1.AppArmorProfile, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
-m4_ifdef(`HAVE_SMACK',
-`$1.SmackProcessLabel, config_parse_exec_smack_process_label, 0, offsetof($1, exec_context)',
-`$1.SmackProcessLabel, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')'
-)m4_dnl
-m4_define(`KILL_CONTEXT_CONFIG_ITEMS',
-`$1.SendSIGKILL, config_parse_bool, 0, offsetof($1, kill_context.send_sigkill)
-$1.SendSIGHUP, config_parse_bool, 0, offsetof($1, kill_context.send_sighup)
-$1.KillMode, config_parse_kill_mode, 0, offsetof($1, kill_context.kill_mode)
-$1.KillSignal, config_parse_kill_signal, 0, offsetof($1, kill_context.kill_signal)'
-)m4_dnl
-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.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)
-$1.MemoryAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.memory_accounting)
-$1.MemoryLimit, config_parse_memory_limit, 0, offsetof($1, cgroup_context)
-$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.BlockIOAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.blockio_accounting)
-$1.BlockIOWeight, config_parse_blockio_weight, 0, offsetof($1, cgroup_context.blockio_weight)
-$1.StartupBlockIOWeight, config_parse_blockio_weight, 0, offsetof($1, cgroup_context.startup_blockio_weight)
-$1.BlockIODeviceWeight, config_parse_blockio_device_weight, 0, offsetof($1, cgroup_context)
-$1.BlockIOReadBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context)
-$1.BlockIOWriteBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context)
-$1.Delegate, config_parse_bool, 0, offsetof($1, cgroup_context.delegate)'
-)m4_dnl
-Unit.Description, config_parse_unit_string_printf, 0, offsetof(Unit, description)
-Unit.Documentation, config_parse_documentation, 0, offsetof(Unit, documentation)
-Unit.SourcePath, config_parse_path, 0, offsetof(Unit, source_path)
-Unit.Requires, config_parse_unit_deps, UNIT_REQUIRES, 0
-Unit.RequiresOverridable, config_parse_unit_deps, UNIT_REQUIRES_OVERRIDABLE, 0
-Unit.Requisite, config_parse_unit_deps, UNIT_REQUISITE, 0
-Unit.RequisiteOverridable, config_parse_unit_deps, UNIT_REQUISITE_OVERRIDABLE, 0
-Unit.Wants, config_parse_unit_deps, UNIT_WANTS, 0
-Unit.BindsTo, config_parse_unit_deps, UNIT_BINDS_TO, 0
-Unit.BindTo, config_parse_unit_deps, UNIT_BINDS_TO, 0
-Unit.Conflicts, config_parse_unit_deps, UNIT_CONFLICTS, 0
-Unit.Before, config_parse_unit_deps, UNIT_BEFORE, 0
-Unit.After, config_parse_unit_deps, UNIT_AFTER, 0
-Unit.OnFailure, config_parse_unit_deps, UNIT_ON_FAILURE, 0
-Unit.PropagatesReloadTo, config_parse_unit_deps, UNIT_PROPAGATES_RELOAD_TO, 0
-Unit.PropagateReloadTo, config_parse_unit_deps, UNIT_PROPAGATES_RELOAD_TO, 0
-Unit.ReloadPropagatedFrom, config_parse_unit_deps, UNIT_RELOAD_PROPAGATED_FROM, 0
-Unit.PropagateReloadFrom, config_parse_unit_deps, UNIT_RELOAD_PROPAGATED_FROM, 0
-Unit.PartOf, config_parse_unit_deps, UNIT_PART_OF, 0
-Unit.JoinsNamespaceOf, config_parse_unit_deps, UNIT_JOINS_NAMESPACE_OF, 0
-Unit.RequiresMountsFor, config_parse_unit_requires_mounts_for, 0, 0
-Unit.StopWhenUnneeded, config_parse_bool, 0, offsetof(Unit, stop_when_unneeded)
-Unit.RefuseManualStart, config_parse_bool, 0, offsetof(Unit, refuse_manual_start)
-Unit.RefuseManualStop, config_parse_bool, 0, offsetof(Unit, refuse_manual_stop)
-Unit.AllowIsolate, config_parse_bool, 0, offsetof(Unit, allow_isolate)
-Unit.DefaultDependencies, config_parse_bool, 0, offsetof(Unit, default_dependencies)
-Unit.OnFailureJobMode, config_parse_job_mode, 0, offsetof(Unit, on_failure_job_mode)
-Unit.OnFailureIsolate, config_parse_job_mode_isolate, 0, offsetof(Unit, on_failure_job_mode)
-Unit.IgnoreOnIsolate, config_parse_bool, 0, offsetof(Unit, ignore_on_isolate)
-Unit.IgnoreOnSnapshot, config_parse_bool, 0, offsetof(Unit, ignore_on_snapshot)
-Unit.JobTimeoutSec, config_parse_sec, 0, offsetof(Unit, job_timeout)
-Unit.JobTimeoutAction, config_parse_failure_action, 0, offsetof(Unit, job_timeout_action)
-Unit.JobTimeoutRebootArgument, config_parse_string, 0, offsetof(Unit, job_timeout_reboot_arg)
-Unit.ConditionPathExists, config_parse_unit_condition_path, CONDITION_PATH_EXISTS, offsetof(Unit, conditions)
-Unit.ConditionPathExistsGlob, config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB, offsetof(Unit, conditions)
-Unit.ConditionPathIsDirectory, config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY, offsetof(Unit, conditions)
-Unit.ConditionPathIsSymbolicLink,config_parse_unit_condition_path, CONDITION_PATH_IS_SYMBOLIC_LINK,offsetof(Unit, conditions)
-Unit.ConditionPathIsMountPoint, config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT, offsetof(Unit, conditions)
-Unit.ConditionPathIsReadWrite, config_parse_unit_condition_path, CONDITION_PATH_IS_READ_WRITE, offsetof(Unit, conditions)
-Unit.ConditionDirectoryNotEmpty, config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, offsetof(Unit, conditions)
-Unit.ConditionFileNotEmpty, config_parse_unit_condition_path, CONDITION_FILE_NOT_EMPTY, offsetof(Unit, conditions)
-Unit.ConditionFileIsExecutable, config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE, offsetof(Unit, conditions)
-Unit.ConditionNeedsUpdate, config_parse_unit_condition_path, CONDITION_NEEDS_UPDATE, offsetof(Unit, conditions)
-Unit.ConditionFirstBoot, config_parse_unit_condition_string, CONDITION_FIRST_BOOT, offsetof(Unit, conditions)
-Unit.ConditionKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, offsetof(Unit, conditions)
-Unit.ConditionArchitecture, config_parse_unit_condition_string, CONDITION_ARCHITECTURE, offsetof(Unit, conditions)
-Unit.ConditionVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, offsetof(Unit, conditions)
-Unit.ConditionSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, offsetof(Unit, conditions)
-Unit.ConditionCapability, config_parse_unit_condition_string, CONDITION_CAPABILITY, offsetof(Unit, conditions)
-Unit.ConditionHost, config_parse_unit_condition_string, CONDITION_HOST, offsetof(Unit, conditions)
-Unit.ConditionACPower, config_parse_unit_condition_string, CONDITION_AC_POWER, offsetof(Unit, conditions)
-Unit.ConditionNull, config_parse_unit_condition_null, 0, offsetof(Unit, conditions)
-Unit.AssertPathExists, config_parse_unit_condition_path, CONDITION_PATH_EXISTS, offsetof(Unit, asserts)
-Unit.AssertPathExistsGlob, config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB, offsetof(Unit, asserts)
-Unit.AssertPathIsDirectory, config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY, offsetof(Unit, asserts)
-Unit.AssertPathIsSymbolicLink, config_parse_unit_condition_path, CONDITION_PATH_IS_SYMBOLIC_LINK,offsetof(Unit, asserts)
-Unit.AssertPathIsMountPoint, config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT, offsetof(Unit, asserts)
-Unit.AssertPathIsReadWrite, config_parse_unit_condition_path, CONDITION_PATH_IS_READ_WRITE, offsetof(Unit, asserts)
-Unit.AssertDirectoryNotEmpty, config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, offsetof(Unit, asserts)
-Unit.AssertFileNotEmpty, config_parse_unit_condition_path, CONDITION_FILE_NOT_EMPTY, offsetof(Unit, asserts)
-Unit.AssertFileIsExecutable, config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE, offsetof(Unit, asserts)
-Unit.AssertNeedsUpdate, config_parse_unit_condition_path, CONDITION_NEEDS_UPDATE, offsetof(Unit, asserts)
-Unit.AssertFirstBoot, config_parse_unit_condition_string, CONDITION_FIRST_BOOT, offsetof(Unit, asserts)
-Unit.AssertKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, offsetof(Unit, asserts)
-Unit.AssertArchitecture, config_parse_unit_condition_string, CONDITION_ARCHITECTURE, offsetof(Unit, asserts)
-Unit.AssertVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, offsetof(Unit, asserts)
-Unit.AssertSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, offsetof(Unit, asserts)
-Unit.AssertCapability, config_parse_unit_condition_string, CONDITION_CAPABILITY, offsetof(Unit, asserts)
-Unit.AssertHost, config_parse_unit_condition_string, CONDITION_HOST, offsetof(Unit, asserts)
-Unit.AssertACPower, config_parse_unit_condition_string, CONDITION_AC_POWER, offsetof(Unit, asserts)
-Unit.AssertNull, config_parse_unit_condition_null, 0, offsetof(Unit, asserts)
-m4_dnl
-Service.PIDFile, config_parse_unit_path_printf, 0, offsetof(Service, pid_file)
-Service.ExecStartPre, config_parse_exec, SERVICE_EXEC_START_PRE, offsetof(Service, exec_command)
-Service.ExecStart, config_parse_exec, SERVICE_EXEC_START, offsetof(Service, exec_command)
-Service.ExecStartPost, config_parse_exec, SERVICE_EXEC_START_POST, offsetof(Service, exec_command)
-Service.ExecReload, config_parse_exec, SERVICE_EXEC_RELOAD, offsetof(Service, exec_command)
-Service.ExecStop, config_parse_exec, SERVICE_EXEC_STOP, offsetof(Service, exec_command)
-Service.ExecStopPost, config_parse_exec, SERVICE_EXEC_STOP_POST, offsetof(Service, exec_command)
-Service.RestartSec, config_parse_sec, 0, offsetof(Service, restart_usec)
-Service.TimeoutSec, config_parse_service_timeout, 0, offsetof(Service, timeout_start_usec)
-Service.TimeoutStartSec, config_parse_service_timeout, 0, offsetof(Service, timeout_start_usec)
-Service.TimeoutStopSec, config_parse_service_timeout, 0, offsetof(Service, timeout_stop_usec)
-Service.WatchdogSec, config_parse_sec, 0, offsetof(Service, watchdog_usec)
-Service.StartLimitInterval, config_parse_sec, 0, offsetof(Service, start_limit.interval)
-Service.StartLimitBurst, config_parse_unsigned, 0, offsetof(Service, start_limit.burst)
-Service.StartLimitAction, config_parse_failure_action, 0, offsetof(Service, start_limit_action)
-Service.RebootArgument, config_parse_string, 0, offsetof(Service, reboot_arg)
-Service.FailureAction, config_parse_failure_action, 0, offsetof(Service, failure_action)
-Service.Type, config_parse_service_type, 0, offsetof(Service, type)
-Service.Restart, config_parse_service_restart, 0, offsetof(Service, restart)
-Service.PermissionsStartOnly, config_parse_bool, 0, offsetof(Service, permissions_start_only)
-Service.RootDirectoryStartOnly, config_parse_bool, 0, offsetof(Service, root_directory_start_only)
-Service.RemainAfterExit, config_parse_bool, 0, offsetof(Service, remain_after_exit)
-Service.GuessMainPID, config_parse_bool, 0, offsetof(Service, guess_main_pid)
-Service.RestartPreventExitStatus, config_parse_set_status, 0, offsetof(Service, restart_prevent_status)
-Service.RestartForceExitStatus, config_parse_set_status, 0, offsetof(Service, restart_force_status)
-Service.SuccessExitStatus, config_parse_set_status, 0, offsetof(Service, success_status)
-Service.SysVStartPriority, config_parse_warn_compat, DISABLED_LEGACY, 0
-Service.NonBlocking, config_parse_bool, 0, offsetof(Service, exec_context.non_blocking)
-Service.BusName, config_parse_bus_name, 0, offsetof(Service, bus_name)
-Service.FileDescriptorStoreMax, config_parse_unsigned, 0, offsetof(Service, n_fd_store_max)
-Service.NotifyAccess, config_parse_notify_access, 0, offsetof(Service, notify_access)
-Service.Sockets, config_parse_service_sockets, 0, 0
-m4_ifdef(`ENABLE_KDBUS',
-`Service.BusPolicy, config_parse_bus_endpoint_policy, 0, offsetof(Service, exec_context)',
-`Service.BusPolicy, config_parse_warn_compat, DISABLED_EXPERIMENTAL, 0')
-EXEC_CONTEXT_CONFIG_ITEMS(Service)m4_dnl
-CGROUP_CONTEXT_CONFIG_ITEMS(Service)m4_dnl
-KILL_CONTEXT_CONFIG_ITEMS(Service)m4_dnl
-m4_dnl
-Socket.ListenStream, config_parse_socket_listen, SOCKET_SOCKET, 0
-Socket.ListenDatagram, config_parse_socket_listen, SOCKET_SOCKET, 0
-Socket.ListenSequentialPacket, config_parse_socket_listen, SOCKET_SOCKET, 0
-Socket.ListenFIFO, config_parse_socket_listen, SOCKET_FIFO, 0
-Socket.ListenNetlink, config_parse_socket_listen, SOCKET_SOCKET, 0
-Socket.ListenSpecial, config_parse_socket_listen, SOCKET_SPECIAL, 0
-Socket.ListenMessageQueue, config_parse_socket_listen, SOCKET_MQUEUE, 0
-Socket.BindIPv6Only, config_parse_socket_bind, 0, 0,
-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)
-Socket.ExecStartPost, config_parse_exec, SOCKET_EXEC_START_POST, offsetof(Socket, exec_command)
-Socket.ExecStopPre, config_parse_exec, SOCKET_EXEC_STOP_PRE, offsetof(Socket, exec_command)
-Socket.ExecStopPost, config_parse_exec, SOCKET_EXEC_STOP_POST, offsetof(Socket, exec_command)
-Socket.TimeoutSec, config_parse_sec, 0, offsetof(Socket, timeout_usec)
-Socket.SocketUser, config_parse_unit_string_printf, 0, offsetof(Socket, user)
-Socket.SocketGroup, config_parse_unit_string_printf, 0, offsetof(Socket, group)
-Socket.SocketMode, config_parse_mode, 0, offsetof(Socket, socket_mode)
-Socket.DirectoryMode, config_parse_mode, 0, offsetof(Socket, directory_mode)
-Socket.Accept, config_parse_bool, 0, offsetof(Socket, accept)
-Socket.MaxConnections, config_parse_unsigned, 0, offsetof(Socket, max_connections)
-Socket.KeepAlive, config_parse_bool, 0, offsetof(Socket, keep_alive)
-Socket.KeepAliveTimeSec, config_parse_sec, 0, offsetof(Socket, keep_alive_time)
-Socket.KeepAliveIntervalSec, config_parse_sec, 0, offsetof(Socket, keep_alive_interval)
-Socket.KeepAliveProbes, config_parse_unsigned, 0, offsetof(Socket, keep_alive_cnt)
-Socket.DeferAcceptSec, config_parse_sec, 0, offsetof(Socket, defer_accept)
-Socket.NoDelay, config_parse_bool, 0, offsetof(Socket, no_delay)
-Socket.Priority, config_parse_int, 0, offsetof(Socket, priority)
-Socket.ReceiveBuffer, config_parse_iec_size, 0, offsetof(Socket, receive_buffer)
-Socket.SendBuffer, config_parse_iec_size, 0, offsetof(Socket, send_buffer)
-Socket.IPTOS, config_parse_ip_tos, 0, offsetof(Socket, ip_tos)
-Socket.IPTTL, config_parse_int, 0, offsetof(Socket, ip_ttl)
-Socket.Mark, config_parse_int, 0, offsetof(Socket, mark)
-Socket.PipeSize, config_parse_iec_size, 0, offsetof(Socket, pipe_size)
-Socket.FreeBind, config_parse_bool, 0, offsetof(Socket, free_bind)
-Socket.Transparent, config_parse_bool, 0, offsetof(Socket, transparent)
-Socket.Broadcast, config_parse_bool, 0, offsetof(Socket, broadcast)
-Socket.PassCredentials, config_parse_bool, 0, offsetof(Socket, pass_cred)
-Socket.PassSecurity, config_parse_bool, 0, offsetof(Socket, pass_sec)
-Socket.TCPCongestion, config_parse_string, 0, offsetof(Socket, tcp_congestion)
-Socket.ReusePort, config_parse_bool, 0, offsetof(Socket, reuse_port)
-Socket.MessageQueueMaxMessages, config_parse_long, 0, offsetof(Socket, mq_maxmsg)
-Socket.MessageQueueMessageSize, config_parse_long, 0, offsetof(Socket, mq_msgsize)
-Socket.RemoveOnStop, config_parse_bool, 0, offsetof(Socket, remove_on_stop)
-Socket.Symlinks, config_parse_unit_path_strv_printf, 0, offsetof(Socket, symlinks)
-Socket.Service, config_parse_socket_service, 0, 0
-m4_ifdef(`HAVE_SMACK',
-`Socket.SmackLabel, config_parse_string, 0, offsetof(Socket, smack)
-Socket.SmackLabelIPIn, config_parse_string, 0, offsetof(Socket, smack_ip_in)
-Socket.SmackLabelIPOut, config_parse_string, 0, offsetof(Socket, smack_ip_out)',
-`Socket.SmackLabel, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
-Socket.SmackLabelIPIn, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
-Socket.SmackLabelIPOut, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
-m4_ifdef(`HAVE_SELINUX',
-`Socket.SELinuxContextFromNet, config_parse_bool, 0, offsetof(Socket, selinux_context_from_net)',
-`Socket.SELinuxContextFromNet, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
-EXEC_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl
-CGROUP_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl
-KILL_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl
-m4_dnl
-BusName.Name, config_parse_string, 0, offsetof(BusName, name)
-BusName.Activating, config_parse_bool, 0, offsetof(BusName, activating)
-BusName.Service, config_parse_busname_service, 0, 0
-BusName.AllowUser, config_parse_bus_policy, 0, 0
-BusName.AllowGroup, config_parse_bus_policy, 0, 0
-BusName.AllowWorld, config_parse_bus_policy_world, 0, offsetof(BusName, policy_world)
-BusName.SELinuxContext, config_parse_exec_selinux_context, 0, 0
-BusName.AcceptFileDescriptors, config_parse_bool, 0, offsetof(BusName, accept_fd)
-m4_dnl
-Mount.What, config_parse_string, 0, offsetof(Mount, parameters_fragment.what)
-Mount.Where, config_parse_path, 0, offsetof(Mount, where)
-Mount.Options, config_parse_string, 0, offsetof(Mount, parameters_fragment.options)
-Mount.Type, config_parse_string, 0, offsetof(Mount, parameters_fragment.fstype)
-Mount.TimeoutSec, config_parse_sec, 0, offsetof(Mount, timeout_usec)
-Mount.DirectoryMode, config_parse_mode, 0, offsetof(Mount, directory_mode)
-Mount.SloppyOptions, config_parse_bool, 0, offsetof(Mount, sloppy_options)
-EXEC_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
-CGROUP_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
-KILL_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
-m4_dnl
-Automount.Where, config_parse_path, 0, offsetof(Automount, where)
-Automount.DirectoryMode, config_parse_mode, 0, offsetof(Automount, directory_mode)
-m4_dnl
-Swap.What, config_parse_path, 0, offsetof(Swap, parameters_fragment.what)
-Swap.Priority, config_parse_int, 0, offsetof(Swap, parameters_fragment.priority)
-Swap.Options, config_parse_string, 0, offsetof(Swap, parameters_fragment.options)
-Swap.TimeoutSec, config_parse_sec, 0, offsetof(Swap, timeout_usec)
-EXEC_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl
-CGROUP_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl
-KILL_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl
-m4_dnl
-Timer.OnCalendar, config_parse_timer, 0, 0
-Timer.OnActiveSec, config_parse_timer, 0, 0
-Timer.OnBootSec, config_parse_timer, 0, 0
-Timer.OnStartupSec, config_parse_timer, 0, 0
-Timer.OnUnitActiveSec, config_parse_timer, 0, 0
-Timer.OnUnitInactiveSec, config_parse_timer, 0, 0
-Timer.Persistent, config_parse_bool, 0, offsetof(Timer, persistent)
-Timer.WakeSystem, config_parse_bool, 0, offsetof(Timer, wake_system)
-Timer.AccuracySec, config_parse_sec, 0, offsetof(Timer, accuracy_usec)
-Timer.Unit, config_parse_trigger_unit, 0, 0
-m4_dnl
-Path.PathExists, config_parse_path_spec, 0, 0
-Path.PathExistsGlob, config_parse_path_spec, 0, 0
-Path.PathChanged, config_parse_path_spec, 0, 0
-Path.PathModified, config_parse_path_spec, 0, 0
-Path.DirectoryNotEmpty, config_parse_path_spec, 0, 0
-Path.Unit, config_parse_trigger_unit, 0, 0
-Path.MakeDirectory, config_parse_bool, 0, offsetof(Path, make_directory)
-Path.DirectoryMode, config_parse_mode, 0, offsetof(Path, directory_mode)
-m4_dnl
-CGROUP_CONTEXT_CONFIG_ITEMS(Slice)m4_dnl
-m4_dnl
-CGROUP_CONTEXT_CONFIG_ITEMS(Scope)m4_dnl
-KILL_CONTEXT_CONFIG_ITEMS(Scope)m4_dnl
-Scope.TimeoutStopSec, config_parse_sec, 0, offsetof(Scope, timeout_stop_usec)
-m4_dnl The [Install] section is ignored here.
-Install.Alias, NULL, 0, 0
-Install.WantedBy, NULL, 0, 0
-Install.RequiredBy, NULL, 0, 0
-Install.Also, NULL, 0, 0
-Install.DefaultInstance, NULL, 0, 0
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
deleted file mode 100644
index 1553f8cda..000000000
--- a/src/core/load-fragment.c
+++ /dev/null
@@ -1,3771 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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/>.
-***/
-
-#include <linux/oom.h>
-#include <errno.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sched.h>
-#include <linux/fs.h>
-#include <sys/stat.h>
-#include <sys/resource.h>
-
-#ifdef HAVE_SECCOMP
-#include <seccomp.h>
-#endif
-
-#include "unit.h"
-#include "strv.h"
-#include "conf-parser.h"
-#include "load-fragment.h"
-#include "log.h"
-#include "ioprio.h"
-#include "securebits.h"
-#include "missing.h"
-#include "unit-name.h"
-#include "unit-printf.h"
-#include "utf8.h"
-#include "path-util.h"
-#include "env-util.h"
-#include "cgroup.h"
-#include "bus-util.h"
-#include "bus-error.h"
-#include "errno-list.h"
-#include "af-list.h"
-#include "cap-list.h"
-#include "bus-internal.h"
-
-#ifdef HAVE_SECCOMP
-#include "seccomp-util.h"
-#endif
-
-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, EINVAL,
- "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, EINVAL,
- "Support for option %s= has been removed and it is ignored", lvalue);
- break;
- case DISABLED_EXPERIMENTAL:
- log_syntax(unit, LOG_INFO, filename, line, EINVAL,
- "Support for option %s= has not yet been enabled and it is ignored", lvalue);
- break;
- };
-
- return 0;
-}
-
-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) {
-
- UnitDependency d = ltype;
- Unit *u = userdata;
- const char *word, *state;
- size_t l;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *t = NULL, *k = NULL;
- int r;
-
- t = strndup(word, l);
- if (!t)
- return log_oom();
-
- r = unit_name_printf(u, t, &k);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", strerror(-r));
- continue;
- }
-
- r = unit_add_dependency_by_name(u, d, k, NULL, true);
- if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to add dependency on %s, ignoring: %s", k, strerror(-r));
- }
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
-
- return 0;
-}
-
-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) {
-
- _cleanup_free_ char *k = NULL;
- Unit *u = userdata;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(u);
-
- 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);
- return 0;
- }
-
- return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, 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) {
-
- Unit *u = userdata;
- _cleanup_free_ char *k = NULL;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(u);
-
- 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: %s", rvalue, strerror(-r));
-
- return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype,
- k ? k : rvalue, data, 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) {
-
- _cleanup_free_ char *k = NULL;
- Unit *u = userdata;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(u);
-
- 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: %s", rvalue, strerror(-r));
- return 0;
- }
-
- return config_parse_path(unit, filename, line, section, section_line, lvalue, ltype, k, data, 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) {
-
- char ***x = data;
- const char *word, *state;
- Unit *u = userdata;
- size_t l;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(u);
-
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *k = NULL;
- char t[l+1];
-
- memcpy(t, word, l);
- t[l] = 0;
-
- r = unit_full_printf(u, t, &k);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to resolve unit specifiers on %s, ignoring: %s", t, strerror(-r));
- return 0;
- }
-
- if (!utf8_is_valid(k)) {
- log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
- return 0;
- }
-
- if (!path_is_absolute(k)) {
- log_syntax(unit, LOG_ERR, filename, line, -r, "Symlink path %s is not absolute, ignoring: %s", k, strerror(-r));
- return 0;
- }
-
- path_kill_slashes(k);
-
- r = strv_push(x, k);
- if (r < 0)
- return log_oom();
-
- k = NULL;
- }
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Invalid syntax, ignoring.");
-
- return 0;
-}
-
-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) {
-
- _cleanup_free_ SocketPort *p = NULL;
- SocketPort *tail;
- Socket *s;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- s = SOCKET(data);
-
- if (isempty(rvalue)) {
- /* An empty assignment removes all ports */
- socket_free_ports(s);
- return 0;
- }
-
- p = new0(SocketPort, 1);
- if (!p)
- return log_oom();
-
- if (ltype != SOCKET_SOCKET) {
-
- p->type = ltype;
- r = unit_full_printf(UNIT(s), rvalue, &p->path);
- if (r < 0) {
- p->path = strdup(rvalue);
- if (!p->path)
- return log_oom();
- else
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve unit specifiers on %s, ignoring: %s", rvalue, strerror(-r));
- }
-
- path_kill_slashes(p->path);
-
- } 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: %s", rvalue, strerror(-r));
-
- r = socket_address_parse_netlink(&p->address, k ?: rvalue);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse address value, ignoring: %s", rvalue);
- return 0;
- }
-
- } 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: %s", rvalue, strerror(-r));
-
- r = socket_address_parse(&p->address, k ? k : rvalue);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse address value, ignoring: %s", rvalue);
- return 0;
- }
-
- if (streq(lvalue, "ListenStream"))
- p->address.type = SOCK_STREAM;
- else if (streq(lvalue, "ListenDatagram"))
- p->address.type = SOCK_DGRAM;
- else {
- assert(streq(lvalue, "ListenSequentialPacket"));
- p->address.type = SOCK_SEQPACKET;
- }
-
- if (socket_address_family(&p->address) != AF_LOCAL && p->address.type == SOCK_SEQPACKET) {
- log_syntax(unit, LOG_ERR, filename, line, EOPNOTSUPP,
- "Address family not supported, ignoring: %s", rvalue);
- return 0;
- }
- }
-
- p->fd = -1;
- p->socket = s;
-
- if (s->ports) {
- LIST_FIND_TAIL(port, s->ports, tail);
- LIST_INSERT_AFTER(port, s->ports, tail, p);
- } else
- LIST_PREPEND(port, s->ports, p);
- p = NULL;
-
- 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 = socket_address_bind_ipv6_only_from_string(rvalue);
- if (b < 0) {
- int r;
-
- r = parse_boolean(rvalue);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse bind IPv6 only value, ignoring: %s", rvalue);
- return 0;
- }
-
- s->bind_ipv6_only = r ? SOCKET_ADDRESS_IPV6_ONLY : SOCKET_ADDRESS_BOTH;
- } else
- s->bind_ipv6_only = b;
-
- return 0;
-}
-
-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) {
-
- ExecContext *c = data;
- int priority, r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- r = safe_atoi(rvalue, &priority);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse nice priority, ignoring: %s. ", rvalue);
- return 0;
- }
-
- if (priority < PRIO_MIN || priority >= PRIO_MAX) {
- log_syntax(unit, LOG_ERR, filename, line, ERANGE,
- "Nice priority out of range, ignoring: %s", rvalue);
- return 0;
- }
-
- c->nice = priority;
- c->nice_set = true;
-
- 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) {
-
- ExecContext *c = data;
- int oa, r;
-
- assert(filename);
- assert(lvalue);
- 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);
- return 0;
- }
-
- if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
- log_syntax(unit, LOG_ERR, filename, line, ERANGE,
- "OOM score adjust value out of range, ignoring: %s", rvalue);
- return 0;
- }
-
- c->oom_score_adjust = oa;
- c->oom_score_adjust_set = true;
-
- return 0;
-}
-
-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) {
-
- ExecCommand **e = data, *nce;
- char *path, **n;
- unsigned k;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(e);
-
- e += ltype;
-
- if (isempty(rvalue)) {
- /* An empty assignment resets the list */
- *e = exec_command_free_list(*e);
- return 0;
- }
-
- /* We accept an absolute path as first argument, or
- * alternatively an absolute prefixed with @ to allow
- * overriding of argv[0]. */
- for (;;) {
- int i;
- const char *word, *state, *reason;
- size_t l;
- bool separate_argv0 = false, ignore = false;
-
- path = NULL;
- nce = NULL;
- n = NULL;
-
- rvalue += strspn(rvalue, WHITESPACE);
-
- if (rvalue[0] == 0)
- break;
-
- k = 0;
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- if (k == 0) {
- for (i = 0; i < 2; i++) {
- if (*word == '-' && !ignore) {
- ignore = true;
- word ++;
- }
-
- if (*word == '@' && !separate_argv0) {
- separate_argv0 = true;
- word ++;
- }
- }
- } else
- if (strneq(word, ";", MAX(l, 1U)))
- goto found;
-
- k++;
- }
- if (!isempty(state)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
- return 0;
- }
-
- found:
- /* If separate_argv0, we'll move first element to path variable */
- n = new(char*, MAX(k + !separate_argv0, 1u));
- if (!n)
- return log_oom();
-
- k = 0;
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- char *c;
- unsigned skip;
-
- if (separate_argv0 ? path == NULL : k == 0) {
- /* first word, very special */
- skip = separate_argv0 + ignore;
-
- /* skip special chars in the beginning */
- assert(skip < l);
-
- } else if (strneq(word, ";", MAX(l, 1U)))
- /* new commandline */
- break;
-
- else
- skip = strneq(word, "\\;", MAX(l, 1U));
-
- c = cunescape_length(word + skip, l - skip);
- if (!c) {
- r = log_oom();
- goto fail;
- }
-
- if (!utf8_is_valid(c)) {
- log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
- r = 0;
- goto fail;
- }
-
- /* where to stuff this? */
- if (separate_argv0 && path == NULL)
- path = c;
- else
- n[k++] = c;
- }
-
- n[k] = NULL;
-
- if (!n[0])
- reason = "Empty executable name or zeroeth argument";
- else if (!string_is_safe(path ?: n[0]))
- reason = "Executable path contains special characters";
- else if (!path_is_absolute(path ?: n[0]))
- reason = "Executable path is not absolute";
- else if (endswith(path ?: n[0], "/"))
- reason = "Executable path specifies a directory";
- else
- goto ok;
-
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "%s, ignoring: %s", reason, rvalue);
- r = 0;
- goto fail;
-
-ok:
- if (!path) {
- path = strdup(n[0]);
- if (!path) {
- r = log_oom();
- goto fail;
- }
- }
-
- nce = new0(ExecCommand, 1);
- if (!nce) {
- r = log_oom();
- goto fail;
- }
-
- nce->argv = n;
- nce->path = path;
- nce->ignore = ignore;
-
- path_kill_slashes(nce->path);
-
- exec_command_append_list(e, nce);
-
- rvalue = state;
- }
-
- return 0;
-
-fail:
- n[k] = NULL;
- strv_free(n);
- free(path);
- free(nce);
-
- return r;
-}
-
-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,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Socket *s = data;
- char *n;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (rvalue[0] && !streq(rvalue, "*")) {
- n = strdup(rvalue);
- if (!n)
- return log_oom();
- } else
- n = NULL;
-
- free(s->bind_to_device);
- s->bind_to_device = n;
-
- return 0;
-}
-
-DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "Failed to parse output specifier");
-DEFINE_CONFIG_PARSE_ENUM(config_parse_input, exec_input, ExecInput, "Failed to parse input specifier");
-
-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) {
-
- ExecContext *c = data;
- int x;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- x = ioprio_class_from_string(rvalue);
- if (x < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse IO scheduling class, ignoring: %s", rvalue);
- return 0;
- }
-
- c->ioprio = IOPRIO_PRIO_VALUE(x, IOPRIO_PRIO_DATA(c->ioprio));
- c->ioprio_set = true;
-
- return 0;
-}
-
-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) {
-
- ExecContext *c = data;
- int i, r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- r = safe_atoi(rvalue, &i);
- if (r < 0 || i < 0 || i >= IOPRIO_BE_NR) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse IO priority, ignoring: %s", rvalue);
- return 0;
- }
-
- c->ioprio = IOPRIO_PRIO_VALUE(IOPRIO_PRIO_CLASS(c->ioprio), i);
- c->ioprio_set = true;
-
- return 0;
-}
-
-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) {
-
-
- ExecContext *c = data;
- int x;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- x = sched_policy_from_string(rvalue);
- if (x < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -x,
- "Failed to parse CPU scheduling policy, ignoring: %s", rvalue);
- return 0;
- }
-
- c->cpu_sched_policy = x;
- /* Moving to or from real-time policy? We need to adjust the priority */
- c->cpu_sched_priority = CLAMP(c->cpu_sched_priority, sched_get_priority_min(x), sched_get_priority_max(x));
- c->cpu_sched_set = true;
-
- return 0;
-}
-
-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) {
-
- ExecContext *c = data;
- int i, min, max, r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- 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);
- return 0;
- }
-
- /* On Linux RR/FIFO range from 1 to 99 and OTHER/BATCH may only be 0 */
- min = sched_get_priority_min(c->cpu_sched_policy);
- max = sched_get_priority_max(c->cpu_sched_policy);
-
- if (i < min || i > max) {
- log_syntax(unit, LOG_ERR, filename, line, ERANGE,
- "CPU scheduling priority is out of range, ignoring: %s", rvalue);
- return 0;
- }
-
- c->cpu_sched_priority = i;
- c->cpu_sched_set = true;
-
- return 0;
-}
-
-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) {
-
- ExecContext *c = data;
- const char *word, *state;
- size_t l;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (isempty(rvalue)) {
- /* An empty assignment resets the CPU list */
- if (c->cpuset)
- CPU_FREE(c->cpuset);
- c->cpuset = NULL;
- return 0;
- }
-
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *t = NULL;
- int r;
- unsigned cpu;
-
- t = strndup(word, l);
- if (!t)
- return log_oom();
-
- r = safe_atou(t, &cpu);
-
- if (!c->cpuset) {
- c->cpuset = cpu_set_malloc(&c->cpuset_ncpus);
- if (!c->cpuset)
- return log_oom();
- }
-
- if (r < 0 || cpu >= c->cpuset_ncpus) {
- log_syntax(unit, LOG_ERR, filename, line, ERANGE,
- "Failed to parse CPU affinity '%s', ignoring: %s", t, rvalue);
- return 0;
- }
-
- CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
- }
- if (!isempty(state))
- log_syntax(unit, LOG_WARNING, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
-
- return 0;
-}
-
-int config_parse_exec_capabilities(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;
- cap_t cap;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- cap = cap_from_text(rvalue);
- if (!cap) {
- log_syntax(unit, LOG_ERR, filename, line, errno,
- "Failed to parse capabilities, ignoring: %s", rvalue);
- return 0;
- }
-
- if (c->capabilities)
- cap_free(c->capabilities);
- c->capabilities = cap;
-
- 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;
- size_t l;
- const char *word, *state;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (isempty(rvalue)) {
- /* An empty assignment resets the field */
- c->secure_bits = 0;
- return 0;
- }
-
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- if (first_word(word, "keep-caps"))
- c->secure_bits |= 1<<SECURE_KEEP_CAPS;
- else if (first_word(word, "keep-caps-locked"))
- c->secure_bits |= 1<<SECURE_KEEP_CAPS_LOCKED;
- else if (first_word(word, "no-setuid-fixup"))
- c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP;
- else if (first_word(word, "no-setuid-fixup-locked"))
- c->secure_bits |= 1<<SECURE_NO_SETUID_FIXUP_LOCKED;
- else if (first_word(word, "noroot"))
- c->secure_bits |= 1<<SECURE_NOROOT;
- else if (first_word(word, "noroot-locked"))
- c->secure_bits |= 1<<SECURE_NOROOT_LOCKED;
- else {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse secure bits, ignoring: %s", rvalue);
- return 0;
- }
- }
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid syntax, garbage at the end, ignoring.");
-
- return 0;
-}
-
-int config_parse_bounding_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) {
-
- uint64_t *capability_bounding_set_drop = data;
- const char *word, *state;
- size_t l;
- bool invert = false;
- uint64_t sum = 0;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (rvalue[0] == '~') {
- invert = true;
- rvalue++;
- }
-
- /* Note that we store this inverted internally, since the
- * kernel wants it like this. But we actually expose it
- * non-inverted everywhere to have a fully normalized
- * interface. */
-
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *t = NULL;
- int cap;
-
- t = strndup(word, l);
- if (!t)
- return log_oom();
-
- cap = capability_from_name(t);
- if (cap < 0) {
- log_syntax(unit, LOG_ERR, filename, line, errno, "Failed to parse capability in bounding set, ignoring: %s", t);
- continue;
- }
-
- sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
- }
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
-
- if (invert)
- *capability_bounding_set_drop |= sum;
- else
- *capability_bounding_set_drop |= ~sum;
-
- 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;
- unsigned long long u;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- rl += ltype;
-
- if (streq(rvalue, "infinity"))
- u = (unsigned long long) RLIM_INFINITY;
- else {
- int r;
-
- r = safe_atollu(rvalue, &u);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse resource value, ignoring: %s", rvalue);
- return 0;
- }
- }
-
- if (!*rl) {
- *rl = new(struct rlimit, 1);
- if (!*rl)
- return log_oom();
- }
-
- (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
- return 0;
-}
-
-DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
-
-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 *sig = data;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(sig);
-
- r = signal_from_string_try_harder(rvalue);
- if (r <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse kill signal, ignoring: %s", rvalue);
- return 0;
- }
-
- *sig = r;
- return 0;
-}
-
-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;
- const char *word, *state;
- size_t l;
- unsigned long flags = 0;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- FOREACH_WORD_SEPARATOR(word, l, rvalue, ", ", state) {
- _cleanup_free_ char *t;
-
- t = strndup(word, l);
- if (!t)
- return log_oom();
-
- if (streq(t, "shared"))
- flags = MS_SHARED;
- else if (streq(t, "slave"))
- flags = MS_SLAVE;
- else if (streq(word, "private"))
- flags = MS_PRIVATE;
- else {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse mount flag %s, ignoring: %s", t, rvalue);
- return 0;
- }
- }
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
-
- c->mount_flags = flags;
- return 0;
-}
-
-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) {
-
- ExecContext *c = data;
- Unit *u = userdata;
- bool ignore;
- char *k;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (isempty(rvalue)) {
- free(c->selinux_context);
- c->selinux_context = NULL;
- c->selinux_context_ignore = false;
- return 0;
- }
-
- if (rvalue[0] == '-') {
- ignore = true;
- rvalue++;
- } else
- ignore = false;
-
- r = unit_name_printf(u, rvalue, &k);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", strerror(-r));
- return 0;
- }
-
- free(c->selinux_context);
- c->selinux_context = k;
- c->selinux_context_ignore = ignore;
-
- return 0;
-}
-
-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) {
-
- ExecContext *c = data;
- Unit *u = userdata;
- bool ignore;
- char *k;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (isempty(rvalue)) {
- free(c->apparmor_profile);
- c->apparmor_profile = NULL;
- c->apparmor_profile_ignore = false;
- return 0;
- }
-
- if (rvalue[0] == '-') {
- ignore = true;
- rvalue++;
- } else
- ignore = false;
-
- r = unit_name_printf(u, rvalue, &k);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", strerror(-r));
- return 0;
- }
-
- free(c->apparmor_profile);
- c->apparmor_profile = k;
- c->apparmor_profile_ignore = ignore;
-
- return 0;
-}
-
-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) {
-
- ExecContext *c = data;
- Unit *u = userdata;
- bool ignore;
- char *k;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (isempty(rvalue)) {
- free(c->smack_process_label);
- c->smack_process_label = NULL;
- c->smack_process_label_ignore = false;
- return 0;
- }
-
- if (rvalue[0] == '-') {
- ignore = true;
- rvalue++;
- } else
- ignore = false;
-
- r = unit_name_printf(u, rvalue, &k);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", strerror(-r));
- return 0;
- }
-
- free(c->smack_process_label);
- c->smack_process_label = k;
- c->smack_process_label_ignore = ignore;
-
- return 0;
-}
-
-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) {
-
- Timer *t = data;
- usec_t u = 0;
- TimerValue *v;
- TimerBase b;
- CalendarSpec *c = NULL;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (isempty(rvalue)) {
- /* Empty assignment resets list */
- timer_free_values(t);
- return 0;
- }
-
- b = timer_base_from_string(lvalue);
- if (b < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -b,
- "Failed to parse timer base, ignoring: %s", lvalue);
- return 0;
- }
-
- if (b == TIMER_CALENDAR) {
- if (calendar_spec_from_string(rvalue, &c) < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse calendar specification, ignoring: %s",
- rvalue);
- return 0;
- }
- } else {
- if (parse_sec(rvalue, &u) < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse timer value, ignoring: %s",
- rvalue);
- return 0;
- }
- }
-
- v = new0(TimerValue, 1);
- if (!v) {
- calendar_spec_free(c);
- return log_oom();
- }
-
- v->base = b;
- v->value = u;
- v->calendar_spec = c;
-
- LIST_PREPEND(value, t->values, v);
-
- return 0;
-}
-
-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) {
-
- _cleanup_free_ char *p = NULL;
- Unit *u = data;
- UnitType type;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (!set_isempty(u->dependencies[UNIT_TRIGGERS])) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Multiple units to trigger specified, ignoring: %s", rvalue);
- return 0;
- }
-
- r = unit_name_printf(u, rvalue, &p);
- if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", strerror(-r));
-
- type = unit_name_to_type(p ?: rvalue);
- if (type < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Unit type not valid, ignoring: %s", rvalue);
- return 0;
- }
-
- if (type == u->type) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trigger cannot be of same type, ignoring: %s", rvalue);
- return 0;
- }
-
- r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p ?: rvalue, NULL, true);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to add trigger on %s, ignoring: %s", p ?: rvalue, strerror(-r));
- return 0;
- }
-
- return 0;
-}
-
-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) {
-
- Path *p = data;
- PathSpec *s;
- PathType b;
- _cleanup_free_ char *k = NULL;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (isempty(rvalue)) {
- /* Empty assignment clears list */
- path_free_specs(p);
- return 0;
- }
-
- b = path_type_from_string(lvalue);
- if (b < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse path type, ignoring: %s", lvalue);
- return 0;
- }
-
- r = unit_full_printf(UNIT(p), rvalue, &k);
- if (r < 0) {
- k = strdup(rvalue);
- if (!k)
- return log_oom();
- else
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve unit specifiers on %s. Ignoring.",
- rvalue);
- }
-
- if (!path_is_absolute(k)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Path is not absolute, ignoring: %s", k);
- return 0;
- }
-
- s = new0(PathSpec, 1);
- if (!s)
- return log_oom();
-
- s->unit = UNIT(p);
- s->path = path_kill_slashes(k);
- k = NULL;
- s->type = b;
- s->inotify_fd = -1;
-
- LIST_PREPEND(spec, p->specs, s);
-
- return 0;
-}
-
-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) {
-
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- Socket *s = data;
- int r;
- Unit *x;
- _cleanup_free_ char *p = NULL;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- r = unit_name_printf(UNIT(s), rvalue, &p);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
- return 0;
- }
-
- if (!endswith(p, ".service")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type service, ignoring: %s", rvalue);
- return 0;
- }
-
- r = manager_load_unit(UNIT(s)->manager, p, NULL, &error, &x);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r, "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
- return 0;
- }
-
- unit_ref_set(&s->service, x);
-
- return 0;
-}
-
-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) {
-
- Service *s = data;
- const char *word, *state;
- size_t l;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *t = NULL, *k = NULL;
-
- t = strndup(word, l);
- if (!t)
- return log_oom();
-
- r = unit_name_printf(UNIT(s), t, &k);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
- continue;
- }
-
- if (!endswith(k, ".socket")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Unit must be of type socket, ignoring: %s", k);
- continue;
- }
-
- r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
- if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
-
- r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
- if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
- }
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Trailing garbage, ignoring.");
-
- return 0;
-}
-
-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) {
-
- _cleanup_free_ char *k = NULL;
- Unit *u = userdata;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(u);
-
- 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);
- return 0;
- }
-
- if (!service_name_is_valid(k)) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Invalid bus name %s, ignoring.", k);
- return 0;
- }
-
- return config_parse_string(unit, filename, line, section, section_line, lvalue, ltype, k, data, 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) {
-
- Service *s = userdata;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(s);
-
- r = config_parse_sec(unit, filename, line, section, section_line, lvalue, ltype,
- rvalue, data, userdata);
- if (r < 0)
- return r;
-
- if (streq(lvalue, "TimeoutSec")) {
- s->start_timeout_defined = true;
- s->timeout_stop_usec = s->timeout_start_usec;
- } else if (streq(lvalue, "TimeoutStartSec"))
- s->start_timeout_defined = true;
-
- return 0;
-}
-
-int config_parse_busname_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) {
-
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- BusName *n = data;
- int r;
- Unit *x;
- _cleanup_free_ char *p = NULL;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- r = unit_name_printf(UNIT(n), rvalue, &p);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", rvalue);
- return 0;
- }
-
- if (!endswith(p, ".service")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Unit must be of type service, ignoring: %s", rvalue);
- return 0;
- }
-
- r = manager_load_unit(UNIT(n)->manager, p, NULL, &error, &x);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to load unit %s, ignoring: %s", rvalue, bus_error_message(&error, r));
- return 0;
- }
-
- unit_ref_set(&n->service, x);
-
- return 0;
-}
-
-DEFINE_CONFIG_PARSE_ENUM(config_parse_bus_policy_world, bus_policy_access, BusPolicyAccess, "Failed to parse bus name policy access");
-
-int config_parse_bus_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) {
-
- _cleanup_free_ BusNamePolicy *p = NULL;
- _cleanup_free_ char *id_str = NULL;
- BusName *busname = data;
- char *access_str;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- p = new0(BusNamePolicy, 1);
- if (!p)
- return log_oom();
-
- if (streq(lvalue, "AllowUser"))
- p->type = BUSNAME_POLICY_TYPE_USER;
- else if (streq(lvalue, "AllowGroup"))
- p->type = BUSNAME_POLICY_TYPE_GROUP;
- else
- assert_not_reached("Unknown lvalue");
-
- id_str = strdup(rvalue);
- if (!id_str)
- return log_oom();
-
- access_str = strpbrk(id_str, WHITESPACE);
- if (!access_str) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid busname policy value '%s'", rvalue);
- return 0;
- }
-
- *access_str = '\0';
- access_str++;
- access_str += strspn(access_str, WHITESPACE);
-
- p->access = bus_policy_access_from_string(access_str);
- if (p->access < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid busname policy access type '%s'", access_str);
- return 0;
- }
-
- p->name = id_str;
- id_str = NULL;
-
- LIST_PREPEND(policy, busname->policy, p);
- p = NULL;
-
- return 0;
-}
-
-int config_parse_bus_endpoint_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) {
-
- _cleanup_free_ char *name = NULL;
- BusPolicyAccess access;
- ExecContext *c = data;
- char *access_str;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- name = strdup(rvalue);
- if (!name)
- return log_oom();
-
- access_str = strpbrk(name, WHITESPACE);
- if (!access_str) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid endpoint policy value '%s'", rvalue);
- return 0;
- }
-
- *access_str = '\0';
- access_str++;
- access_str += strspn(access_str, WHITESPACE);
-
- access = bus_policy_access_from_string(access_str);
- if (access <= _BUS_POLICY_ACCESS_INVALID ||
- access >= _BUS_POLICY_ACCESS_MAX) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid endpoint policy access type '%s'", access_str);
- return 0;
- }
-
- if (!c->bus_endpoint) {
- r = bus_endpoint_new(&c->bus_endpoint);
-
- if (r < 0)
- return r;
- }
-
- return bus_endpoint_add_policy(c->bus_endpoint, name, access);
-}
-
-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) {
-
- char ***env = data;
- Unit *u = userdata;
- _cleanup_free_ char *n = NULL;
- const char *s;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (isempty(rvalue)) {
- /* Empty assignment frees the list */
- strv_free(*env);
- *env = NULL;
- return 0;
- }
-
- 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);
-
- s = n ?: rvalue;
- if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Path '%s' is not absolute, ignoring.", s);
- return 0;
- }
-
- r = strv_extend(env, s);
- if (r < 0)
- return log_oom();
-
- return 0;
-}
-
-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) {
-
- Unit *u = userdata;
- char*** env = data;
- const char *word, *state;
- size_t l;
- _cleanup_free_ char *k = NULL;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (isempty(rvalue)) {
- /* Empty assignment resets the list */
- strv_free(*env);
- *env = NULL;
- return 0;
- }
-
- if (u) {
- r = unit_full_printf(u, rvalue, &k);
- if (r < 0)
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to resolve specifiers, ignoring: %s", rvalue);
- }
-
- if (!k)
- k = strdup(rvalue);
- if (!k)
- return log_oom();
-
- FOREACH_WORD_QUOTED(word, l, k, state) {
- _cleanup_free_ char *n;
- char **x;
-
- n = cunescape_length(word, l);
- if (!n)
- return log_oom();
-
- if (!env_assignment_is_valid(n)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid environment assignment, ignoring: %s", rvalue);
- continue;
- }
-
- x = strv_env_set(*env, n);
- if (!x)
- return log_oom();
-
- strv_free(*env);
- *env = x;
- }
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
-
- 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, EINVAL,
- "Failed to parse IP TOS value, ignoring: %s", rvalue);
- return 0;
- }
-
- *ip_tos = x;
- return 0;
-}
-
-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) {
-
- _cleanup_free_ char *p = NULL;
- Condition **list = data, *c;
- ConditionType t = ltype;
- bool trigger, negate;
- Unit *u = userdata;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (isempty(rvalue)) {
- /* Empty assignment resets the list */
- *list = condition_free_list(*list);
- return 0;
- }
-
- trigger = rvalue[0] == '|';
- if (trigger)
- rvalue++;
-
- negate = rvalue[0] == '!';
- if (negate)
- rvalue++;
-
- 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);
- return 0;
- }
-
- if (!path_is_absolute(p)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL, "Path in condition not absolute, ignoring: %s", p);
- return 0;
- }
-
- c = condition_new(t, p, trigger, negate);
- if (!c)
- return log_oom();
-
- LIST_PREPEND(conditions, *list, c);
- return 0;
-}
-
-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) {
-
- _cleanup_free_ char *s = NULL;
- Condition **list = data, *c;
- ConditionType t = ltype;
- bool trigger, negate;
- Unit *u = userdata;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (isempty(rvalue)) {
- /* Empty assignment resets the list */
- *list = condition_free_list(*list);
- return 0;
- }
-
- trigger = rvalue[0] == '|';
- if (trigger)
- rvalue++;
-
- negate = rvalue[0] == '!';
- if (negate)
- rvalue++;
-
- 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);
- return 0;
- }
-
- c = condition_new(t, s, trigger, negate);
- if (!c)
- return log_oom();
-
- LIST_PREPEND(conditions, *list, c);
- return 0;
-}
-
-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) {
-
- Condition **list = data, *c;
- bool trigger, negate;
- int b;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (isempty(rvalue)) {
- /* Empty assignment resets the list */
- *list = condition_free_list(*list);
- return 0;
- }
-
- trigger = rvalue[0] == '|';
- if (trigger)
- rvalue++;
-
- negate = rvalue[0] == '!';
- if (negate)
- rvalue++;
-
- b = parse_boolean(rvalue);
- if (b < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -b, "Failed to parse boolean value in condition, ignoring: %s", rvalue);
- return 0;
- }
-
- if (!b)
- negate = !negate;
-
- c = condition_new(CONDITION_NULL, NULL, trigger, negate);
- if (!c)
- return log_oom();
-
- LIST_PREPEND(conditions, *list, c);
- 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_failure_action, failure_action, FailureAction, "Failed to parse failure action specifier");
-
-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) {
-
- Unit *u = userdata;
- const char *word, *state;
- size_t l;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- int r;
- _cleanup_free_ char *n;
-
- n = strndup(word, l);
- if (!n)
- return log_oom();
-
- if (!utf8_is_valid(n)) {
- log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
- continue;
- }
-
- r = unit_require_mounts_for(u, n);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to add required mount for, ignoring: %s", rvalue);
- continue;
- }
- }
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
-
- return 0;
-}
-
-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) {
-
- Unit *u = userdata;
- int r;
- char **a, **b;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(u);
-
- if (isempty(rvalue)) {
- /* Empty assignment resets the list */
- strv_free(u->documentation);
- u->documentation = NULL;
- return 0;
- }
-
- r = config_parse_unit_strv_printf(unit, filename, line, section, section_line, lvalue, ltype,
- rvalue, data, userdata);
- if (r < 0)
- return r;
-
- for (a = b = u->documentation; a && *a; a++) {
-
- if (documentation_url_is_valid(*a))
- *(b++) = *a;
- else {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid URL, ignoring: %s", *a);
- free(*a);
- }
- }
- if (b)
- *b = NULL;
-
- return r;
-}
-
-#ifdef HAVE_SECCOMP
-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) {
-
- static const char default_syscalls[] =
- "execve\0"
- "exit\0"
- "exit_group\0"
- "rt_sigreturn\0"
- "sigreturn\0";
-
- ExecContext *c = data;
- Unit *u = userdata;
- bool invert = false;
- const char *word, *state;
- size_t l;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(u);
-
- if (isempty(rvalue)) {
- /* Empty assignment resets the list */
- set_free(c->syscall_filter);
- c->syscall_filter = NULL;
- c->syscall_whitelist = false;
- return 0;
- }
-
- if (rvalue[0] == '~') {
- invert = true;
- rvalue++;
- }
-
- if (!c->syscall_filter) {
- c->syscall_filter = set_new(NULL);
- if (!c->syscall_filter)
- return log_oom();
-
- if (invert)
- /* Allow everything but the ones listed */
- c->syscall_whitelist = false;
- else {
- const char *i;
-
- /* Allow nothing but the ones listed */
- c->syscall_whitelist = true;
-
- /* Accept default syscalls if we are on a whitelist */
- NULSTR_FOREACH(i, default_syscalls) {
- int id;
-
- id = seccomp_syscall_resolve_name(i);
- if (id < 0)
- continue;
-
- r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
- if (r == -EEXIST)
- continue;
- if (r < 0)
- return log_oom();
- }
- }
- }
-
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *t = NULL;
- int id;
-
- t = strndup(word, l);
- if (!t)
- return log_oom();
-
- id = seccomp_syscall_resolve_name(t);
- if (id < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse system call, ignoring: %s", t);
- continue;
- }
-
- /* If we previously wanted to forbid a syscall and now
- * we want to allow it, then remove it from the list
- */
- if (!invert == c->syscall_whitelist) {
- r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
- if (r == -EEXIST)
- continue;
- if (r < 0)
- return log_oom();
- } else
- set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
- }
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
-
- /* Turn on NNP, but only if it wasn't configured explicitly
- * before, and only if we are in user mode. */
- if (!c->no_new_privileges_set && u->manager->running_as == SYSTEMD_USER)
- c->no_new_privileges = true;
-
- return 0;
-}
-
-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) {
-
- Set **archs = data;
- const char *word, *state;
- size_t l;
- int r;
-
- if (isempty(rvalue)) {
- set_free(*archs);
- *archs = NULL;
- return 0;
- }
-
- r = set_ensure_allocated(archs, NULL);
- if (r < 0)
- return log_oom();
-
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *t = NULL;
- uint32_t a;
-
- t = strndup(word, l);
- if (!t)
- return log_oom();
-
- r = seccomp_arch_from_string(t, &a);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse system call architecture, ignoring: %s", t);
- continue;
- }
-
- r = set_put(*archs, UINT32_TO_PTR(a + 1));
- if (r == -EEXIST)
- continue;
- if (r < 0)
- return log_oom();
- }
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
-
- return 0;
-}
-
-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) {
-
- ExecContext *c = data;
- int e;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- if (isempty(rvalue)) {
- /* Empty assignment resets to KILL */
- c->syscall_errno = 0;
- return 0;
- }
-
- e = errno_from_name(rvalue);
- if (e < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse error number, ignoring: %s", rvalue);
- return 0;
- }
-
- c->syscall_errno = e;
- return 0;
-}
-
-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) {
-
- ExecContext *c = data;
- bool invert = false;
- const char *word, *state;
- size_t l;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- if (isempty(rvalue)) {
- /* Empty assignment resets the list */
- set_free(c->address_families);
- c->address_families = NULL;
- c->address_families_whitelist = false;
- return 0;
- }
-
- if (rvalue[0] == '~') {
- invert = true;
- rvalue++;
- }
-
- if (!c->address_families) {
- c->address_families = set_new(NULL);
- if (!c->address_families)
- return log_oom();
-
- c->address_families_whitelist = !invert;
- }
-
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *t = NULL;
- int af;
-
- t = strndup(word, l);
- if (!t)
- return log_oom();
-
- af = af_from_name(t);
- if (af <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse address family, ignoring: %s", t);
- continue;
- }
-
- /* If we previously wanted to forbid an address family and now
- * we want to allow it, then remove it from the list
- */
- if (!invert == c->address_families_whitelist) {
- r = set_put(c->address_families, INT_TO_PTR(af));
- if (r == -EEXIST)
- continue;
- if (r < 0)
- return log_oom();
- } else
- set_remove(c->address_families, INT_TO_PTR(af));
- }
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
-
- return 0;
-}
-#endif
-
-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) {
-
- _cleanup_free_ char *k = NULL;
- Unit *u = userdata, *slice;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(u);
-
- 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);
- if (!k) {
- k = strdup(rvalue);
- if (!k)
- return log_oom();
- }
-
- r = manager_load_unit(u->manager, k, NULL, NULL, &slice);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to load slice unit %s. Ignoring.", k);
- return 0;
- }
-
- if (slice->type != UNIT_SLICE) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Slice unit %s is not a slice. Ignoring.", k);
- return 0;
- }
-
- unit_ref_set(&u->slice, slice);
- return 0;
-}
-
-DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
-
-int config_parse_cpu_shares(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- unsigned long *shares = data, lu;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- if (isempty(rvalue)) {
- *shares = (unsigned long) -1;
- return 0;
- }
-
- r = safe_atolu(rvalue, &lu);
- if (r < 0 || lu <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "CPU shares '%s' invalid. Ignoring.", rvalue);
- return 0;
- }
-
- *shares = lu;
- return 0;
-}
-
-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) {
-
- CGroupContext *c = data;
- double percent;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- if (isempty(rvalue)) {
- c->cpu_quota_per_sec_usec = USEC_INFINITY;
- return 0;
- }
-
- if (!endswith(rvalue, "%")) {
-
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
- return 0;
- }
-
- if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "CPU quota '%s' invalid. Ignoring.", rvalue);
- return 0;
- }
-
- c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
-
- return 0;
-}
-
-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) {
-
- CGroupContext *c = data;
- off_t bytes;
- int r;
-
- if (isempty(rvalue)) {
- c->memory_limit = (uint64_t) -1;
- return 0;
- }
-
- assert_cc(sizeof(uint64_t) == sizeof(off_t));
-
- r = parse_size(rvalue, 1024, &bytes);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Memory limit '%s' invalid. Ignoring.", rvalue);
- return 0;
- }
-
- c->memory_limit = (uint64_t) bytes;
- return 0;
-}
-
-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) {
-
- _cleanup_free_ char *path = NULL;
- CGroupContext *c = data;
- CGroupDeviceAllow *a;
- const char *m;
- size_t n;
-
- if (isempty(rvalue)) {
- while (c->device_allow)
- cgroup_context_free_device_allow(c, c->device_allow);
-
- return 0;
- }
-
- n = strcspn(rvalue, WHITESPACE);
- path = strndup(rvalue, n);
- if (!path)
- return log_oom();
-
- if (!startswith(path, "/dev/") &&
- !startswith(path, "block-") &&
- !startswith(path, "char-")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid device node path '%s'. Ignoring.", path);
- return 0;
- }
-
- m = rvalue + n + strspn(rvalue + n, WHITESPACE);
- if (isempty(m))
- m = "rwm";
-
- if (!in_charset(m, "rwm")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid device rights '%s'. Ignoring.", m);
- return 0;
- }
-
- a = new0(CGroupDeviceAllow, 1);
- if (!a)
- return log_oom();
-
- a->path = path;
- path = NULL;
- a->r = !!strchr(m, 'r');
- a->w = !!strchr(m, 'w');
- a->m = !!strchr(m, 'm');
-
- LIST_PREPEND(device_allow, c->device_allow, a);
- 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) {
-
- unsigned long *weight = data, lu;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- if (isempty(rvalue)) {
- *weight = (unsigned long) -1;
- return 0;
- }
-
- r = safe_atolu(rvalue, &lu);
- if (r < 0 || lu < 10 || lu > 1000) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Block IO weight '%s' invalid. Ignoring.", rvalue);
- return 0;
- }
-
- *weight = lu;
- return 0;
-}
-
-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) {
-
- _cleanup_free_ char *path = NULL;
- CGroupBlockIODeviceWeight *w;
- CGroupContext *c = data;
- unsigned long lu;
- const char *weight;
- size_t n;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- if (isempty(rvalue)) {
- while (c->blockio_device_weights)
- cgroup_context_free_blockio_device_weight(c, c->blockio_device_weights);
-
- return 0;
- }
-
- n = strcspn(rvalue, WHITESPACE);
- weight = rvalue + n;
- if (!*weight) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Expected block device and device weight. Ignoring.");
- return 0;
- }
-
- path = strndup(rvalue, n);
- if (!path)
- return log_oom();
-
- if (!path_startswith(path, "/dev")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid device node path '%s'. Ignoring.", path);
- return 0;
- }
-
- weight += strspn(weight, WHITESPACE);
- r = safe_atolu(weight, &lu);
- if (r < 0 || lu < 10 || lu > 1000) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Block IO weight '%s' invalid. Ignoring.", rvalue);
- return 0;
- }
-
- w = new0(CGroupBlockIODeviceWeight, 1);
- if (!w)
- return log_oom();
-
- w->path = path;
- path = NULL;
-
- w->weight = lu;
-
- LIST_PREPEND(device_weights, c->blockio_device_weights, w);
- return 0;
-}
-
-int config_parse_blockio_bandwidth(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- _cleanup_free_ char *path = NULL;
- CGroupBlockIODeviceBandwidth *b;
- CGroupContext *c = data;
- const char *bandwidth;
- off_t bytes;
- bool read;
- size_t n;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- read = streq("BlockIOReadBandwidth", lvalue);
-
- if (isempty(rvalue)) {
- CGroupBlockIODeviceBandwidth *next;
-
- LIST_FOREACH_SAFE (device_bandwidths, b, next, c->blockio_device_bandwidths)
- if (b->read == read)
- cgroup_context_free_blockio_device_bandwidth(c, b);
-
- return 0;
- }
-
- n = strcspn(rvalue, WHITESPACE);
- bandwidth = rvalue + n;
- bandwidth += strspn(bandwidth, WHITESPACE);
-
- if (!*bandwidth) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Expected space separated pair of device node and bandwidth. Ignoring.");
- return 0;
- }
-
- path = strndup(rvalue, n);
- if (!path)
- return log_oom();
-
- if (!path_startswith(path, "/dev")) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid device node path '%s'. Ignoring.", path);
- return 0;
- }
-
- r = parse_size(bandwidth, 1000, &bytes);
- if (r < 0 || bytes <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Block IO Bandwidth '%s' invalid. Ignoring.", rvalue);
- return 0;
- }
-
- b = new0(CGroupBlockIODeviceBandwidth, 1);
- if (!b)
- return log_oom();
-
- b->path = path;
- path = NULL;
- b->bandwidth = (uint64_t) bytes;
- b->read = read;
-
- LIST_PREPEND(device_bandwidths, c->blockio_device_bandwidths, b);
-
- 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,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- JobMode *m = data;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- r = parse_boolean(rvalue);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse boolean, ignoring: %s", rvalue);
- return 0;
- }
-
- *m = r ? JOB_ISOLATE : JOB_REPLACE;
- return 0;
-}
-
-int config_parse_personality(
- 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) {
-
- unsigned long *personality = data, p;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(personality);
-
- p = personality_from_string(rvalue);
- if (p == 0xffffffffUL) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Failed to parse personality, ignoring: %s", rvalue);
- return 0;
- }
-
- *personality = p;
- return 0;
-}
-
-int config_parse_runtime_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) {
-
- char***rt = data;
- const char *word, *state;
- size_t l;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (isempty(rvalue)) {
- /* Empty assignment resets the list */
- strv_free(*rt);
- *rt = NULL;
- return 0;
- }
-
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *n;
-
- n = strndup(word, l);
- if (!n)
- return log_oom();
-
- if (!filename_is_valid(n)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Runtime directory is not valid, ignoring assignment: %s", rvalue);
- continue;
- }
-
- r = strv_push(rt, n);
- if (r < 0)
- return log_oom();
-
- n = NULL;
- }
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
-
- return 0;
-}
-
-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) {
-
- size_t l;
- const char *word, *state;
- int r;
- ExitStatusSet *status_set = data;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- /* Empty assignment resets the list */
- if (isempty(rvalue)) {
- exit_status_set_free(status_set);
- return 0;
- }
-
- FOREACH_WORD(word, l, rvalue, state) {
- _cleanup_free_ char *temp;
- int val;
- Set **set;
-
- temp = strndup(word, l);
- if (!temp)
- return log_oom();
-
- r = safe_atoi(temp, &val);
- if (r < 0) {
- val = signal_from_string_try_harder(temp);
-
- if (val <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, -val,
- "Failed to parse value, ignoring: %s", word);
- continue;
- }
- set = &status_set->signal;
- } else {
- if (val < 0 || val > 255) {
- log_syntax(unit, LOG_ERR, filename, line, ERANGE,
- "Value %d is outside range 0-255, ignoring", val);
- continue;
- }
- set = &status_set->status;
- }
-
- r = set_ensure_allocated(set, NULL);
- if (r < 0)
- 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 (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
-
- return 0;
-}
-
-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) {
-
- char*** sv = data;
- const char *word, *state;
- size_t l;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (isempty(rvalue)) {
- /* Empty assignment resets the list */
- strv_free(*sv);
- *sv = NULL;
- return 0;
- }
-
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *n;
- int offset;
-
- n = strndup(word, l);
- if (!n)
- return log_oom();
-
- if (!utf8_is_valid(n)) {
- log_invalid_utf8(unit, LOG_ERR, filename, line, EINVAL, rvalue);
- continue;
- }
-
- offset = n[0] == '-';
- if (!path_is_absolute(n + offset)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Not an absolute path, ignoring: %s", rvalue);
- continue;
- }
-
- path_kill_slashes(n);
-
- r = strv_push(sv, n);
- if (r < 0)
- return log_oom();
-
- n = NULL;
- }
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
-
- 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;
- c->no_new_privileges_set = true;
-
- 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;
- int k;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- /* Our enum shall be a superset of booleans, hence first try
- * to parse as as boolean, and then as enum */
-
- k = parse_boolean(rvalue);
- if (k > 0)
- c->protect_home = PROTECT_HOME_YES;
- else if (k == 0)
- c->protect_home = PROTECT_HOME_NO;
- else {
- ProtectHome h;
-
- h = protect_home_from_string(rvalue);
- if (h < 0){
- log_syntax(unit, LOG_ERR, filename, line, -h,
- "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;
- int k;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- /* Our enum shall be a superset of booleans, hence first try
- * to parse as as boolean, and then as enum */
-
- k = parse_boolean(rvalue);
- if (k > 0)
- c->protect_system = PROTECT_SYSTEM_YES;
- else if (k == 0)
- c->protect_system = PROTECT_SYSTEM_NO;
- else {
- ProtectSystem s;
-
- s = protect_system_from_string(rvalue);
- if (s < 0){
- log_syntax(unit, LOG_ERR, filename, line, -s,
- "Failed to parse protect system value, ignoring: %s", rvalue);
- return 0;
- }
-
- c->protect_system = s;
- }
-
- return 0;
-}
-
-#define FOLLOW_MAX 8
-
-static int open_follow(char **filename, FILE **_f, Set *names, char **_final) {
- unsigned c = 0;
- int fd, r;
- FILE *f;
- char *id = NULL;
-
- assert(filename);
- assert(*filename);
- assert(_f);
- assert(names);
-
- /* This will update the filename pointer if the loaded file is
- * reached by a symlink. The old string will be freed. */
-
- for (;;) {
- char *target, *name;
-
- if (c++ >= FOLLOW_MAX)
- return -ELOOP;
-
- path_kill_slashes(*filename);
-
- /* Add the file name we are currently looking at to
- * the names of this unit, but only if it is a valid
- * unit name. */
- name = basename(*filename);
-
- if (unit_name_is_valid(name, TEMPLATE_VALID)) {
-
- id = set_get(names, name);
- if (!id) {
- id = strdup(name);
- if (!id)
- return -ENOMEM;
-
- r = set_consume(names, id);
- if (r < 0)
- return r;
- }
- }
-
- /* Try to open the file name, but don't if its a symlink */
- fd = open(*filename, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
- if (fd >= 0)
- break;
-
- if (errno != ELOOP)
- return -errno;
-
- /* Hmm, so this is a symlink. Let's read the name, and follow it manually */
- r = readlink_and_make_absolute(*filename, &target);
- if (r < 0)
- return r;
-
- free(*filename);
- *filename = target;
- }
-
- f = fdopen(fd, "re");
- if (!f) {
- safe_close(fd);
- return -errno;
- }
-
- *_f = f;
- *_final = id;
- return 0;
-}
-
-static int merge_by_names(Unit **u, Set *names, const char *id) {
- char *k;
- int r;
-
- assert(u);
- assert(*u);
- assert(names);
-
- /* Let's try to add in all symlink names we found */
- while ((k = set_steal_first(names))) {
-
- /* First try to merge in the other name into our
- * unit */
- r = unit_merge_by_name(*u, k);
- if (r < 0) {
- Unit *other;
-
- /* Hmm, we couldn't merge the other unit into
- * ours? Then let's try it the other way
- * round */
-
- other = manager_get_unit((*u)->manager, k);
- free(k);
-
- if (other) {
- r = unit_merge(other, *u);
- if (r >= 0) {
- *u = other;
- return merge_by_names(u, names, NULL);
- }
- }
-
- return r;
- }
-
- if (id == k)
- unit_choose_id(*u, id);
-
- free(k);
- }
-
- return 0;
-}
-
-static int load_from_path(Unit *u, const char *path) {
- int r;
- _cleanup_set_free_free_ Set *symlink_names = NULL;
- _cleanup_fclose_ FILE *f = NULL;
- _cleanup_free_ char *filename = NULL;
- char *id = NULL;
- Unit *merged;
- struct stat st;
-
- assert(u);
- assert(path);
-
- symlink_names = set_new(&string_hash_ops);
- if (!symlink_names)
- return -ENOMEM;
-
- if (path_is_absolute(path)) {
-
- filename = strdup(path);
- if (!filename)
- return -ENOMEM;
-
- r = open_follow(&filename, &f, symlink_names, &id);
- if (r < 0) {
- free(filename);
- filename = NULL;
-
- if (r != -ENOENT)
- return r;
- }
-
- } else {
- char **p;
-
- STRV_FOREACH(p, u->manager->lookup_paths.unit_path) {
-
- /* Instead of opening the path right away, we manually
- * follow all symlinks and add their name to our unit
- * name set while doing so */
- filename = path_make_absolute(path, *p);
- if (!filename)
- return -ENOMEM;
-
- if (u->manager->unit_path_cache &&
- !set_get(u->manager->unit_path_cache, filename))
- r = -ENOENT;
- else
- r = open_follow(&filename, &f, symlink_names, &id);
-
- if (r < 0) {
- free(filename);
- filename = NULL;
-
- if (r != -ENOENT)
- return r;
-
- /* Empty the symlink names for the next run */
- set_clear_free(symlink_names);
- continue;
- }
-
- break;
- }
- }
-
- if (!filename)
- /* Hmm, no suitable file found? */
- return 0;
-
- merged = u;
- r = merge_by_names(&merged, symlink_names, id);
- if (r < 0)
- return r;
-
- if (merged != u) {
- u->load_state = UNIT_MERGED;
- return 0;
- }
-
- if (fstat(fileno(f), &st) < 0)
- return -errno;
-
- if (null_or_empty(&st))
- u->load_state = UNIT_MASKED;
- else {
- u->load_state = UNIT_LOADED;
-
- /* Now, parse the file contents */
- r = config_parse(u->id, filename, f,
- UNIT_VTABLE(u)->sections,
- config_item_perf_lookup, load_fragment_gperf_lookup,
- false, true, false, u);
- if (r < 0)
- return r;
- }
-
- free(u->fragment_path);
- u->fragment_path = filename;
- filename = NULL;
-
- u->fragment_mtime = timespec_load(&st.st_mtim);
-
- if (u->source_path) {
- if (stat(u->source_path, &st) >= 0)
- u->source_mtime = timespec_load(&st.st_mtim);
- else
- u->source_mtime = 0;
- }
-
- return 0;
-}
-
-int unit_load_fragment(Unit *u) {
- int r;
- Iterator i;
- const char *t;
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
- assert(u->id);
-
- /* First, try to find the unit under its id. We always look
- * for unit files in the default directories, to make it easy
- * to override things by placing things in /etc/systemd/system */
- r = load_from_path(u, u->id);
- if (r < 0)
- return r;
-
- /* Try to find an alias we can load this with */
- if (u->load_state == UNIT_STUB) {
- SET_FOREACH(t, u->names, i) {
-
- if (t == u->id)
- continue;
-
- r = load_from_path(u, t);
- if (r < 0)
- return r;
-
- if (u->load_state != UNIT_STUB)
- break;
- }
- }
-
- /* And now, try looking for it under the suggested (originally linked) path */
- if (u->load_state == UNIT_STUB && u->fragment_path) {
-
- r = load_from_path(u, u->fragment_path);
- if (r < 0)
- return r;
-
- if (u->load_state == UNIT_STUB) {
- /* Hmm, this didn't work? Then let's get rid
- * of the fragment path stored for us, so that
- * we don't point to an invalid location. */
- free(u->fragment_path);
- u->fragment_path = NULL;
- }
- }
-
- /* Look for a template */
- if (u->load_state == UNIT_STUB && u->instance) {
- _cleanup_free_ char *k;
-
- k = unit_name_template(u->id);
- if (!k)
- return -ENOMEM;
-
- r = load_from_path(u, k);
- if (r < 0)
- return r;
-
- if (u->load_state == UNIT_STUB) {
- SET_FOREACH(t, u->names, i) {
- _cleanup_free_ char *z = NULL;
-
- if (t == u->id)
- continue;
-
- z = unit_name_template(t);
- if (!z)
- return -ENOMEM;
-
- r = load_from_path(u, z);
- if (r < 0)
- return r;
-
- if (u->load_state != UNIT_STUB)
- break;
- }
- }
- }
-
- return 0;
-}
-
-void unit_dump_config_items(FILE *f) {
- static const struct {
- const ConfigParserCallback callback;
- const char *rvalue;
- } table[] = {
- { config_parse_warn_compat, "NOTSUPPORTED" },
- { config_parse_int, "INTEGER" },
- { config_parse_unsigned, "UNSIGNED" },
- { config_parse_iec_size, "SIZE" },
- { config_parse_iec_off, "SIZE" },
- { config_parse_si_size, "SIZE" },
- { config_parse_bool, "BOOLEAN" },
- { config_parse_string, "STRING" },
- { config_parse_path, "PATH" },
- { config_parse_unit_path_printf, "PATH" },
- { config_parse_strv, "STRING [...]" },
- { config_parse_exec_nice, "NICE" },
- { config_parse_exec_oom_score_adjust, "OOMSCOREADJUST" },
- { config_parse_exec_io_class, "IOCLASS" },
- { config_parse_exec_io_priority, "IOPRIORITY" },
- { config_parse_exec_cpu_sched_policy, "CPUSCHEDPOLICY" },
- { config_parse_exec_cpu_sched_prio, "CPUSCHEDPRIO" },
- { config_parse_exec_cpu_affinity, "CPUAFFINITY" },
- { config_parse_mode, "MODE" },
- { config_parse_unit_env_file, "FILE" },
- { config_parse_output, "OUTPUT" },
- { config_parse_input, "INPUT" },
- { config_parse_log_facility, "FACILITY" },
- { config_parse_log_level, "LEVEL" },
- { config_parse_exec_capabilities, "CAPABILITIES" },
- { config_parse_exec_secure_bits, "SECUREBITS" },
- { config_parse_bounding_set, "BOUNDINGSET" },
- { config_parse_limit, "LIMIT" },
- { config_parse_unit_deps, "UNIT [...]" },
- { config_parse_exec, "PATH [ARGUMENT [...]]" },
- { config_parse_service_type, "SERVICETYPE" },
- { config_parse_service_restart, "SERVICERESTART" },
- { config_parse_kill_mode, "KILLMODE" },
- { config_parse_kill_signal, "SIGNAL" },
- { config_parse_socket_listen, "SOCKET [...]" },
- { config_parse_socket_bind, "SOCKETBIND" },
- { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
- { config_parse_sec, "SECONDS" },
- { config_parse_nsec, "NANOSECONDS" },
- { config_parse_namespace_path_strv, "PATH [...]" },
- { config_parse_unit_requires_mounts_for, "PATH [...]" },
- { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
- { config_parse_unit_string_printf, "STRING" },
- { config_parse_trigger_unit, "UNIT" },
- { config_parse_timer, "TIMER" },
- { config_parse_path_spec, "PATH" },
- { config_parse_notify_access, "ACCESS" },
- { config_parse_ip_tos, "TOS" },
- { config_parse_unit_condition_path, "CONDITION" },
- { config_parse_unit_condition_string, "CONDITION" },
- { config_parse_unit_condition_null, "CONDITION" },
- { config_parse_unit_slice, "SLICE" },
- { config_parse_documentation, "URL" },
- { config_parse_service_timeout, "SECONDS" },
- { config_parse_failure_action, "ACTION" },
- { config_parse_set_status, "STATUS" },
- { config_parse_service_sockets, "SOCKETS" },
- { config_parse_environ, "ENVIRON" },
-#ifdef HAVE_SECCOMP
- { config_parse_syscall_filter, "SYSCALLS" },
- { config_parse_syscall_archs, "ARCHS" },
- { config_parse_syscall_errno, "ERRNO" },
- { config_parse_address_families, "FAMILIES" },
-#endif
- { config_parse_cpu_shares, "SHARES" },
- { config_parse_memory_limit, "LIMIT" },
- { config_parse_device_allow, "DEVICE" },
- { config_parse_device_policy, "POLICY" },
- { config_parse_blockio_bandwidth, "BANDWIDTH" },
- { config_parse_blockio_weight, "WEIGHT" },
- { config_parse_blockio_device_weight, "DEVICEWEIGHT" },
- { config_parse_long, "LONG" },
- { config_parse_socket_service, "SERVICE" },
-#ifdef HAVE_SELINUX
- { config_parse_exec_selinux_context, "LABEL" },
-#endif
- { config_parse_job_mode, "MODE" },
- { config_parse_job_mode_isolate, "BOOLEAN" },
- { config_parse_personality, "PERSONALITY" },
- };
-
- const char *prev = NULL;
- const char *i;
-
- assert(f);
-
- NULSTR_FOREACH(i, load_fragment_gperf_nulstr) {
- const char *rvalue = "OTHER", *lvalue;
- unsigned j;
- size_t prefix_len;
- const char *dot;
- const ConfigPerfItem *p;
-
- assert_se(p = load_fragment_gperf_lookup(i, strlen(i)));
-
- dot = strchr(i, '.');
- lvalue = dot ? dot + 1 : i;
- prefix_len = dot-i;
-
- if (dot)
- if (!prev || !strneq(prev, i, prefix_len+1)) {
- if (prev)
- fputc('\n', 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
deleted file mode 100644
index ce10d03c3..000000000
--- a/src/core/load-fragment.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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"
-
-/* Read service data from .desktop file style configuration fragments */
-
-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_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_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_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_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_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_capabilities(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_bounding_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_busname_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_bus_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_bus_policy_world(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_endpoint_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_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_failure_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_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_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_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_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_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_personality(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_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_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_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);
-
-/* gperf prototypes */
-const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned 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
deleted file mode 100644
index 108072ca9..000000000
--- a/src/core/locale-setup.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 <stdlib.h>
-#include <errno.h>
-
-#include "locale-setup.h"
-#include "util.h"
-#include "virt.h"
-#include "fileio.h"
-#include "strv.h"
-#include "env-util.h"
-#include "locale-util.h"
-
-int locale_setup(char ***environment) {
- char **add;
- char *variables[_VARIABLE_LC_MAX] = {};
- int r = 0, i;
-
- if (detect_container(NULL) <= 0) {
- r = parse_env_file("/proc/cmdline", WHITESPACE,
- "locale.LANG", &variables[VARIABLE_LANG],
- "locale.LANGUAGE", &variables[VARIABLE_LANGUAGE],
- "locale.LC_CTYPE", &variables[VARIABLE_LC_CTYPE],
- "locale.LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC],
- "locale.LC_TIME", &variables[VARIABLE_LC_TIME],
- "locale.LC_COLLATE", &variables[VARIABLE_LC_COLLATE],
- "locale.LC_MONETARY", &variables[VARIABLE_LC_MONETARY],
- "locale.LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES],
- "locale.LC_PAPER", &variables[VARIABLE_LC_PAPER],
- "locale.LC_NAME", &variables[VARIABLE_LC_NAME],
- "locale.LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS],
- "locale.LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE],
- "locale.LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT],
- "locale.LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION],
- NULL);
-
- if (r < 0 && r != -ENOENT)
- log_warning_errno(r, "Failed to read /proc/cmdline: %m");
- }
-
- /* 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,
- "LANG", &variables[VARIABLE_LANG],
- "LANGUAGE", &variables[VARIABLE_LANGUAGE],
- "LC_CTYPE", &variables[VARIABLE_LC_CTYPE],
- "LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC],
- "LC_TIME", &variables[VARIABLE_LC_TIME],
- "LC_COLLATE", &variables[VARIABLE_LC_COLLATE],
- "LC_MONETARY", &variables[VARIABLE_LC_MONETARY],
- "LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES],
- "LC_PAPER", &variables[VARIABLE_LC_PAPER],
- "LC_NAME", &variables[VARIABLE_LC_NAME],
- "LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS],
- "LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE],
- "LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT],
- "LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION],
- NULL);
-
- if (r < 0 && r != -ENOENT)
- log_warning_errno(r, "Failed to read /etc/locale.conf: %m");
- }
-
- add = NULL;
- for (i = 0; i < _VARIABLE_LC_MAX; i++) {
- char *s;
-
- if (!variables[i])
- continue;
-
- s = strjoin(locale_variable_to_string(i), "=", variables[i], NULL);
- if (!s) {
- r = -ENOMEM;
- goto finish;
- }
-
- if (strv_consume(&add, s) < 0) {
- r = -ENOMEM;
- goto finish;
- }
- }
-
- if (!strv_isempty(add)) {
- char **e;
-
- e = strv_env_merge(2, *environment, add);
- if (!e) {
- r = -ENOMEM;
- goto finish;
- }
-
- strv_free(*environment);
- *environment = e;
- }
-
- r = 0;
-
-finish:
- strv_free(add);
-
- for (i = 0; i < _VARIABLE_LC_MAX; i++)
- free(variables[i]);
-
- return r;
-}
diff --git a/src/core/locale-setup.h b/src/core/locale-setup.h
deleted file mode 100644
index 62c654c37..000000000
--- a/src/core/locale-setup.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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
deleted file mode 100644
index 63b15c120..000000000
--- a/src/core/loopback-setup.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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>
-
-#include "sd-rtnl.h"
-#include "rtnl-util.h"
-#include "missing.h"
-#include "loopback-setup.h"
-
-static int start_loopback(sd_rtnl *rtnl) {
- _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
- int r;
-
- r = sd_rtnl_message_new_link(rtnl, &req, RTM_SETLINK, LOOPBACK_IFINDEX);
- if (r < 0)
- return r;
-
- r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
- if (r < 0)
- return r;
-
- r = sd_rtnl_call(rtnl, req, 0, NULL);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-static bool check_loopback(sd_rtnl *rtnl) {
- _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
- unsigned flags;
- int r;
-
- r = sd_rtnl_message_new_link(rtnl, &req, RTM_GETLINK, LOOPBACK_IFINDEX);
- if (r < 0)
- return false;
-
- r = sd_rtnl_call(rtnl, req, 0, &reply);
- if (r < 0)
- return false;
-
- r = sd_rtnl_message_link_get_flags(reply, &flags);
- if (r < 0)
- return false;
-
- return flags & IFF_UP;
-}
-
-int loopback_setup(void) {
- _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
- int r;
-
- r = sd_rtnl_open(&rtnl, 0);
- if (r < 0)
- return r;
-
- r = start_loopback(rtnl);
- if (r < 0) {
-
- /* If we lack the permissions to configure the
- * loopback device, but we find it to be already
- * configured, let's exit cleanly, in order to
- * supported unprivileged containers. */
- if (r == -EPERM && check_loopback(rtnl))
- return 0;
-
- return log_warning_errno(r, "Failed to configure loopback device: %m");
- }
-
- return 0;
-}
diff --git a/src/core/loopback-setup.h b/src/core/loopback-setup.h
deleted file mode 100644
index dd83cf13a..000000000
--- a/src/core/loopback-setup.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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
deleted file mode 100644
index 7505dcbca..000000000
--- a/src/core/machine-id-setup.c
+++ /dev/null
@@ -1,361 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sys/mount.h>
-
-#include "systemd/sd-id128.h"
-
-#include "machine-id-setup.h"
-#include "macro.h"
-#include "util.h"
-#include "mkdir.h"
-#include "log.h"
-#include "virt.h"
-#include "fileio.h"
-#include "path-util.h"
-
-static int shorten_uuid(char destination[34], const char source[36]) {
- unsigned i, j;
-
- assert(destination);
- assert(source);
-
- /* Converts a UUID into a machine ID, by lowercasing it and
- * removing dashes. Validates everything. */
-
- for (i = 0, j = 0; i < 36 && j < 32; i++) {
- int t;
-
- t = unhexchar(source[i]);
- if (t < 0)
- continue;
-
- destination[j++] = hexchar(t);
- }
-
- if (i != 36 || j != 32)
- return -EINVAL;
-
- destination[32] = '\n';
- destination[33] = 0;
- return 0;
-}
-
-static int read_machine_id(int fd, char id[34]) {
- char id_to_validate[34];
- int r;
-
- assert(fd >= 0);
- assert(id);
-
- /* Reads a machine ID from a file, validates it, and returns
- * it. The returned ID ends in a newline. */
-
- r = loop_read_exact(fd, id_to_validate, 33, false);
- if (r < 0)
- return r;
-
- if (id_to_validate[32] != '\n')
- return -EINVAL;
-
- id_to_validate[32] = 0;
-
- if (!id128_is_valid(id_to_validate))
- return -EINVAL;
-
- memcpy(id, id_to_validate, 32);
- id[32] = '\n';
- id[33] = 0;
- return 0;
-}
-
-static int write_machine_id(int fd, char id[34]) {
- assert(fd >= 0);
- assert(id);
-
- if (lseek(fd, 0, SEEK_SET) < 0)
- return -errno;
-
- return loop_write(fd, id, 33, false);
-}
-
-static int generate_machine_id(char id[34], const char *root) {
- int fd, r;
- unsigned char *p;
- sd_id128_t buf;
- char *q;
- const char *vm_id, *dbus_machine_id;
-
- assert(id);
-
- if (isempty(root))
- dbus_machine_id = "/var/lib/dbus/machine-id";
- else
- dbus_machine_id = strjoina(root, "/var/lib/dbus/machine-id");
-
- /* First, try reading the D-Bus machine id, unless it is a symlink */
- fd = open(dbus_machine_id, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
- if (fd >= 0) {
- r = read_machine_id(fd, id);
- safe_close(fd);
-
- if (r >= 0) {
- log_info("Initializing machine ID from D-Bus machine ID.");
- return 0;
- }
- }
-
- if (isempty(root)) {
- /* If that didn't work, see if we are running in a container,
- * and a machine ID was passed in via $container_uuid the way
- * libvirt/LXC does it */
- r = detect_container(NULL);
- if (r > 0) {
- _cleanup_free_ char *e = NULL;
-
- r = getenv_for_pid(1, "container_uuid", &e);
- if (r > 0) {
- r = shorten_uuid(id, e);
- if (r >= 0) {
- log_info("Initializing machine ID from container UUID.");
- return 0;
- }
- }
-
- } else {
- /* If we are not running in a container, see if we are
- * running in qemu/kvm and a machine ID was passed in
- * via -uuid on the qemu/kvm command line */
-
- r = detect_vm(&vm_id);
- if (r > 0 && streq(vm_id, "kvm")) {
- char uuid[36];
-
- fd = open("/sys/class/dmi/id/product_uuid", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
- if (fd >= 0) {
- r = loop_read_exact(fd, uuid, 36, false);
- safe_close(fd);
-
- if (r >= 0) {
- r = shorten_uuid(id, uuid);
- if (r >= 0) {
- log_info("Initializing machine ID from KVM UUID.");
- return 0;
- }
- }
- }
- }
- }
- }
-
- /* If that didn't work, generate a random machine id */
- r = sd_id128_randomize(&buf);
- if (r < 0)
- return log_error_errno(r, "Failed to open /dev/urandom: %m");
-
- for (p = buf.bytes, q = id; p < buf.bytes + sizeof(buf); p++, q += 2) {
- q[0] = hexchar(*p >> 4);
- q[1] = hexchar(*p & 15);
- }
-
- id[32] = '\n';
- id[33] = 0;
-
- log_info("Initializing machine ID from random generator.");
-
- return 0;
-}
-
-int machine_id_setup(const char *root) {
- const char *etc_machine_id, *run_machine_id;
- _cleanup_close_ int fd = -1;
- bool writable = true;
- char id[34]; /* 32 + \n + \0 */
- int r;
-
- if (isempty(root)) {
- etc_machine_id = "/etc/machine-id";
- run_machine_id = "/run/machine-id";
- } else {
- char *x;
-
- x = strjoina(root, "/etc/machine-id");
- etc_machine_id = path_kill_slashes(x);
-
- x = strjoina(root, "/run/machine-id");
- run_machine_id = path_kill_slashes(x);
- }
-
- RUN_WITH_UMASK(0000) {
- /* We create this 0444, to indicate that this isn't really
- * something you should ever modify. Of course, since the file
- * will be owned by root it doesn't matter much, but maybe
- * people look. */
-
- mkdir_parents(etc_machine_id, 0755);
- fd = open(etc_machine_id, O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444);
- if (fd < 0) {
- int old_errno = errno;
-
- fd = open(etc_machine_id, O_RDONLY|O_CLOEXEC|O_NOCTTY);
- if (fd < 0) {
- if (old_errno == EROFS && errno == ENOENT)
- log_error_errno(errno,
- "System cannot boot: Missing /etc/machine-id and /etc is mounted read-only.\n"
- "Booting up is supported only when:\n"
- "1) /etc/machine-id exists and is populated.\n"
- "2) /etc/machine-id exists and is empty.\n"
- "3) /etc/machine-id is missing and /etc is writable.\n");
- else
- log_error_errno(errno, "Cannot open %s: %m", etc_machine_id);
-
- return -errno;
- }
-
- writable = false;
- }
- }
-
- if (read_machine_id(fd, id) >= 0)
- return 0;
-
- /* Hmm, so, the id currently stored is not useful, then let's
- * generate one */
-
- r = generate_machine_id(id, root);
- if (r < 0)
- return r;
-
- if (writable)
- if (write_machine_id(fd, id) >= 0)
- return 0;
-
- fd = safe_close(fd);
-
- /* Hmm, we couldn't write it? So let's write it to
- * /run/machine-id as a replacement */
-
- RUN_WITH_UMASK(0022) {
- r = write_string_file(run_machine_id, id);
- }
- if (r < 0) {
- (void) unlink(run_machine_id);
- return log_error_errno(r, "Cannot write %s: %m", run_machine_id);
- }
-
- /* And now, let's mount it over */
- if (mount(run_machine_id, etc_machine_id, NULL, MS_BIND, NULL) < 0) {
- (void) unlink_noerrno(run_machine_id);
- return log_error_errno(errno, "Failed to mount %s: %m", etc_machine_id);
- }
-
- log_info("Installed transient %s file.", etc_machine_id);
-
- /* Mark the mount read-only */
- if (mount(NULL, etc_machine_id, NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, NULL) < 0)
- log_warning_errno(errno, "Failed to make transient %s read-only: %m", etc_machine_id);
-
- return 0;
-}
-
-int machine_id_commit(const char *root) {
- _cleanup_close_ int fd = -1, initial_mntns_fd = -1;
- const char *etc_machine_id;
- char id[34]; /* 32 + \n + \0 */
- int r;
-
- if (isempty(root))
- etc_machine_id = "/etc/machine-id";
- else {
- char *x;
-
- x = strjoina(root, "/etc/machine-id");
- etc_machine_id = path_kill_slashes(x);
- }
-
- r = path_is_mount_point(etc_machine_id, false);
- if (r < 0)
- return log_error_errno(r, "Failed to determine whether %s is a mount point: %m", etc_machine_id);
- if (r == 0) {
- log_debug("%s is is not a mount point. Nothing to do.", etc_machine_id);
- return 0;
- }
-
- /* Read existing machine-id */
- fd = open(etc_machine_id, O_RDONLY|O_CLOEXEC|O_NOCTTY);
- if (fd < 0)
- return log_error_errno(errno, "Cannot open %s: %m", etc_machine_id);
-
- r = read_machine_id(fd, id);
- if (r < 0)
- return log_error_errno(r, "We didn't find a valid machine ID in %s.", etc_machine_id);
-
- r = is_fd_on_temporary_fs(fd);
- if (r < 0)
- return log_error_errno(r, "Failed to determine whether %s is on a temporary file system: %m", etc_machine_id);
- if (r == 0) {
- log_error("%s is not on a temporary file system.", etc_machine_id);
- return -EROFS;
- }
-
- fd = safe_close(fd);
-
- /* Store current mount namespace */
- r = namespace_open(0, NULL, &initial_mntns_fd, NULL, NULL);
- if (r < 0)
- return log_error_errno(r, "Can't fetch current mount namespace: %m");
-
- /* Switch to a new mount namespace, isolate ourself and unmount etc_machine_id in our new namespace */
- if (unshare(CLONE_NEWNS) < 0)
- return log_error_errno(errno, "Failed to enter new namespace: %m");
-
- if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0)
- return log_error_errno(errno, "Couldn't make-rslave / mountpoint in our private namespace: %m");
-
- if (umount(etc_machine_id) < 0)
- return log_error_errno(errno, "Failed to unmount transient %s file in our private namespace: %m", etc_machine_id);
-
- /* Update a persistent version of etc_machine_id */
- fd = open(etc_machine_id, O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444);
- if (fd < 0)
- return log_error_errno(errno, "Cannot open for writing %s. This is mandatory to get a persistent machine-id: %m", etc_machine_id);
-
- r = write_machine_id(fd, id);
- if (r < 0)
- return log_error_errno(r, "Cannot write %s: %m", etc_machine_id);
-
- fd = safe_close(fd);
-
- /* Return to initial namespace and proceed a lazy tmpfs unmount */
- r = namespace_enter(-1, initial_mntns_fd, -1, -1);
- if (r < 0)
- return log_warning_errno(r, "Failed to switch back to initial mount namespace: %m.\nWe'll keep transient %s file until next reboot.", etc_machine_id);
-
- if (umount2(etc_machine_id, MNT_DETACH) < 0)
- return log_warning_errno(errno, "Failed to unmount transient %s file: %m.\nWe keep that mount until next reboot.", etc_machine_id);
-
- return 0;
-}
diff --git a/src/core/machine-id-setup.h b/src/core/machine-id-setup.h
deleted file mode 100644
index f7707c3bf..000000000
--- a/src/core/machine-id-setup.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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);
diff --git a/src/core/macros.systemd.in b/src/core/macros.systemd.in
deleted file mode 100644
index bea6ef1da..000000000
--- a/src/core/macros.systemd.in
+++ /dev/null
@@ -1,109 +0,0 @@
-# -*- Mode: makefile; indent-tabs-mode: t -*- */
-#
-# 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
-
-%_unitdir @systemunitdir@
-%_userunitdir @userunitdir@
-%_presetdir @systempresetdir@
-%_udevhwdbdir @udevhwdbdir@
-%_udevrulesdir @udevrulesdir@
-%_journalcatalogdir @catalogdir@
-%_tmpfilesdir @tmpfilesdir@
-%_sysusersdir @sysusersdir@
-%_sysctldir @sysctldir@
-%_binfmtdir @binfmtdir@
-
-%systemd_requires \
-Requires(post): systemd \
-Requires(preun): systemd \
-Requires(postun): systemd \
-%{nil}
-
-%systemd_post() \
-if [ $1 -eq 1 ] ; then \
- # Initial installation \
- systemctl preset %{?*} >/dev/null 2>&1 || : \
-fi \
-%{nil}
-
-%systemd_user_post() %systemd_post --user --global %{?*}
-
-%systemd_preun() \
-if [ $1 -eq 0 ] ; then \
- # Package removal, not upgrade \
- systemctl --no-reload disable %{?*} > /dev/null 2>&1 || : \
- systemctl stop %{?*} > /dev/null 2>&1 || : \
-fi \
-%{nil}
-
-%systemd_user_preun() \
-if [ $1 -eq 0 ] ; then \
- # Package removal, not upgrade \
- systemctl --no-reload --user --global disable %{?*} > /dev/null 2>&1 || : \
-fi \
-%{nil}
-
-%systemd_postun() \
-systemctl daemon-reload >/dev/null 2>&1 || : \
-%{nil}
-
-%systemd_user_postun() %{nil}
-
-%systemd_postun_with_restart() \
-systemctl daemon-reload >/dev/null 2>&1 || : \
-if [ $1 -ge 1 ] ; then \
- # Package upgrade, not uninstall \
- systemctl try-restart %{?*} >/dev/null 2>&1 || : \
-fi \
-%{nil}
-
-%systemd_user_postun_with_restart() %{nil}
-
-%udev_hwdb_update() \
-udevadm hwdb --update >/dev/null 2>&1 || : \
-%{nil}
-
-%udev_rules_update() \
-udevadm control --reload >/dev/null 2>&1 || : \
-%{nil}
-
-%journal_catalog_update() \
-journalctl --update-catalog >/dev/null 2>&1 || : \
-%{nil}
-
-%tmpfiles_create() \
-systemd-tmpfiles --create %{?*} >/dev/null 2>&1 || : \
-%{nil}
-
-%sysusers_create() \
-systemd-sysusers %{?*} >/dev/null 2>&1 || : \
-%{nil}
-
-%sysusers_create_inline() \
-echo %{?*} | systemd-sysusers - >/dev/null 2>&1 || : \
-%{nil}
-
-%sysctl_apply() \
-@rootlibexecdir@/systemd-sysctl %{?*} >/dev/null 2>&1 || : \
-%{nil}
-
-%binfmt_apply() \
-@rootlibexecdir@/systemd-binfmt %{?*} >/dev/null 2>&1 || : \
-%{nil}
diff --git a/src/core/main.c b/src/core/main.c
deleted file mode 100644
index 4fe0b7380..000000000
--- a/src/core/main.c
+++ /dev/null
@@ -1,2036 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <getopt.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <sys/prctl.h>
-#include <sys/mount.h>
-
-#ifdef HAVE_VALGRIND_VALGRIND_H
-#include <valgrind/valgrind.h>
-#endif
-#ifdef HAVE_SECCOMP
-#include <seccomp.h>
-#endif
-
-#include "sd-daemon.h"
-#include "sd-bus.h"
-#include "log.h"
-#include "fdset.h"
-#include "special.h"
-#include "conf-parser.h"
-#include "missing.h"
-#include "pager.h"
-#include "build.h"
-#include "strv.h"
-#include "def.h"
-#include "virt.h"
-#include "architecture.h"
-#include "watchdog.h"
-#include "switch-root.h"
-#include "capability.h"
-#include "killall.h"
-#include "env-util.h"
-#include "clock-util.h"
-#include "fileio.h"
-#include "bus-error.h"
-#include "bus-util.h"
-#include "selinux-util.h"
-#include "manager.h"
-#include "dbus-manager.h"
-#include "load-fragment.h"
-
-#include "mount-setup.h"
-#include "loopback-setup.h"
-#include "hostname-setup.h"
-#include "machine-id-setup.h"
-#include "selinux-setup.h"
-#include "ima-setup.h"
-#include "smack-setup.h"
-#include "kmod-setup.h"
-
-static enum {
- ACTION_RUN,
- ACTION_HELP,
- ACTION_VERSION,
- ACTION_TEST,
- ACTION_DUMP_CONFIGURATION_ITEMS,
- ACTION_DONE
-} arg_action = ACTION_RUN;
-static char *arg_default_unit = NULL;
-static SystemdRunningAs arg_running_as = _SYSTEMD_RUNNING_AS_INVALID;
-static bool arg_dump_core = true;
-static bool arg_crash_shell = false;
-static int arg_crash_chvt = -1;
-static bool arg_confirm_spawn = false;
-static ShowStatus arg_show_status = _SHOW_STATUS_UNSET;
-static bool arg_switched_root = false;
-static int arg_no_pager = -1;
-static char ***arg_join_controllers = NULL;
-static ExecOutput arg_default_std_output = EXEC_OUTPUT_JOURNAL;
-static ExecOutput arg_default_std_error = EXEC_OUTPUT_INHERIT;
-static usec_t arg_default_restart_usec = DEFAULT_RESTART_USEC;
-static usec_t arg_default_timeout_start_usec = DEFAULT_TIMEOUT_USEC;
-static usec_t arg_default_timeout_stop_usec = DEFAULT_TIMEOUT_USEC;
-static usec_t arg_default_start_limit_interval = DEFAULT_START_LIMIT_INTERVAL;
-static unsigned arg_default_start_limit_burst = DEFAULT_START_LIMIT_BURST;
-static usec_t arg_runtime_watchdog = 0;
-static usec_t arg_shutdown_watchdog = 10 * USEC_PER_MINUTE;
-static char **arg_default_environment = NULL;
-static struct rlimit *arg_default_rlimit[_RLIMIT_MAX] = {};
-static uint64_t arg_capability_bounding_set_drop = 0;
-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;
-static FILE* arg_serialization = NULL;
-static bool arg_default_cpu_accounting = false;
-static bool arg_default_blockio_accounting = false;
-static bool arg_default_memory_accounting = false;
-
-static void nop_handler(int sig) {}
-
-static void pager_open_if_enabled(void) {
-
- if (arg_no_pager <= 0)
- return;
-
- pager_open(false);
-}
-
-noreturn static void crash(int sig) {
-
- if (getpid() != 1)
- /* Pass this on immediately, if this is not PID 1 */
- raise(sig);
- else if (!arg_dump_core)
- log_emergency("Caught <%s>, not dumping core.", signal_to_string(sig));
- else {
- struct sigaction sa = {
- .sa_handler = nop_handler,
- .sa_flags = SA_NOCLDSTOP|SA_RESTART,
- };
- pid_t pid;
-
- /* We want to wait for the core process, hence let's enable SIGCHLD */
- sigaction(SIGCHLD, &sa, NULL);
-
- pid = raw_clone(SIGCHLD, NULL);
- if (pid < 0)
- log_emergency_errno(errno, "Caught <%s>, cannot fork for core dump: %m", signal_to_string(sig));
-
- else if (pid == 0) {
- struct rlimit rl = {};
-
- /* Enable default signal handler for core dump */
- zero(sa);
- sa.sa_handler = SIG_DFL;
- sigaction(sig, &sa, NULL);
-
- /* Don't limit the core dump size */
- rl.rlim_cur = RLIM_INFINITY;
- rl.rlim_max = RLIM_INFINITY;
- setrlimit(RLIMIT_CORE, &rl);
-
- /* Just to be sure... */
- (void) chdir("/");
-
- /* Raise the signal again */
- pid = raw_getpid();
- kill(pid, sig); /* raise() would kill the parent */
-
- assert_not_reached("We shouldn't be here...");
- _exit(1);
- } else {
- siginfo_t status;
- int r;
-
- /* Order things nicely. */
- r = wait_for_terminate(pid, &status);
- if (r < 0)
- log_emergency_errno(r, "Caught <%s>, waitpid() failed: %m", signal_to_string(sig));
- else if (status.si_code != CLD_DUMPED)
- log_emergency("Caught <%s>, core dump failed (child "PID_FMT", code=%s, status=%i/%s).",
- signal_to_string(sig),
- pid, sigchld_code_to_string(status.si_code),
- status.si_status,
- strna(status.si_code == CLD_EXITED
- ? exit_status_to_string(status.si_status, EXIT_STATUS_FULL)
- : signal_to_string(status.si_status)));
- else
- log_emergency("Caught <%s>, dumped core as pid "PID_FMT".", signal_to_string(sig), pid);
- }
- }
-
- if (arg_crash_chvt)
- chvt(arg_crash_chvt);
-
- if (arg_crash_shell) {
- struct sigaction sa = {
- .sa_handler = SIG_IGN,
- .sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART,
- };
- pid_t pid;
-
- log_info("Executing crash shell in 10s...");
- sleep(10);
-
- /* Let the kernel reap children for us */
- assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
-
- pid = raw_clone(SIGCHLD, NULL);
- if (pid < 0)
- log_emergency_errno(errno, "Failed to fork off crash shell: %m");
- else if (pid == 0) {
- make_console_stdio();
- execle("/bin/sh", "/bin/sh", NULL, environ);
-
- log_emergency_errno(errno, "execle() failed: %m");
- _exit(1);
- } else
- log_info("Successfully spawned crash shell as PID "PID_FMT".", pid);
- }
-
- log_emergency("Freezing execution.");
- freeze();
-}
-
-static void install_crash_handler(void) {
- static const struct sigaction sa = {
- .sa_handler = crash,
- .sa_flags = SA_NODEFER, /* So that we can raise the signal again from the signal handler */
- };
- int r;
-
- /* We ignore the return value here, since, we don't mind if we
- * cannot set up a crash handler */
- r = sigaction_many(&sa, SIGNALS_CRASH_HANDLER, -1);
- if (r < 0)
- log_debug_errno(r, "I had trouble setting up the crash handler, ignoring: %m");
-}
-
-static int console_setup(void) {
- _cleanup_close_ int tty_fd = -1;
- int r;
-
- tty_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
- if (tty_fd < 0)
- return log_error_errno(tty_fd, "Failed to open /dev/console: %m");
-
- /* We don't want to force text mode. plymouth may be showing
- * pictures already from initrd. */
- r = reset_terminal_fd(tty_fd, false);
- if (r < 0)
- return log_error_errno(r, "Failed to reset /dev/console: %m");
-
- return 0;
-}
-
-static int set_default_unit(const char *u) {
- char *c;
-
- assert(u);
-
- c = strdup(u);
- if (!c)
- return -ENOMEM;
-
- free(arg_default_unit);
- arg_default_unit = c;
-
- return 0;
-}
-
-static int parse_proc_cmdline_item(const char *key, const char *value) {
-
- static const char * const rlmap[] = {
- "emergency", SPECIAL_EMERGENCY_TARGET,
- "-b", SPECIAL_EMERGENCY_TARGET,
- "rescue", SPECIAL_RESCUE_TARGET,
- "single", SPECIAL_RESCUE_TARGET,
- "-s", SPECIAL_RESCUE_TARGET,
- "s", SPECIAL_RESCUE_TARGET,
- "S", SPECIAL_RESCUE_TARGET,
- "1", SPECIAL_RESCUE_TARGET,
- "2", SPECIAL_MULTI_USER_TARGET,
- "3", SPECIAL_MULTI_USER_TARGET,
- "4", SPECIAL_MULTI_USER_TARGET,
- "5", SPECIAL_GRAPHICAL_TARGET,
- };
- int r;
-
- assert(key);
-
- if (streq(key, "systemd.unit") && value) {
-
- if (!in_initrd())
- return set_default_unit(value);
-
- } else if (streq(key, "rd.systemd.unit") && value) {
-
- if (in_initrd())
- return set_default_unit(value);
-
- } else if (streq(key, "systemd.dump_core") && value) {
-
- r = parse_boolean(value);
- if (r < 0)
- log_warning("Failed to parse dump core switch %s. Ignoring.", value);
- else
- arg_dump_core = r;
-
- } else if (streq(key, "systemd.crash_shell") && value) {
-
- r = parse_boolean(value);
- if (r < 0)
- log_warning("Failed to parse crash shell switch %s. Ignoring.", value);
- else
- arg_crash_shell = r;
-
- } else if (streq(key, "systemd.crash_chvt") && value) {
-
- if (safe_atoi(value, &r) < 0)
- log_warning("Failed to parse crash chvt switch %s. Ignoring.", value);
- else
- arg_crash_chvt = r;
-
- } else if (streq(key, "systemd.confirm_spawn") && value) {
-
- r = parse_boolean(value);
- if (r < 0)
- log_warning("Failed to parse confirm spawn switch %s. Ignoring.", value);
- else
- arg_confirm_spawn = r;
-
- } else if (streq(key, "systemd.show_status") && value) {
-
- r = parse_show_status(value, &arg_show_status);
- if (r < 0)
- log_warning("Failed to parse show status switch %s. Ignoring.", value);
-
- } else if (streq(key, "systemd.default_standard_output") && value) {
-
- r = exec_output_from_string(value);
- if (r < 0)
- log_warning("Failed to parse default standard output switch %s. Ignoring.", value);
- else
- arg_default_std_output = r;
-
- } else if (streq(key, "systemd.default_standard_error") && value) {
-
- r = exec_output_from_string(value);
- if (r < 0)
- log_warning("Failed to parse default standard error switch %s. Ignoring.", value);
- else
- arg_default_std_error = r;
-
- } else if (streq(key, "systemd.setenv") && value) {
-
- if (env_assignment_is_valid(value)) {
- char **env;
-
- env = strv_env_set(arg_default_environment, value);
- if (env)
- arg_default_environment = env;
- else
- log_warning_errno(ENOMEM, "Setting environment variable '%s' failed, ignoring: %m", value);
- } else
- log_warning("Environment variable name '%s' is not valid. Ignoring.", value);
-
- } else if (streq(key, "quiet") && !value) {
-
- if (arg_show_status == _SHOW_STATUS_UNSET)
- arg_show_status = SHOW_STATUS_AUTO;
-
- } else if (streq(key, "debug") && !value) {
-
- /* Note that log_parse_environment() handles 'debug'
- * too, and sets the log level to LOG_DEBUG. */
-
- if (detect_container(NULL) > 0)
- log_set_target(LOG_TARGET_CONSOLE);
-
- } else if (!in_initrd() && !value) {
- unsigned i;
-
- /* SysV compatibility */
- for (i = 0; i < ELEMENTSOF(rlmap); i += 2)
- if (streq(key, rlmap[i]))
- return set_default_unit(rlmap[i+1]);
- }
-
- return 0;
-}
-
-#define DEFINE_SETTER(name, func, descr) \
- static int 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 r; \
- \
- assert(filename); \
- assert(lvalue); \
- assert(rvalue); \
- \
- r = func(rvalue); \
- if (r < 0) \
- log_syntax(unit, LOG_ERR, filename, line, -r, \
- "Invalid " descr "'%s': %s", \
- rvalue, strerror(-r)); \
- \
- 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")
-
-static int config_parse_cpu_affinity2(
- 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) {
-
- const char *word, *state;
- size_t l;
- cpu_set_t *c = NULL;
- unsigned ncpus = 0;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- char *t;
- int r;
- unsigned cpu;
-
- if (!(t = strndup(word, l)))
- return log_oom();
-
- r = safe_atou(t, &cpu);
- free(t);
-
- if (!c)
- if (!(c = cpu_set_malloc(&ncpus)))
- return log_oom();
-
- if (r < 0 || cpu >= ncpus) {
- log_syntax(unit, LOG_ERR, filename, line, -r,
- "Failed to parse CPU affinity '%s'", rvalue);
- CPU_FREE(c);
- return -EBADMSG;
- }
-
- CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c);
- }
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
-
- if (c) {
- if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0)
- log_unit_warning(unit, "Failed to set CPU affinity: %m");
-
- CPU_FREE(c);
- }
-
- return 0;
-}
-
-static int config_parse_show_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 k;
- ShowStatus *b = data;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- k = parse_show_status(rvalue, b);
- if (k < 0) {
- log_syntax(unit, LOG_ERR, filename, line, -k,
- "Failed to parse show status setting, ignoring: %s", rvalue);
- return 0;
- }
-
- return 0;
-}
-
-static void strv_free_free(char ***l) {
- char ***i;
-
- if (!l)
- return;
-
- for (i = l; *i; i++)
- strv_free(*i);
-
- free(l);
-}
-
-static void free_join_controllers(void) {
- strv_free_free(arg_join_controllers);
- arg_join_controllers = NULL;
-}
-
-static int config_parse_join_controllers(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) {
-
- unsigned n = 0;
- const char *word, *state;
- size_t length;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- free_join_controllers();
-
- FOREACH_WORD_QUOTED(word, length, rvalue, state) {
- char *s, **l;
-
- s = strndup(word, length);
- if (!s)
- return log_oom();
-
- l = strv_split(s, ",");
- free(s);
-
- strv_uniq(l);
-
- if (strv_length(l) <= 1) {
- strv_free(l);
- continue;
- }
-
- if (!arg_join_controllers) {
- arg_join_controllers = new(char**, 2);
- if (!arg_join_controllers) {
- strv_free(l);
- return log_oom();
- }
-
- arg_join_controllers[0] = l;
- arg_join_controllers[1] = NULL;
-
- n = 1;
- } else {
- char ***a;
- char ***t;
-
- t = new0(char**, n+2);
- if (!t) {
- strv_free(l);
- return log_oom();
- }
-
- n = 0;
-
- for (a = arg_join_controllers; *a; a++) {
-
- if (strv_overlap(*a, l)) {
- if (strv_extend_strv(&l, *a) < 0) {
- strv_free(l);
- strv_free_free(t);
- return log_oom();
- }
-
- } else {
- char **c;
-
- c = strv_copy(*a);
- if (!c) {
- strv_free(l);
- strv_free_free(t);
- return log_oom();
- }
-
- t[n++] = c;
- }
- }
-
- t[n++] = strv_uniq(l);
-
- strv_free_free(arg_join_controllers);
- arg_join_controllers = t;
- }
- }
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Trailing garbage, ignoring.");
-
- return 0;
-}
-
-static int parse_config_file(void) {
-
- const ConfigTableItem items[] = {
- { "Manager", "LogLevel", config_parse_level2, 0, NULL },
- { "Manager", "LogTarget", config_parse_target, 0, NULL },
- { "Manager", "LogColor", config_parse_color, 0, NULL },
- { "Manager", "LogLocation", config_parse_location, 0, NULL },
- { "Manager", "DumpCore", config_parse_bool, 0, &arg_dump_core },
- { "Manager", "CrashShell", config_parse_bool, 0, &arg_crash_shell },
- { "Manager", "ShowStatus", config_parse_show_status, 0, &arg_show_status },
- { "Manager", "CrashChVT", config_parse_int, 0, &arg_crash_chvt },
- { "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, NULL },
- { "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers },
- { "Manager", "RuntimeWatchdogSec", config_parse_sec, 0, &arg_runtime_watchdog },
- { "Manager", "ShutdownWatchdogSec", config_parse_sec, 0, &arg_shutdown_watchdog },
- { "Manager", "CapabilityBoundingSet", config_parse_bounding_set, 0, &arg_capability_bounding_set_drop },
-#ifdef HAVE_SECCOMP
- { "Manager", "SystemCallArchitectures", config_parse_syscall_archs, 0, &arg_syscall_archs },
-#endif
- { "Manager", "TimerSlackNSec", config_parse_nsec, 0, &arg_timer_slack_nsec },
- { "Manager", "DefaultTimerAccuracySec", config_parse_sec, 0, &arg_default_timer_accuracy_usec },
- { "Manager", "DefaultStandardOutput", config_parse_output, 0, &arg_default_std_output },
- { "Manager", "DefaultStandardError", config_parse_output, 0, &arg_default_std_error },
- { "Manager", "DefaultTimeoutStartSec", config_parse_sec, 0, &arg_default_timeout_start_usec },
- { "Manager", "DefaultTimeoutStopSec", config_parse_sec, 0, &arg_default_timeout_stop_usec },
- { "Manager", "DefaultRestartSec", config_parse_sec, 0, &arg_default_restart_usec },
- { "Manager", "DefaultStartLimitInterval", 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, 0, &arg_default_rlimit[RLIMIT_CPU] },
- { "Manager", "DefaultLimitFSIZE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_FSIZE] },
- { "Manager", "DefaultLimitDATA", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_DATA] },
- { "Manager", "DefaultLimitSTACK", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_STACK] },
- { "Manager", "DefaultLimitCORE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_CORE] },
- { "Manager", "DefaultLimitRSS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RSS] },
- { "Manager", "DefaultLimitNOFILE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NOFILE] },
- { "Manager", "DefaultLimitAS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_AS] },
- { "Manager", "DefaultLimitNPROC", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NPROC] },
- { "Manager", "DefaultLimitMEMLOCK", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_MEMLOCK] },
- { "Manager", "DefaultLimitLOCKS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_LOCKS] },
- { "Manager", "DefaultLimitSIGPENDING", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_SIGPENDING] },
- { "Manager", "DefaultLimitMSGQUEUE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_MSGQUEUE] },
- { "Manager", "DefaultLimitNICE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NICE] },
- { "Manager", "DefaultLimitRTPRIO", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTPRIO] },
- { "Manager", "DefaultLimitRTTIME", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTTIME] },
- { "Manager", "DefaultCPUAccounting", config_parse_bool, 0, &arg_default_cpu_accounting },
- { "Manager", "DefaultBlockIOAccounting", config_parse_bool, 0, &arg_default_blockio_accounting },
- { "Manager", "DefaultMemoryAccounting", config_parse_bool, 0, &arg_default_memory_accounting },
- {}
- };
-
- const char *fn, *conf_dirs_nulstr;
-
- fn = arg_running_as == SYSTEMD_SYSTEM ? PKGSYSCONFDIR "/system.conf" : PKGSYSCONFDIR "/user.conf";
- conf_dirs_nulstr = arg_running_as == SYSTEMD_SYSTEM ? CONF_DIRS_NULSTR("systemd/system.conf") : CONF_DIRS_NULSTR("systemd/user.conf");
- config_parse_many(fn, conf_dirs_nulstr, "Manager\0",
- config_item_table_lookup, items, false, NULL);
-
- return 0;
-}
-
-static int parse_argv(int argc, char *argv[]) {
-
- enum {
- ARG_LOG_LEVEL = 0x100,
- ARG_LOG_TARGET,
- ARG_LOG_COLOR,
- ARG_LOG_LOCATION,
- ARG_UNIT,
- ARG_SYSTEM,
- ARG_USER,
- ARG_TEST,
- ARG_NO_PAGER,
- ARG_VERSION,
- ARG_DUMP_CONFIGURATION_ITEMS,
- ARG_DUMP_CORE,
- ARG_CRASH_SHELL,
- ARG_CONFIRM_SPAWN,
- ARG_SHOW_STATUS,
- ARG_DESERIALIZE,
- ARG_SWITCHED_ROOT,
- ARG_DEFAULT_STD_OUTPUT,
- ARG_DEFAULT_STD_ERROR
- };
-
- static const struct option options[] = {
- { "log-level", required_argument, NULL, ARG_LOG_LEVEL },
- { "log-target", required_argument, NULL, ARG_LOG_TARGET },
- { "log-color", optional_argument, NULL, ARG_LOG_COLOR },
- { "log-location", optional_argument, NULL, ARG_LOG_LOCATION },
- { "unit", required_argument, NULL, ARG_UNIT },
- { "system", no_argument, NULL, ARG_SYSTEM },
- { "user", no_argument, NULL, ARG_USER },
- { "test", no_argument, NULL, ARG_TEST },
- { "no-pager", no_argument, NULL, ARG_NO_PAGER },
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, ARG_VERSION },
- { "dump-configuration-items", no_argument, NULL, ARG_DUMP_CONFIGURATION_ITEMS },
- { "dump-core", optional_argument, NULL, ARG_DUMP_CORE },
- { "crash-shell", optional_argument, NULL, ARG_CRASH_SHELL },
- { "confirm-spawn", optional_argument, NULL, ARG_CONFIRM_SPAWN },
- { "show-status", optional_argument, NULL, ARG_SHOW_STATUS },
- { "deserialize", required_argument, NULL, ARG_DESERIALIZE },
- { "switched-root", no_argument, NULL, ARG_SWITCHED_ROOT },
- { "default-standard-output", required_argument, NULL, ARG_DEFAULT_STD_OUTPUT, },
- { "default-standard-error", required_argument, NULL, ARG_DEFAULT_STD_ERROR, },
- {}
- };
-
- int c, r;
-
- assert(argc >= 1);
- assert(argv);
-
- if (getpid() == 1)
- opterr = 0;
-
- while ((c = getopt_long(argc, argv, "hDbsz:", options, NULL)) >= 0)
-
- switch (c) {
-
- case ARG_LOG_LEVEL:
- r = log_set_max_level_from_string(optarg);
- if (r < 0) {
- log_error("Failed to parse log level %s.", optarg);
- return r;
- }
-
- break;
-
- case ARG_LOG_TARGET:
- r = log_set_target_from_string(optarg);
- if (r < 0) {
- log_error("Failed to parse log target %s.", optarg);
- return r;
- }
-
- break;
-
- case ARG_LOG_COLOR:
-
- if (optarg) {
- r = log_show_color_from_string(optarg);
- if (r < 0) {
- log_error("Failed to parse log color setting %s.", optarg);
- return r;
- }
- } else
- log_show_color(true);
-
- break;
-
- case ARG_LOG_LOCATION:
- if (optarg) {
- r = log_show_location_from_string(optarg);
- if (r < 0) {
- log_error("Failed to parse log location setting %s.", optarg);
- return r;
- }
- } else
- log_show_location(true);
-
- break;
-
- case ARG_DEFAULT_STD_OUTPUT:
- r = exec_output_from_string(optarg);
- if (r < 0) {
- log_error("Failed to parse default standard output setting %s.", optarg);
- return r;
- } else
- arg_default_std_output = r;
- break;
-
- case ARG_DEFAULT_STD_ERROR:
- r = exec_output_from_string(optarg);
- if (r < 0) {
- log_error("Failed to parse default standard error output setting %s.", optarg);
- return r;
- } else
- arg_default_std_error = r;
- break;
-
- case ARG_UNIT:
-
- r = set_default_unit(optarg);
- if (r < 0)
- return log_error_errno(r, "Failed to set default unit %s: %m", optarg);
-
- break;
-
- case ARG_SYSTEM:
- arg_running_as = SYSTEMD_SYSTEM;
- break;
-
- case ARG_USER:
- arg_running_as = SYSTEMD_USER;
- break;
-
- case ARG_TEST:
- arg_action = ACTION_TEST;
- if (arg_no_pager < 0)
- arg_no_pager = true;
- break;
-
- case ARG_NO_PAGER:
- arg_no_pager = true;
- break;
-
- case ARG_VERSION:
- arg_action = ACTION_VERSION;
- break;
-
- case ARG_DUMP_CONFIGURATION_ITEMS:
- arg_action = ACTION_DUMP_CONFIGURATION_ITEMS;
- break;
-
- case ARG_DUMP_CORE:
- r = optarg ? parse_boolean(optarg) : 1;
- if (r < 0) {
- log_error("Failed to parse dump core boolean %s.", optarg);
- return r;
- }
- arg_dump_core = r;
- break;
-
- case ARG_CRASH_SHELL:
- r = optarg ? parse_boolean(optarg) : 1;
- if (r < 0) {
- log_error("Failed to parse crash shell boolean %s.", optarg);
- return r;
- }
- arg_crash_shell = r;
- break;
-
- case ARG_CONFIRM_SPAWN:
- r = optarg ? parse_boolean(optarg) : 1;
- if (r < 0) {
- log_error("Failed to parse confirm spawn boolean %s.", optarg);
- return r;
- }
- arg_confirm_spawn = r;
- break;
-
- case ARG_SHOW_STATUS:
- if (optarg) {
- r = parse_show_status(optarg, &arg_show_status);
- if (r < 0) {
- log_error("Failed to parse show status boolean %s.", optarg);
- return r;
- }
- } else
- arg_show_status = SHOW_STATUS_YES;
- break;
-
- case ARG_DESERIALIZE: {
- int fd;
- FILE *f;
-
- r = safe_atoi(optarg, &fd);
- if (r < 0 || fd < 0) {
- log_error("Failed to parse deserialize option %s.", optarg);
- return r < 0 ? r : -EINVAL;
- }
-
- fd_cloexec(fd, true);
-
- f = fdopen(fd, "r");
- if (!f)
- return log_error_errno(errno, "Failed to open serialization fd: %m");
-
- if (arg_serialization)
- fclose(arg_serialization);
-
- arg_serialization = f;
-
- break;
- }
-
- case ARG_SWITCHED_ROOT:
- arg_switched_root = true;
- break;
-
- case 'h':
- arg_action = ACTION_HELP;
- if (arg_no_pager < 0)
- arg_no_pager = true;
- break;
-
- case 'D':
- log_set_max_level(LOG_DEBUG);
- break;
-
- case 'b':
- case 's':
- case 'z':
- /* Just to eat away the sysvinit kernel
- * cmdline args without getopt() error
- * messages that we'll parse in
- * parse_proc_cmdline_word() or ignore. */
-
- case '?':
- if (getpid() != 1)
- return -EINVAL;
- else
- return 0;
-
- default:
- assert_not_reached("Unhandled option code.");
- }
-
- if (optind < argc && getpid() != 1) {
- /* Hmm, when we aren't run as init system
- * let's complain about excess arguments */
-
- log_error("Excess arguments.");
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int help(void) {
-
- printf("%s [OPTIONS...]\n\n"
- "Starts up and maintains the system or user services.\n\n"
- " -h --help Show this help\n"
- " --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"
- " --unit=UNIT Set default unit\n"
- " --system Run a system instance, even if PID != 1\n"
- " --user Run a user instance\n"
- " --dump-core[=0|1] Dump core on crash\n"
- " --crash-shell[=0|1] Run shell on crash\n"
- " --confirm-spawn[=0|1] Ask for confirmation when spawning processes\n"
- " --show-status[=0|1] Show status updates on the console during bootup\n"
- " --log-target=TARGET Set log target (console, journal, kmsg, journal-or-kmsg, null)\n"
- " --log-level=LEVEL Set log level (debug, info, notice, warning, err, crit, alert, emerg)\n"
- " --log-color[=0|1] Highlight important log messages\n"
- " --log-location[=0|1] Include code location in log messages\n"
- " --default-standard-output= Set default standard output for services\n"
- " --default-standard-error= Set default standard error output for services\n",
- program_invocation_short_name);
-
- return 0;
-}
-
-static int version(void) {
- puts(PACKAGE_STRING);
- puts(SYSTEMD_FEATURES);
-
- return 0;
-}
-
-static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds, bool switching_root) {
- FILE *f = NULL;
- FDSet *fds = NULL;
- int r;
-
- assert(m);
- assert(_f);
- assert(_fds);
-
- r = manager_open_serialization(m, &f);
- if (r < 0) {
- log_error_errno(r, "Failed to create serialization file: %m");
- goto fail;
- }
-
- /* Make sure nothing is really destructed when we shut down */
- m->n_reloading ++;
- bus_manager_send_reloading(m, true);
-
- fds = fdset_new();
- if (!fds) {
- r = -ENOMEM;
- log_error_errno(r, "Failed to allocate fd set: %m");
- goto fail;
- }
-
- r = manager_serialize(m, f, fds, switching_root);
- if (r < 0) {
- log_error_errno(r, "Failed to serialize state: %m");
- goto fail;
- }
-
- if (fseeko(f, 0, SEEK_SET) < 0) {
- log_error_errno(errno, "Failed to rewind serialization fd: %m");
- goto fail;
- }
-
- r = fd_cloexec(fileno(f), false);
- if (r < 0) {
- log_error_errno(r, "Failed to disable O_CLOEXEC for serialization: %m");
- goto fail;
- }
-
- r = fdset_cloexec(fds, false);
- if (r < 0) {
- log_error_errno(r, "Failed to disable O_CLOEXEC for serialization fds: %m");
- goto fail;
- }
-
- *_f = f;
- *_fds = fds;
-
- return 0;
-
-fail:
- fdset_free(fds);
-
- if (f)
- fclose(f);
-
- return r;
-}
-
-static int bump_rlimit_nofile(struct rlimit *saved_rlimit) {
- struct rlimit nl;
- int r;
-
- assert(saved_rlimit);
-
- /* Save the original RLIMIT_NOFILE so that we can reset it
- * later when transitioning from the initrd to the main
- * systemd or suchlike. */
- if (getrlimit(RLIMIT_NOFILE, saved_rlimit) < 0)
- return log_error_errno(errno, "Reading RLIMIT_NOFILE failed: %m");
-
- /* Make sure forked processes get the default kernel setting */
- if (!arg_default_rlimit[RLIMIT_NOFILE]) {
- struct rlimit *rl;
-
- rl = newdup(struct rlimit, saved_rlimit, 1);
- if (!rl)
- return log_oom();
-
- arg_default_rlimit[RLIMIT_NOFILE] = rl;
- }
-
- /* Bump up the resource limit for ourselves substantially */
- nl.rlim_cur = nl.rlim_max = 64*1024;
- r = setrlimit_closest(RLIMIT_NOFILE, &nl);
- if (r < 0)
- return log_error_errno(r, "Setting RLIMIT_NOFILE failed: %m");
-
- return 0;
-}
-
-static void test_mtab(void) {
-
- static const char ok[] =
- "/proc/self/mounts\0"
- "/proc/mounts\0"
- "../proc/self/mounts\0"
- "../proc/mounts\0";
-
- _cleanup_free_ char *p = NULL;
- int r;
-
- /* Check that /etc/mtab is a symlink to the right place or
- * non-existing. But certainly not a file, or a symlink to
- * some weird place... */
-
- r = readlink_malloc("/etc/mtab", &p);
- if (r == -ENOENT)
- return;
- if (r >= 0 && nulstr_contains(ok, p))
- return;
-
- log_warning("/etc/mtab is not a symlink or not pointing to /proc/self/mounts. "
- "This is not supported anymore. "
- "Please make sure to replace this file by a symlink to avoid incorrect or misleading mount(8) output.");
-}
-
-static void test_usr(void) {
-
- /* Check that /usr is not a separate fs */
-
- if (dir_is_empty("/usr") <= 0)
- return;
-
- log_warning("/usr appears to be on its own filesystem and is not already mounted. This is not a supported setup. "
- "Some things will probably break (sometimes even silently) in mysterious ways. "
- "Consult http://freedesktop.org/wiki/Software/systemd/separate-usr-is-broken for more information.");
-}
-
-static int initialize_join_controllers(void) {
- /* By default, mount "cpu" + "cpuacct" together, and "net_cls"
- * + "net_prio". We'd like to add "cpuset" to the mix, but
- * "cpuset" doesn't really work for groups with no initialized
- * attributes. */
-
- arg_join_controllers = new(char**, 3);
- if (!arg_join_controllers)
- return -ENOMEM;
-
- arg_join_controllers[0] = strv_new("cpu", "cpuacct", NULL);
- arg_join_controllers[1] = strv_new("net_cls", "net_prio", NULL);
- arg_join_controllers[2] = NULL;
-
- if (!arg_join_controllers[0] || !arg_join_controllers[1]) {
- free_join_controllers();
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static int enforce_syscall_archs(Set *archs) {
-#ifdef HAVE_SECCOMP
- scmp_filter_ctx *seccomp;
- Iterator i;
- void *id;
- int r;
-
- seccomp = seccomp_init(SCMP_ACT_ALLOW);
- if (!seccomp)
- return log_oom();
-
- SET_FOREACH(id, arg_syscall_archs, i) {
- r = seccomp_arch_add(seccomp, PTR_TO_UINT32(id) - 1);
- if (r == -EEXIST)
- continue;
- if (r < 0) {
- log_error_errno(r, "Failed to add architecture to seccomp: %m");
- goto finish;
- }
- }
-
- r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0);
- if (r < 0) {
- log_error_errno(r, "Failed to unset NO_NEW_PRIVS: %m");
- goto finish;
- }
-
- r = seccomp_load(seccomp);
- if (r < 0)
- log_error_errno(r, "Failed to add install architecture seccomp: %m");
-
-finish:
- seccomp_release(seccomp);
- return r;
-#else
- return 0;
-#endif
-}
-
-static int status_welcome(void) {
- _cleanup_free_ char *pretty_name = NULL, *ansi_color = NULL;
- int r;
-
- r = parse_env_file("/etc/os-release", NEWLINE,
- "PRETTY_NAME", &pretty_name,
- "ANSI_COLOR", &ansi_color,
- NULL);
- if (r == -ENOENT) {
- r = parse_env_file("/usr/lib/os-release", NEWLINE,
- "PRETTY_NAME", &pretty_name,
- "ANSI_COLOR", &ansi_color,
- NULL);
- }
-
- if (r < 0 && r != -ENOENT)
- log_warning_errno(r, "Failed to read os-release file: %m");
-
- return status_printf(NULL, false, false,
- "\nWelcome to \x1B[%sm%s\x1B[0m!\n",
- isempty(ansi_color) ? "1" : ansi_color,
- isempty(pretty_name) ? "Linux" : pretty_name);
-}
-
-static int write_container_id(void) {
- const char *c;
-
- c = getenv("container");
- if (isempty(c))
- return 0;
-
- return write_string_file("/run/systemd/container", c);
-}
-
-int main(int argc, char *argv[]) {
- Manager *m = NULL;
- int r, retval = EXIT_FAILURE;
- usec_t before_startup, after_startup;
- char timespan[FORMAT_TIMESPAN_MAX];
- FDSet *fds = NULL;
- bool reexecute = false;
- const char *shutdown_verb = NULL;
- dual_timestamp initrd_timestamp = DUAL_TIMESTAMP_NULL;
- dual_timestamp userspace_timestamp = DUAL_TIMESTAMP_NULL;
- dual_timestamp kernel_timestamp = DUAL_TIMESTAMP_NULL;
- dual_timestamp security_start_timestamp = DUAL_TIMESTAMP_NULL;
- dual_timestamp security_finish_timestamp = DUAL_TIMESTAMP_NULL;
- static char systemd[] = "systemd";
- bool skip_setup = false;
- unsigned j;
- bool loaded_policy = false;
- bool arm_reboot_watchdog = false;
- bool queue_default_job = false;
- bool empty_etc = false;
- char *switch_root_dir = NULL, *switch_root_init = NULL;
- struct rlimit saved_rlimit_nofile = RLIMIT_MAKE_CONST(0);
- const char *error_message = NULL;
-
- dual_timestamp_from_monotonic(&kernel_timestamp, 0);
- dual_timestamp_get(&userspace_timestamp);
-
- /* Determine if this is a reexecution or normal bootup. We do
- * the full command line parsing much later, so let's just
- * have a quick peek here. */
- if (strv_find(argv+1, "--deserialize"))
- skip_setup = true;
-
- /* If we have switched root, do all the special setup
- * things */
- if (strv_find(argv+1, "--switched-root"))
- skip_setup = false;
-
- /* If we get started via the /sbin/init symlink then we are
- called 'init'. After a subsequent reexecution we are then
- called 'systemd'. That is confusing, hence let's call us
- systemd right-away. */
- program_invocation_short_name = systemd;
- prctl(PR_SET_NAME, systemd);
-
- saved_argv = argv;
- saved_argc = argc;
-
- log_show_color(isatty(STDERR_FILENO) > 0);
- log_set_upgrade_syslog_to_journal(true);
-
- /* Disable the umask logic */
- if (getpid() == 1)
- umask(0);
-
- if (getpid() == 1 && detect_container(NULL) <= 0) {
-
- /* Running outside of a container as PID 1 */
- arg_running_as = SYSTEMD_SYSTEM;
- make_null_stdio();
- log_set_target(LOG_TARGET_KMSG);
- log_open();
-
- if (in_initrd())
- initrd_timestamp = userspace_timestamp;
-
- if (!skip_setup) {
- mount_setup_early();
- dual_timestamp_get(&security_start_timestamp);
- if (mac_selinux_setup(&loaded_policy) < 0) {
- error_message = "Failed to load SELinux policy";
- goto finish;
- } else if (ima_setup() < 0) {
- error_message = "Failed to load IMA policy";
- goto finish;
- } else if (mac_smack_setup(&loaded_policy) < 0) {
- error_message = "Failed to load SMACK policy";
- goto finish;
- }
- dual_timestamp_get(&security_finish_timestamp);
- }
-
- if (mac_selinux_init(NULL) < 0) {
- error_message = "Failed to initialize SELinux policy";
- goto finish;
- }
-
- if (!skip_setup) {
- if (clock_is_localtime() > 0) {
- int min;
-
- /*
- * The very first call of settimeofday() also does a time warp in the kernel.
- *
- * In the rtc-in-local time mode, we set the kernel's timezone, and rely on
- * external tools to take care of maintaining the RTC and do all adjustments.
- * This matches the behavior of Windows, which leaves the RTC alone if the
- * registry tells that the RTC runs in UTC.
- */
- r = clock_set_timezone(&min);
- if (r < 0)
- log_error_errno(r, "Failed to apply local time delta, ignoring: %m");
- else
- log_info("RTC configured in localtime, applying delta of %i minutes to system time.", min);
- } else if (!in_initrd()) {
- /*
- * Do a dummy very first call to seal the kernel's time warp magic.
- *
- * Do not call this this from inside the initrd. The initrd might not
- * carry /etc/adjtime with LOCAL, but the real system could be set up
- * that way. In such case, we need to delay the time-warp or the sealing
- * until we reach the real system.
- *
- * Do no set the kernel's timezone. The concept of local time cannot
- * be supported reliably, the time will jump or be incorrect at every daylight
- * saving time change. All kernel local time concepts will be treated
- * as UTC that way.
- */
- clock_reset_timewarp();
- }
- }
-
- /* 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() == 1) {
- /* Running inside a container, as PID 1 */
- arg_running_as = SYSTEMD_SYSTEM;
- log_set_target(LOG_TARGET_CONSOLE);
- log_close_console(); /* force reopen of /dev/console */
- log_open();
-
- /* For the later on, see above... */
- log_set_target(LOG_TARGET_JOURNAL);
-
- /* clear the kernel timestamp,
- * because we are in a container */
- kernel_timestamp.monotonic = 0ULL;
- kernel_timestamp.realtime = 0ULL;
-
- } else {
- /* Running as user instance */
- arg_running_as = SYSTEMD_USER;
- log_set_target(LOG_TARGET_AUTO);
- log_open();
-
- /* clear the kernel timestamp,
- * because we are not PID 1 */
- kernel_timestamp.monotonic = 0ULL;
- kernel_timestamp.realtime = 0ULL;
- }
-
- /* Initialize default unit */
- r = set_default_unit(SPECIAL_DEFAULT_TARGET);
- if (r < 0) {
- log_emergency_errno(r, "Failed to set default unit %s: %m", SPECIAL_DEFAULT_TARGET);
- error_message = "Failed to set default unit";
- goto finish;
- }
-
- r = initialize_join_controllers();
- if (r < 0) {
- error_message = "Failed to initalize cgroup controllers";
- goto finish;
- }
-
- /* Mount /proc, /sys and friends, so that /proc/cmdline and
- * /proc/$PID/fd is available. */
- if (getpid() == 1) {
-
- /* Load the kernel modules early, so that we kdbus.ko is loaded before kdbusfs shall be mounted */
- if (!skip_setup)
- kmod_setup();
-
- r = mount_setup(loaded_policy);
- if (r < 0) {
- error_message = "Failed to mount API filesystems";
- goto finish;
- }
- }
-
- /* Reset all signal handlers. */
- assert_se(reset_all_signal_handlers() == 0);
-
- ignore_signals(SIGNALS_IGNORE, -1);
-
- if (parse_config_file() < 0) {
- error_message = "Failed to parse config file";
- goto finish;
- }
-
- if (arg_running_as == SYSTEMD_SYSTEM) {
- r = parse_proc_cmdline(parse_proc_cmdline_item);
- if (r < 0)
- log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
- }
-
- /* Note that this also parses bits from the kernel command
- * line, including "debug". */
- log_parse_environment();
-
- if (parse_argv(argc, argv) < 0) {
- error_message = "Failed to parse commandline arguments";
- goto finish;
- }
-
- if (arg_action == ACTION_TEST &&
- geteuid() == 0) {
- log_error("Don't run test mode as root.");
- goto finish;
- }
-
- if (arg_running_as == SYSTEMD_USER &&
- arg_action == ACTION_RUN &&
- sd_booted() <= 0) {
- log_error("Trying to run as user instance, but the system has not been booted with systemd.");
- goto finish;
- }
-
- if (arg_running_as == SYSTEMD_SYSTEM &&
- arg_action == ACTION_RUN &&
- running_in_chroot() > 0) {
- log_error("Cannot be run in a chroot() environment.");
- goto finish;
- }
-
- if (arg_action == ACTION_TEST)
- skip_setup = true;
-
- pager_open_if_enabled();
-
- if (arg_action == ACTION_HELP) {
- retval = help();
- goto finish;
- } else if (arg_action == ACTION_VERSION) {
- retval = version();
- goto finish;
- } else if (arg_action == ACTION_DUMP_CONFIGURATION_ITEMS) {
- unit_dump_config_items(stdout);
- retval = EXIT_SUCCESS;
- goto finish;
- } else if (arg_action == ACTION_DONE) {
- retval = EXIT_SUCCESS;
- goto finish;
- }
-
- if (arg_running_as == SYSTEMD_USER &&
- !getenv("XDG_RUNTIME_DIR")) {
- log_error("Trying to run as user instance, but $XDG_RUNTIME_DIR is not set.");
- goto finish;
- }
-
- assert_se(arg_action == ACTION_RUN || arg_action == ACTION_TEST);
-
- /* Close logging fds, in order not to confuse fdset below */
- log_close();
-
- /* Remember open file descriptors for later deserialization */
- r = fdset_new_fill(&fds);
- if (r < 0) {
- log_emergency_errno(r, "Failed to allocate fd set: %m");
- error_message = "Failed to allocate fd set";
- goto finish;
- } else
- fdset_cloexec(fds, true);
-
- if (arg_serialization)
- assert_se(fdset_remove(fds, fileno(arg_serialization)) >= 0);
-
- if (arg_running_as == SYSTEMD_SYSTEM)
- /* Become a session leader if we aren't one yet. */
- setsid();
-
- /* Move out of the way, so that we won't block unmounts */
- assert_se(chdir("/") == 0);
-
- /* Reset the console, but only if this is really init and we
- * are freshly booted */
- if (arg_running_as == SYSTEMD_SYSTEM && arg_action == ACTION_RUN) {
-
- /* If we are init, we connect stdin/stdout/stderr to
- * /dev/null and make sure we don't have a controlling
- * tty. */
- release_terminal();
-
- if (getpid() == 1 && !skip_setup)
- console_setup();
- }
-
- /* Open the logging devices, if possible and necessary */
- log_open();
-
- if (arg_show_status == _SHOW_STATUS_UNSET)
- arg_show_status = SHOW_STATUS_YES;
-
- /* Make sure we leave a core dump without panicing the
- * kernel. */
- if (getpid() == 1) {
- install_crash_handler();
-
- r = mount_cgroup_controllers(arg_join_controllers);
- if (r < 0)
- goto finish;
- }
-
- if (arg_running_as == SYSTEMD_SYSTEM) {
- const char *virtualization = NULL;
-
- log_info(PACKAGE_STRING " running in %ssystem mode. (" SYSTEMD_FEATURES ")",
- arg_action == ACTION_TEST ? "test " : "" );
-
- detect_virtualization(&virtualization);
- if (virtualization)
- log_info("Detected virtualization %s.", virtualization);
-
- write_container_id();
-
- log_info("Detected architecture %s.", architecture_to_string(uname_architecture()));
-
- if (in_initrd())
- log_info("Running in initial RAM disk.");
-
- /* Let's check whether /etc is already populated. We
- * don't actually really check for that, but use
- * /etc/machine-id as flag file. This allows container
- * managers and installers to provision a couple of
- * files already. If the container manager wants to
- * provision the machine ID itself it should pass
- * $container_uuid to PID 1. */
-
- empty_etc = access("/etc/machine-id", F_OK) < 0;
- if (empty_etc)
- log_info("Running with unpopulated /etc.");
- } else {
- _cleanup_free_ char *t;
-
- t = uid_to_name(getuid());
- log_debug(PACKAGE_STRING " running in %suser mode for user "UID_FMT"/%s. (" SYSTEMD_FEATURES ")",
- arg_action == ACTION_TEST ? " test" : "", getuid(), t);
- }
-
- if (arg_running_as == SYSTEMD_SYSTEM && !skip_setup) {
- if (arg_show_status > 0)
- status_welcome();
-
- hostname_setup();
- machine_id_setup(NULL);
- loopback_setup();
-
- test_mtab();
- test_usr();
- }
-
- if (arg_running_as == SYSTEMD_SYSTEM && arg_runtime_watchdog > 0)
- watchdog_set_timeout(&arg_runtime_watchdog);
-
- if (arg_timer_slack_nsec != NSEC_INFINITY)
- if (prctl(PR_SET_TIMERSLACK, arg_timer_slack_nsec) < 0)
- log_error_errno(errno, "Failed to adjust timer slack: %m");
-
- if (arg_capability_bounding_set_drop) {
- r = capability_bounding_set_drop_usermode(arg_capability_bounding_set_drop);
- if (r < 0) {
- log_emergency_errno(r, "Failed to drop capability bounding set of usermode helpers: %m");
- error_message = "Failed to drop capability bounding set of usermode helpers";
- goto finish;
- }
- r = capability_bounding_set_drop(arg_capability_bounding_set_drop, true);
- if (r < 0) {
- log_emergency_errno(r, "Failed to drop capability bounding set: %m");
- error_message = "Failed to drop capability bounding set";
- goto finish;
- }
- }
-
- if (arg_syscall_archs) {
- r = enforce_syscall_archs(arg_syscall_archs);
- if (r < 0) {
- error_message = "Failed to set syscall architectures";
- goto finish;
- }
- }
-
- if (arg_running_as == SYSTEMD_USER) {
- /* Become reaper of our children */
- if (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0) {
- log_warning_errno(errno, "Failed to make us a subreaper: %m");
- if (errno == EINVAL)
- log_info("Perhaps the kernel version is too old (< 3.4?)");
- }
- }
-
- if (arg_running_as == SYSTEMD_SYSTEM) {
- bump_rlimit_nofile(&saved_rlimit_nofile);
-
- if (empty_etc) {
- r = unit_file_preset_all(UNIT_FILE_SYSTEM, false, NULL, UNIT_FILE_PRESET_FULL, false, NULL, 0);
- if (r < 0)
- log_warning_errno(r, "Failed to populate /etc with preset unit settings, ignoring: %m");
- else
- log_info("Populated /etc with preset unit settings.");
- }
- }
-
- r = manager_new(arg_running_as, arg_action == ACTION_TEST, &m);
- if (r < 0) {
- log_emergency_errno(r, "Failed to allocate manager object: %m");
- error_message = "Failed to allocate manager object";
- goto finish;
- }
-
- m->confirm_spawn = arg_confirm_spawn;
- 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;
- m->default_restart_usec = arg_default_restart_usec;
- m->default_timeout_start_usec = arg_default_timeout_start_usec;
- m->default_timeout_stop_usec = arg_default_timeout_stop_usec;
- m->default_start_limit_interval = arg_default_start_limit_interval;
- m->default_start_limit_burst = arg_default_start_limit_burst;
- m->default_cpu_accounting = arg_default_cpu_accounting;
- m->default_blockio_accounting = arg_default_blockio_accounting;
- m->default_memory_accounting = arg_default_memory_accounting;
- m->runtime_watchdog = arg_runtime_watchdog;
- m->shutdown_watchdog = arg_shutdown_watchdog;
-
- m->userspace_timestamp = userspace_timestamp;
- m->kernel_timestamp = kernel_timestamp;
- m->initrd_timestamp = initrd_timestamp;
- m->security_start_timestamp = security_start_timestamp;
- m->security_finish_timestamp = security_finish_timestamp;
-
- manager_set_default_rlimits(m, arg_default_rlimit);
- manager_environment_add(m, NULL, arg_default_environment);
- manager_set_show_status(m, arg_show_status);
- manager_set_first_boot(m, empty_etc);
-
- /* Remember whether we should queue the default job */
- queue_default_job = !arg_serialization || arg_switched_root;
-
- before_startup = now(CLOCK_MONOTONIC);
-
- r = manager_startup(m, arg_serialization, fds);
- if (r < 0)
- log_error_errno(r, "Failed to fully start up daemon: %m");
-
- /* This will close all file descriptors that were opened, but
- * not claimed by any unit. */
- fdset_free(fds);
- fds = NULL;
-
- if (arg_serialization) {
- fclose(arg_serialization);
- arg_serialization = NULL;
- }
-
- if (queue_default_job) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- Unit *target = NULL;
- Job *default_unit_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 (target->load_state == UNIT_ERROR || target->load_state == 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_unit(m, SPECIAL_RESCUE_TARGET, NULL, &error, &target);
- if (r < 0) {
- log_emergency("Failed to load rescue target: %s", bus_error_message(&error, r));
- error_message = "Failed to load rescue target";
- goto finish;
- } else if (target->load_state == UNIT_ERROR || target->load_state == UNIT_NOT_FOUND) {
- log_emergency_errno(target->load_error, "Failed to load rescue target: %m");
- error_message = "Failed to load rescue target";
- goto finish;
- } else if (target->load_state == UNIT_MASKED) {
- log_emergency("Rescue target masked.");
- error_message = "Rescue target masked";
- goto finish;
- }
- }
-
- assert(target->load_state == UNIT_LOADED);
-
- if (arg_action == ACTION_TEST) {
- printf("-> By units:\n");
- manager_dump_units(m, stdout, "\t");
- }
-
- r = manager_add_job(m, JOB_START, target, JOB_ISOLATE, false, &error, &default_unit_job);
- if (r == -EPERM) {
- log_debug("Default target could not be isolated, starting instead: %s", bus_error_message(&error, r));
-
- r = manager_add_job(m, JOB_START, target, JOB_REPLACE, false, &error, &default_unit_job);
- if (r < 0) {
- log_emergency("Failed to start default target: %s", bus_error_message(&error, r));
- error_message = "Failed to start default target";
- goto finish;
- }
- } else if (r < 0) {
- log_emergency("Failed to isolate default target: %s", bus_error_message(&error, r));
- error_message = "Failed to isolate default target";
- goto finish;
- }
-
- m->default_unit_job_id = default_unit_job->id;
-
- after_startup = now(CLOCK_MONOTONIC);
- log_full(arg_action == ACTION_TEST ? LOG_INFO : LOG_DEBUG,
- "Loaded units and determined initial transaction in %s.",
- format_timespan(timespan, sizeof(timespan), after_startup - before_startup, 100 * USEC_PER_MSEC));
-
- if (arg_action == ACTION_TEST) {
- printf("-> By jobs:\n");
- manager_dump_jobs(m, stdout, "\t");
- retval = EXIT_SUCCESS;
- goto finish;
- }
- }
-
- for (;;) {
- r = manager_loop(m);
- if (r < 0) {
- log_emergency_errno(r, "Failed to run main loop: %m");
- error_message = "Failed to run main loop";
- goto finish;
- }
-
- switch (m->exit_code) {
-
- case MANAGER_EXIT:
- retval = EXIT_SUCCESS;
- log_debug("Exit.");
- goto finish;
-
- case MANAGER_RELOAD:
- log_info("Reloading.");
- r = manager_reload(m);
- if (r < 0)
- log_error_errno(r, "Failed to reload: %m");
- break;
-
- case MANAGER_REEXECUTE:
-
- if (prepare_reexecute(m, &arg_serialization, &fds, false) < 0) {
- error_message = "Failed to prepare for reexection";
- goto finish;
- }
-
- reexecute = true;
- log_notice("Reexecuting.");
- goto finish;
-
- case MANAGER_SWITCH_ROOT:
- /* Steal the switch root parameters */
- switch_root_dir = m->switch_root;
- switch_root_init = m->switch_root_init;
- m->switch_root = m->switch_root_init = NULL;
-
- if (!switch_root_init)
- if (prepare_reexecute(m, &arg_serialization, &fds, true) < 0) {
- error_message = "Failed to prepare for reexection";
- goto finish;
- }
-
- reexecute = true;
- log_notice("Switching root.");
- goto finish;
-
- case MANAGER_REBOOT:
- case MANAGER_POWEROFF:
- case MANAGER_HALT:
- case MANAGER_KEXEC: {
- static const char * const table[_MANAGER_EXIT_CODE_MAX] = {
- [MANAGER_REBOOT] = "reboot",
- [MANAGER_POWEROFF] = "poweroff",
- [MANAGER_HALT] = "halt",
- [MANAGER_KEXEC] = "kexec"
- };
-
- assert_se(shutdown_verb = table[m->exit_code]);
- arm_reboot_watchdog = m->exit_code == MANAGER_REBOOT;
-
- log_notice("Shutting down.");
- goto finish;
- }
-
- default:
- assert_not_reached("Unknown exit code.");
- }
- }
-
-finish:
- pager_close();
-
- if (m)
- arg_shutdown_watchdog = m->shutdown_watchdog;
- m = manager_free(m);
-
- for (j = 0; j < ELEMENTSOF(arg_default_rlimit); j++) {
- free(arg_default_rlimit[j]);
- arg_default_rlimit[j] = NULL;
- }
-
- free(arg_default_unit);
- arg_default_unit = NULL;
-
- free_join_controllers();
-
- strv_free(arg_default_environment);
- arg_default_environment = NULL;
-
- set_free(arg_syscall_archs);
- arg_syscall_archs = NULL;
-
- mac_selinux_finish();
-
- if (reexecute) {
- const char **args;
- unsigned i, args_size;
-
- /* Close and disarm the watchdog, so that the new
- * instance can reinitialize it, but doesn't get
- * rebooted while we do that */
- watchdog_close(true);
-
- /* Reset the RLIMIT_NOFILE to the kernel default, so
- * that the new systemd can pass the kernel default to
- * its child processes */
- if (saved_rlimit_nofile.rlim_cur > 0)
- setrlimit(RLIMIT_NOFILE, &saved_rlimit_nofile);
-
- if (switch_root_dir) {
- /* Kill all remaining processes from the
- * initrd, but don't wait for them, so that we
- * can handle the SIGCHLD for them after
- * deserializing. */
- broadcast_signal(SIGTERM, false, true);
-
- /* And switch root with MS_MOVE, because we remove the old directory afterwards and detach it. */
- r = switch_root(switch_root_dir, "/mnt", true, MS_MOVE);
- if (r < 0)
- log_error_errno(r, "Failed to switch root, trying to continue: %m");
- }
-
- args_size = MAX(6, argc+1);
- args = newa(const char*, args_size);
-
- if (!switch_root_init) {
- char sfd[DECIMAL_STR_MAX(int) + 1];
-
- /* First try to spawn ourselves with the right
- * path, and with full serialization. We do
- * this only if the user didn't specify an
- * explicit init to spawn. */
-
- assert(arg_serialization);
- assert(fds);
-
- xsprintf(sfd, "%i", fileno(arg_serialization));
-
- i = 0;
- args[i++] = SYSTEMD_BINARY_PATH;
- if (switch_root_dir)
- args[i++] = "--switched-root";
- args[i++] = arg_running_as == SYSTEMD_SYSTEM ? "--system" : "--user";
- args[i++] = "--deserialize";
- args[i++] = sfd;
- args[i++] = NULL;
-
- /* do not pass along the environment we inherit from the kernel or initrd */
- if (switch_root_dir)
- clearenv();
-
- assert(i <= args_size);
- execv(args[0], (char* const*) args);
- }
-
- /* Try the fallback, if there is any, without any
- * serialization. We pass the original argv[] and
- * envp[]. (Well, modulo the ordering changes due to
- * getopt() in argv[], and some cleanups in envp[],
- * but let's hope that doesn't matter.) */
-
- if (arg_serialization) {
- fclose(arg_serialization);
- arg_serialization = NULL;
- }
-
- if (fds) {
- fdset_free(fds);
- fds = NULL;
- }
-
- /* Reopen the console */
- make_console_stdio();
-
- for (j = 1, i = 1; j < (unsigned) argc; j++)
- args[i++] = argv[j];
- args[i++] = NULL;
- assert(i <= args_size);
-
- /* Reenable any blocked signals, especially important
- * if we switch from initial ramdisk to init=... */
- reset_all_signal_handlers();
- reset_signal_mask();
-
- if (switch_root_init) {
- args[0] = switch_root_init;
- execv(args[0], (char* const*) args);
- log_warning_errno(errno, "Failed to execute configured init, trying fallback: %m");
- }
-
- args[0] = "/sbin/init";
- execv(args[0], (char* const*) args);
-
- if (errno == ENOENT) {
- log_warning("No /sbin/init, trying fallback");
-
- args[0] = "/bin/sh";
- args[1] = NULL;
- execv(args[0], (char* const*) args);
- log_error_errno(errno, "Failed to execute /bin/sh, giving up: %m");
- } else
- log_warning_errno(errno, "Failed to execute /sbin/init, giving up: %m");
- }
-
- if (arg_serialization) {
- fclose(arg_serialization);
- arg_serialization = NULL;
- }
-
- if (fds) {
- fdset_free(fds);
- fds = NULL;
- }
-
-#ifdef HAVE_VALGRIND_VALGRIND_H
- /* If we are PID 1 and running under valgrind, then let's exit
- * here explicitly. valgrind will only generate nice output on
- * exit(), not on exec(), hence let's do the former not the
- * latter here. */
- if (getpid() == 1 && RUNNING_ON_VALGRIND)
- return 0;
-#endif
-
- if (shutdown_verb) {
- char log_level[DECIMAL_STR_MAX(int) + 1];
- const char* command_line[9] = {
- SYSTEMD_SHUTDOWN_BINARY_PATH,
- shutdown_verb,
- "--log-level", log_level,
- "--log-target",
- };
- unsigned pos = 5;
- _cleanup_strv_free_ char **env_block = NULL;
-
- assert(command_line[pos] == NULL);
- env_block = strv_copy(environ);
-
- xsprintf(log_level, "%d", log_get_max_level());
-
- switch (log_get_target()) {
- case LOG_TARGET_KMSG:
- case LOG_TARGET_JOURNAL_OR_KMSG:
- case LOG_TARGET_SYSLOG_OR_KMSG:
- command_line[pos++] = "kmsg";
- break;
-
- case LOG_TARGET_CONSOLE:
- default:
- command_line[pos++] = "console";
- break;
- };
-
- if (log_get_show_color())
- command_line[pos++] = "--log-color";
-
- if (log_get_show_location())
- command_line[pos++] = "--log-location";
-
- assert(pos < ELEMENTSOF(command_line));
-
- if (arm_reboot_watchdog && arg_shutdown_watchdog > 0) {
- char *e;
-
- /* If we reboot let's set the shutdown
- * watchdog and tell the shutdown binary to
- * repeatedly ping it */
- r = watchdog_set_timeout(&arg_shutdown_watchdog);
- watchdog_close(r < 0);
-
- /* Tell the binary how often to ping, ignore failure */
- if (asprintf(&e, "WATCHDOG_USEC="USEC_FMT, arg_shutdown_watchdog) > 0)
- strv_push(&env_block, e);
- } else
- watchdog_close(true);
-
- /* Avoid the creation of new processes forked by the
- * kernel; at this point, we will not listen to the
- * signals anyway */
- if (detect_container(NULL) <= 0)
- cg_uninstall_release_agent(SYSTEMD_CGROUP_CONTROLLER);
-
- execve(SYSTEMD_SHUTDOWN_BINARY_PATH, (char **) command_line, env_block);
- log_error_errno(errno, "Failed to execute shutdown binary, %s: %m",
- getpid() == 1 ? "freezing" : "quitting");
- }
-
- if (getpid() == 1) {
- if (error_message)
- manager_status_printf(NULL, STATUS_TYPE_EMERGENCY,
- ANSI_HIGHLIGHT_RED_ON "!!!!!!" ANSI_HIGHLIGHT_OFF,
- "%s, freezing.", error_message);
- freeze();
- }
-
- return retval;
-}
diff --git a/src/core/manager.c b/src/core/manager.c
deleted file mode 100644
index 1afd359df..000000000
--- a/src/core/manager.c
+++ /dev/null
@@ -1,3155 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 <string.h>
-#include <signal.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <sys/inotify.h>
-#include <sys/epoll.h>
-#include <sys/reboot.h>
-#include <sys/ioctl.h>
-#include <linux/kd.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <sys/timerfd.h>
-
-#ifdef HAVE_AUDIT
-#include <libaudit.h>
-#endif
-
-#include "sd-daemon.h"
-#include "sd-messages.h"
-
-#include "manager.h"
-#include "transaction.h"
-#include "hashmap.h"
-#include "macro.h"
-#include "strv.h"
-#include "log.h"
-#include "util.h"
-#include "mkdir.h"
-#include "ratelimit.h"
-#include "locale-setup.h"
-#include "unit-name.h"
-#include "missing.h"
-#include "path-lookup.h"
-#include "special.h"
-#include "exit-status.h"
-#include "virt.h"
-#include "watchdog.h"
-#include "path-util.h"
-#include "audit-fd.h"
-#include "boot-timestamps.h"
-#include "env-util.h"
-#include "bus-common-errors.h"
-#include "bus-error.h"
-#include "bus-util.h"
-#include "dbus.h"
-#include "dbus-unit.h"
-#include "dbus-job.h"
-#include "dbus-manager.h"
-#include "bus-kernel.h"
-#include "time-util.h"
-
-/* Initial delay and the interval for printing status messages about running jobs */
-#define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC)
-#define JOBS_IN_PROGRESS_PERIOD_USEC (USEC_PER_SEC / 3)
-#define JOBS_IN_PROGRESS_PERIOD_DIVISOR 3
-
-static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
-static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
-static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
-static int manager_dispatch_idle_pipe_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata);
-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_run_generators(Manager *m);
-static void manager_undo_generators(Manager *m);
-
-static void manager_watch_jobs_in_progress(Manager *m) {
- usec_t next;
-
- assert(m);
-
- if (m->jobs_in_progress_event_source)
- return;
-
- next = now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC;
- (void) sd_event_add_time(
- m->event,
- &m->jobs_in_progress_event_source,
- CLOCK_MONOTONIC,
- next, 0,
- manager_dispatch_jobs_in_progress, m);
-}
-
-#define CYLON_BUFFER_EXTRA (2*(sizeof(ANSI_RED_ON)-1) + sizeof(ANSI_HIGHLIGHT_RED_ON)-1 + 2*(sizeof(ANSI_HIGHLIGHT_OFF)-1))
-
-static void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned pos) {
- char *p = buffer;
-
- assert(buflen >= CYLON_BUFFER_EXTRA + width + 1);
- assert(pos <= width+1); /* 0 or width+1 mean that the center light is behind the corner */
-
- if (pos > 1) {
- if (pos > 2)
- p = mempset(p, ' ', pos-2);
- p = stpcpy(p, ANSI_RED_ON);
- *p++ = '*';
- }
-
- if (pos > 0 && pos <= width) {
- p = stpcpy(p, ANSI_HIGHLIGHT_RED_ON);
- *p++ = '*';
- }
-
- p = stpcpy(p, ANSI_HIGHLIGHT_OFF);
-
- if (pos < width) {
- p = stpcpy(p, ANSI_RED_ON);
- *p++ = '*';
- if (pos < width-1)
- p = mempset(p, ' ', width-1-pos);
- strcpy(p, ANSI_HIGHLIGHT_OFF);
- }
-}
-
-void manager_flip_auto_status(Manager *m, bool enable) {
- assert(m);
-
- if (enable) {
- if (m->show_status == SHOW_STATUS_AUTO)
- manager_set_show_status(m, SHOW_STATUS_TEMPORARY);
- } else {
- if (m->show_status == SHOW_STATUS_TEMPORARY)
- manager_set_show_status(m, SHOW_STATUS_AUTO);
- }
-}
-
-static void manager_print_jobs_in_progress(Manager *m) {
- _cleanup_free_ char *job_of_n = NULL;
- Iterator i;
- Job *j;
- unsigned counter = 0, print_nr;
- char cylon[6 + CYLON_BUFFER_EXTRA + 1];
- unsigned cylon_pos;
- char time[FORMAT_TIMESPAN_MAX], limit[FORMAT_TIMESPAN_MAX] = "no limit";
- uint64_t x;
-
- assert(m);
- assert(m->n_running_jobs > 0);
-
- manager_flip_auto_status(m, true);
-
- print_nr = (m->jobs_in_progress_iteration / JOBS_IN_PROGRESS_PERIOD_DIVISOR) % m->n_running_jobs;
-
- HASHMAP_FOREACH(j, m->jobs, i)
- if (j->state == JOB_RUNNING && counter++ == print_nr)
- break;
-
- /* m->n_running_jobs must be consistent with the contents of m->jobs,
- * so the above loop must have succeeded in finding j. */
- assert(counter == print_nr + 1);
- assert(j);
-
- cylon_pos = m->jobs_in_progress_iteration % 14;
- if (cylon_pos >= 8)
- cylon_pos = 14 - cylon_pos;
- draw_cylon(cylon, sizeof(cylon), 6, cylon_pos);
-
- m->jobs_in_progress_iteration++;
-
- if (m->n_running_jobs > 1) {
- if (asprintf(&job_of_n, "(%u of %u) ", counter, m->n_running_jobs) < 0)
- job_of_n = NULL;
- }
-
- format_timespan(time, sizeof(time), now(CLOCK_MONOTONIC) - j->begin_usec, 1*USEC_PER_SEC);
- if (job_get_timeout(j, &x) > 0)
- format_timespan(limit, sizeof(limit), x - j->begin_usec, 1*USEC_PER_SEC);
-
- manager_status_printf(m, STATUS_TYPE_EPHEMERAL, cylon,
- "%sA %s job is running for %s (%s / %s)",
- strempty(job_of_n),
- job_type_to_string(j->type),
- unit_description(j->unit),
- time, limit);
-}
-
-static int have_ask_password(void) {
- _cleanup_closedir_ DIR *dir;
-
- dir = opendir("/run/systemd/ask-password");
- if (!dir) {
- if (errno == ENOENT)
- return false;
- else
- return -errno;
- }
-
- for (;;) {
- struct dirent *de;
-
- errno = 0;
- de = readdir(dir);
- if (!de && errno != 0)
- return -errno;
- if (!de)
- return false;
-
- if (startswith(de->d_name, "ask."))
- return true;
- }
-}
-
-static int manager_dispatch_ask_password_fd(sd_event_source *source,
- int fd, uint32_t revents, void *userdata) {
- Manager *m = userdata;
-
- assert(m);
-
- flush_fd(fd);
-
- m->have_ask_password = have_ask_password();
- if (m->have_ask_password < 0)
- /* Log error but continue. Negative have_ask_password
- * is treated as unknown status. */
- log_error_errno(m->have_ask_password, "Failed to list /run/systemd/ask-password: %m");
-
- return 0;
-}
-
-static void manager_close_ask_password(Manager *m) {
- assert(m);
-
- m->ask_password_inotify_fd = safe_close(m->ask_password_inotify_fd);
- m->ask_password_event_source = sd_event_source_unref(m->ask_password_event_source);
- m->have_ask_password = -EINVAL;
-}
-
-static int manager_check_ask_password(Manager *m) {
- int r;
-
- assert(m);
-
- if (!m->ask_password_event_source) {
- assert(m->ask_password_inotify_fd < 0);
-
- mkdir_p_label("/run/systemd/ask-password", 0755);
-
- m->ask_password_inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
- if (m->ask_password_inotify_fd < 0)
- return log_error_errno(errno, "inotify_init1() failed: %m");
-
- if (inotify_add_watch(m->ask_password_inotify_fd, "/run/systemd/ask-password", IN_CREATE|IN_DELETE|IN_MOVE) < 0) {
- log_error_errno(errno, "Failed to add watch on /run/systemd/ask-password: %m");
- manager_close_ask_password(m);
- return -errno;
- }
-
- r = sd_event_add_io(m->event, &m->ask_password_event_source,
- m->ask_password_inotify_fd, EPOLLIN,
- manager_dispatch_ask_password_fd, m);
- if (r < 0) {
- log_error_errno(errno, "Failed to add event source for /run/systemd/ask-password: %m");
- manager_close_ask_password(m);
- return -errno;
- }
-
- /* Queries might have been added meanwhile... */
- manager_dispatch_ask_password_fd(m->ask_password_event_source,
- m->ask_password_inotify_fd, EPOLLIN, m);
- }
-
- return m->have_ask_password;
-}
-
-static int manager_watch_idle_pipe(Manager *m) {
- int r;
-
- assert(m);
-
- if (m->idle_pipe_event_source)
- return 0;
-
- if (m->idle_pipe[2] < 0)
- return 0;
-
- r = sd_event_add_io(m->event, &m->idle_pipe_event_source, m->idle_pipe[2], EPOLLIN, manager_dispatch_idle_pipe_fd, m);
- if (r < 0)
- return log_error_errno(r, "Failed to watch idle pipe: %m");
-
- return 0;
-}
-
-static void manager_close_idle_pipe(Manager *m) {
- assert(m);
-
- safe_close_pair(m->idle_pipe);
- safe_close_pair(m->idle_pipe + 2);
-}
-
-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)
- return 0;
-
- /* Uses TFD_TIMER_CANCEL_ON_SET to get notifications whenever
- * CLOCK_REALTIME makes a jump relative to CLOCK_MONOTONIC */
-
- m->time_change_fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC);
- 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;
- }
-
- 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");
-
- log_debug("Set up TFD_TIMER_CANCEL_ON_SET timerfd.");
-
- return 0;
-}
-
-static int enable_special_signals(Manager *m) {
- _cleanup_close_ int fd = -1;
-
- assert(m);
-
- /* Enable that we get SIGINT on control-alt-del. In containers
- * this will fail with EPERM (older) or EINVAL (newer), so
- * ignore that. */
- if (reboot(RB_DISABLE_CAD) < 0 && errno != EPERM && errno != EINVAL)
- log_warning_errno(errno, "Failed to enable ctrl-alt-del handling: %m");
-
- fd = open_terminal("/dev/tty0", O_RDWR|O_NOCTTY|O_CLOEXEC);
- if (fd < 0) {
- /* Support systems without virtual console */
- if (fd != -ENOENT)
- log_warning_errno(errno, "Failed to open /dev/tty0: %m");
- } else {
- /* Enable that we get SIGWINCH on kbrequest */
- if (ioctl(fd, KDSIGACCEPT, SIGWINCH) < 0)
- log_warning_errno(errno, "Failed to enable kbrequest handling: %m");
- }
-
- return 0;
-}
-
-static int manager_setup_signals(Manager *m) {
- struct sigaction sa = {
- .sa_handler = SIG_DFL,
- .sa_flags = SA_NOCLDSTOP|SA_RESTART,
- };
- sigset_t mask;
- int r;
-
- assert(m);
-
- assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
-
- /* We make liberal use of realtime signals here. On
- * Linux/glibc we have 30 of them (with the exception of Linux
- * on hppa, see below), between SIGRTMIN+0 ... SIGRTMIN+30
- * (aka SIGRTMAX). */
-
- assert_se(sigemptyset(&mask) == 0);
- sigset_add_many(&mask,
- SIGCHLD, /* Child died */
- SIGTERM, /* Reexecute daemon */
- SIGHUP, /* Reload configuration */
- SIGUSR1, /* systemd/upstart: reconnect to D-Bus */
- SIGUSR2, /* systemd: dump status */
- SIGINT, /* Kernel sends us this on control-alt-del */
- SIGWINCH, /* Kernel sends us this on kbrequest (alt-arrowup) */
- SIGPWR, /* Some kernel drivers and upsd send us this on power failure */
-
- SIGRTMIN+0, /* systemd: start default.target */
- SIGRTMIN+1, /* systemd: isolate rescue.target */
- SIGRTMIN+2, /* systemd: isolate emergency.target */
- SIGRTMIN+3, /* systemd: start halt.target */
- SIGRTMIN+4, /* systemd: start poweroff.target */
- SIGRTMIN+5, /* systemd: start reboot.target */
- SIGRTMIN+6, /* systemd: start kexec.target */
-
- /* ... space for more special targets ... */
-
- SIGRTMIN+13, /* systemd: Immediate halt */
- SIGRTMIN+14, /* systemd: Immediate poweroff */
- SIGRTMIN+15, /* systemd: Immediate reboot */
- SIGRTMIN+16, /* systemd: Immediate kexec */
-
- /* ... space for more immediate system state changes ... */
-
- SIGRTMIN+20, /* systemd: enable status messages */
- SIGRTMIN+21, /* systemd: disable status messages */
- SIGRTMIN+22, /* systemd: set log level to LOG_DEBUG */
- SIGRTMIN+23, /* systemd: set log level to LOG_INFO */
- SIGRTMIN+24, /* systemd: Immediate exit (--user only) */
-
- /* .. 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) */
-
- /* ... one free signal here SIGRTMIN+30 ... */
-#endif
- -1);
- assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
-
- m->signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC);
- if (m->signal_fd < 0)
- return -errno;
-
- r = sd_event_add_io(m->event, &m->signal_event_source, m->signal_fd, EPOLLIN, manager_dispatch_signal_fd, m);
- if (r < 0)
- return r;
-
- /* Process signals a bit earlier than the rest of things, but
- * later than notify_fd processing, so that the notify
- * processing can still figure out to which process/service a
- * message belongs, before we reap the process. */
- r = sd_event_source_set_priority(m->signal_event_source, -5);
- if (r < 0)
- return r;
-
- if (m->running_as == SYSTEMD_SYSTEM)
- return enable_special_signals(m);
-
- return 0;
-}
-
-static void manager_clean_environment(Manager *m) {
- assert(m);
-
- /* Let's remove some environment variables that we
- * need ourselves to communicate with our clients */
- strv_env_unset_many(
- m->environment,
- "NOTIFY_SOCKET",
- "MAINPID",
- "MANAGERPID",
- "LISTEN_PID",
- "LISTEN_FDS",
- "WATCHDOG_PID",
- "WATCHDOG_USEC",
- NULL);
-}
-
-static int manager_default_environment(Manager *m) {
- assert(m);
-
- if (m->running_as == SYSTEMD_SYSTEM) {
- /* The system manager always starts with a clean
- * environment for its children. It does not import
- * the kernel or the parents exported variables.
- *
- * The initial passed environ is untouched to keep
- * /proc/self/environ valid; it is used for tagging
- * the init process inside containers. */
- m->environment = strv_new("PATH=" DEFAULT_PATH,
- NULL);
-
- /* Import locale variables LC_*= from configuration */
- locale_setup(&m->environment);
- } else {
- /* The user manager passes its own environment
- * along to its children. */
- m->environment = strv_copy(environ);
- }
-
- if (!m->environment)
- return -ENOMEM;
-
- manager_clean_environment(m);
- strv_sort(m->environment);
-
- return 0;
-}
-
-int manager_new(SystemdRunningAs running_as, bool test_run, Manager **_m) {
- Manager *m;
- int r;
-
- assert(_m);
- assert(running_as >= 0);
- assert(running_as < _SYSTEMD_RUNNING_AS_MAX);
-
- m = new0(Manager, 1);
- if (!m)
- return -ENOMEM;
-
-#ifdef ENABLE_EFI
- if (running_as == SYSTEMD_SYSTEM && detect_container(NULL) <= 0)
- boot_timestamps(&m->userspace_timestamp, &m->firmware_timestamp, &m->loader_timestamp);
-#endif
-
- m->running_as = running_as;
- m->exit_code = _MANAGER_EXIT_CODE_INVALID;
- m->default_timer_accuracy_usec = USEC_PER_MINUTE;
-
- m->idle_pipe[0] = m->idle_pipe[1] = m->idle_pipe[2] = m->idle_pipe[3] = -1;
-
- m->pin_cgroupfs_fd = m->notify_fd = m->signal_fd = m->time_change_fd = m->dev_autofs_fd = m->private_listen_fd = m->kdbus_fd = m->utab_inotify_fd = -1;
- m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
-
- m->ask_password_inotify_fd = -1;
- m->have_ask_password = -EINVAL; /* we don't know */
-
- m->test_run = test_run;
-
- /* Reboot immediately if the user hits C-A-D more often than 7x per 2s */
- RATELIMIT_INIT(m->ctrl_alt_del_ratelimit, 2 * USEC_PER_SEC, 7);
-
- r = manager_default_environment(m);
- if (r < 0)
- goto fail;
-
- r = hashmap_ensure_allocated(&m->units, &string_hash_ops);
- if (r < 0)
- goto fail;
-
- r = hashmap_ensure_allocated(&m->jobs, NULL);
- if (r < 0)
- goto fail;
-
- r = hashmap_ensure_allocated(&m->cgroup_unit, &string_hash_ops);
- if (r < 0)
- goto fail;
-
- r = hashmap_ensure_allocated(&m->watch_bus, &string_hash_ops);
- if (r < 0)
- goto fail;
-
- r = set_ensure_allocated(&m->startup_units, NULL);
- if (r < 0)
- goto fail;
-
- r = set_ensure_allocated(&m->failed_units, NULL);
- if (r < 0)
- goto fail;
-
- r = sd_event_default(&m->event);
- if (r < 0)
- goto fail;
-
- r = sd_event_add_defer(m->event, &m->run_queue_event_source, manager_dispatch_run_queue, m);
- if (r < 0)
- goto fail;
-
- r = sd_event_source_set_priority(m->run_queue_event_source, SD_EVENT_PRIORITY_IDLE);
- if (r < 0)
- goto fail;
-
- r = sd_event_source_set_enabled(m->run_queue_event_source, SD_EVENT_OFF);
- if (r < 0)
- goto fail;
-
- r = manager_setup_signals(m);
- if (r < 0)
- goto fail;
-
- r = manager_setup_cgroup(m);
- if (r < 0)
- goto fail;
-
- r = manager_setup_time_change(m);
- if (r < 0)
- goto fail;
-
- m->udev = udev_new();
- if (!m->udev) {
- r = -ENOMEM;
- goto fail;
- }
-
- /* Note that we set up neither kdbus, nor the notify fd
- * here. We do that after deserialization, since they might
- * have gotten serialized across the reexec. */
-
- m->taint_usr = dir_is_empty("/usr") > 0;
-
- *_m = m;
- return 0;
-
-fail:
- manager_free(m);
- return r;
-}
-
-static int manager_setup_notify(Manager *m) {
- int r;
-
- if (m->test_run)
- return 0;
-
- if (m->notify_fd < 0) {
- _cleanup_close_ int fd = -1;
- union sockaddr_union sa = {
- .sa.sa_family = AF_UNIX,
- };
- static const int one = 1;
-
- /* First free all secondary fields */
- free(m->notify_socket);
- m->notify_socket = NULL;
- m->notify_event_source = sd_event_source_unref(m->notify_event_source);
-
- fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
- if (fd < 0)
- return log_error_errno(errno, "Failed to allocate notification socket: %m");
-
- if (m->running_as == SYSTEMD_SYSTEM)
- m->notify_socket = strdup("/run/systemd/notify");
- else {
- const char *e;
-
- e = getenv("XDG_RUNTIME_DIR");
- if (!e) {
- log_error_errno(errno, "XDG_RUNTIME_DIR is not set: %m");
- return -EINVAL;
- }
-
- m->notify_socket = strappend(e, "/systemd/notify");
- }
- if (!m->notify_socket)
- return log_oom();
-
- (void) mkdir_parents_label(m->notify_socket, 0755);
- (void) unlink(m->notify_socket);
-
- strncpy(sa.un.sun_path, m->notify_socket, sizeof(sa.un.sun_path)-1);
- r = bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
- if (r < 0)
- return log_error_errno(errno, "bind(%s) failed: %m", sa.un.sun_path);
-
- r = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
- if (r < 0)
- return log_error_errno(errno, "SO_PASSCRED failed: %m");
-
- m->notify_fd = fd;
- fd = -1;
-
- log_debug("Using notification socket %s", m->notify_socket);
- }
-
- if (!m->notify_event_source) {
- r = sd_event_add_io(m->event, &m->notify_event_source, m->notify_fd, EPOLLIN, manager_dispatch_notify_fd, m);
- if (r < 0)
- return log_error_errno(r, "Failed to allocate notify event source: %m");
-
- /* Process signals a bit earlier than SIGCHLD, so that we can
- * still identify to which service an exit message belongs */
- r = sd_event_source_set_priority(m->notify_event_source, -7);
- if (r < 0)
- return log_error_errno(r, "Failed to set priority of notify event source: %m");
- }
-
- return 0;
-}
-
-static int manager_setup_kdbus(Manager *m) {
-#ifdef ENABLE_KDBUS
- _cleanup_free_ char *p = NULL;
-
- assert(m);
-
- if (m->test_run || m->kdbus_fd >= 0)
- return 0;
-
- if (m->running_as == SYSTEMD_SYSTEM && detect_container(NULL) <= 0)
- bus_kernel_fix_attach_mask();
-
- m->kdbus_fd = bus_kernel_create_bus(
- m->running_as == SYSTEMD_SYSTEM ? "system" : "user",
- m->running_as == SYSTEMD_SYSTEM, &p);
-
- if (m->kdbus_fd < 0)
- return log_debug_errno(m->kdbus_fd, "Failed to set up kdbus: %m");
-
- log_debug("Successfully set up kdbus on %s", p);
-#endif
-
- return 0;
-}
-
-static int manager_connect_bus(Manager *m, bool reexecuting) {
- bool try_bus_connect;
-
- assert(m);
-
- if (m->test_run)
- return 0;
-
- try_bus_connect =
- m->kdbus_fd >= 0 ||
- reexecuting ||
- (m->running_as == SYSTEMD_USER && getenv("DBUS_SESSION_BUS_ADDRESS"));
-
- /* Try to connect to the busses, if possible. */
- return bus_init(m, try_bus_connect);
-}
-
-static unsigned manager_dispatch_cleanup_queue(Manager *m) {
- Unit *u;
- unsigned n = 0;
-
- assert(m);
-
- while ((u = m->cleanup_queue)) {
- assert(u->in_cleanup_queue);
-
- unit_free(u);
- n++;
- }
-
- return n;
-}
-
-enum {
- GC_OFFSET_IN_PATH, /* This one is on the path we were traveling */
- GC_OFFSET_UNSURE, /* No clue */
- GC_OFFSET_GOOD, /* We still need this unit */
- GC_OFFSET_BAD, /* We don't need this unit anymore */
- _GC_OFFSET_MAX
-};
-
-static void unit_gc_sweep(Unit *u, unsigned gc_marker) {
- Iterator i;
- Unit *other;
- bool is_bad;
-
- assert(u);
-
- if (u->gc_marker == gc_marker + GC_OFFSET_GOOD ||
- u->gc_marker == gc_marker + GC_OFFSET_BAD ||
- u->gc_marker == gc_marker + GC_OFFSET_IN_PATH)
- return;
-
- if (u->in_cleanup_queue)
- goto bad;
-
- if (unit_check_gc(u))
- goto good;
-
- u->gc_marker = gc_marker + GC_OFFSET_IN_PATH;
-
- is_bad = true;
-
- SET_FOREACH(other, u->dependencies[UNIT_REFERENCED_BY], i) {
- unit_gc_sweep(other, gc_marker);
-
- if (other->gc_marker == gc_marker + GC_OFFSET_GOOD)
- goto good;
-
- if (other->gc_marker != gc_marker + GC_OFFSET_BAD)
- is_bad = false;
- }
-
- if (is_bad)
- goto bad;
-
- /* We were unable to find anything out about this entry, so
- * let's investigate it later */
- u->gc_marker = gc_marker + GC_OFFSET_UNSURE;
- unit_add_to_gc_queue(u);
- return;
-
-bad:
- /* We definitely know that this one is not useful anymore, so
- * let's mark it for deletion */
- u->gc_marker = gc_marker + GC_OFFSET_BAD;
- unit_add_to_cleanup_queue(u);
- return;
-
-good:
- u->gc_marker = gc_marker + GC_OFFSET_GOOD;
-}
-
-static unsigned manager_dispatch_gc_queue(Manager *m) {
- Unit *u;
- unsigned n = 0;
- unsigned gc_marker;
-
- assert(m);
-
- /* log_debug("Running GC..."); */
-
- m->gc_marker += _GC_OFFSET_MAX;
- if (m->gc_marker + _GC_OFFSET_MAX <= _GC_OFFSET_MAX)
- m->gc_marker = 1;
-
- gc_marker = m->gc_marker;
-
- while ((u = m->gc_queue)) {
- assert(u->in_gc_queue);
-
- unit_gc_sweep(u, gc_marker);
-
- LIST_REMOVE(gc_queue, m->gc_queue, u);
- u->in_gc_queue = false;
-
- n++;
-
- if (u->gc_marker == gc_marker + GC_OFFSET_BAD ||
- u->gc_marker == gc_marker + GC_OFFSET_UNSURE) {
- if (u->id)
- log_unit_debug(u->id, "Collecting %s", u->id);
- u->gc_marker = gc_marker + GC_OFFSET_BAD;
- unit_add_to_cleanup_queue(u);
- }
- }
-
- m->n_in_gc_queue = 0;
-
- return n;
-}
-
-static void manager_clear_jobs_and_units(Manager *m) {
- Unit *u;
-
- assert(m);
-
- while ((u = hashmap_first(m->units)))
- unit_free(u);
-
- manager_dispatch_cleanup_queue(m);
-
- assert(!m->load_queue);
- assert(!m->run_queue);
- assert(!m->dbus_unit_queue);
- assert(!m->dbus_job_queue);
- assert(!m->cleanup_queue);
- assert(!m->gc_queue);
-
- assert(hashmap_isempty(m->jobs));
- assert(hashmap_isempty(m->units));
-
- m->n_on_console = 0;
- m->n_running_jobs = 0;
-}
-
-Manager* manager_free(Manager *m) {
- UnitType c;
- int i;
-
- if (!m)
- return NULL;
-
- manager_clear_jobs_and_units(m);
-
- for (c = 0; c < _UNIT_TYPE_MAX; c++)
- if (unit_vtable[c]->shutdown)
- unit_vtable[c]->shutdown(m);
-
- /* If we reexecute ourselves, we keep the root cgroup
- * around */
- manager_shutdown_cgroup(m, m->exit_code != MANAGER_REEXECUTE);
-
- manager_undo_generators(m);
-
- bus_done(m);
-
- hashmap_free(m->units);
- hashmap_free(m->jobs);
- hashmap_free(m->watch_pids1);
- hashmap_free(m->watch_pids2);
- hashmap_free(m->watch_bus);
-
- set_free(m->startup_units);
- set_free(m->failed_units);
-
- sd_event_source_unref(m->signal_event_source);
- sd_event_source_unref(m->notify_event_source);
- sd_event_source_unref(m->time_change_event_source);
- sd_event_source_unref(m->jobs_in_progress_event_source);
- sd_event_source_unref(m->idle_pipe_event_source);
- sd_event_source_unref(m->run_queue_event_source);
-
- safe_close(m->signal_fd);
- safe_close(m->notify_fd);
- safe_close(m->time_change_fd);
- safe_close(m->kdbus_fd);
-
- manager_close_ask_password(m);
-
- manager_close_idle_pipe(m);
-
- udev_unref(m->udev);
- sd_event_unref(m->event);
-
- free(m->notify_socket);
-
- lookup_paths_free(&m->lookup_paths);
- strv_free(m->environment);
-
- hashmap_free(m->cgroup_unit);
- set_free_free(m->unit_path_cache);
-
- free(m->switch_root);
- free(m->switch_root_init);
-
- for (i = 0; i < _RLIMIT_MAX; i++)
- free(m->rlimit[i]);
-
- assert(hashmap_isempty(m->units_requiring_mounts_for));
- hashmap_free(m->units_requiring_mounts_for);
-
- free(m);
- return NULL;
-}
-
-int manager_enumerate(Manager *m) {
- int r = 0;
- 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++) {
- int q;
-
- if (unit_vtable[c]->supported && !unit_vtable[c]->supported(m)) {
- log_debug("Unit type .%s is not supported on this system.", unit_type_to_string(c));
- continue;
- }
-
- if (!unit_vtable[c]->enumerate)
- continue;
-
- q = unit_vtable[c]->enumerate(m);
- if (q < 0)
- r = q;
- }
-
- manager_dispatch_load_queue(m);
- return r;
-}
-
-static int manager_coldplug(Manager *m) {
- int r = 0;
- Iterator i;
- Unit *u;
- char *k;
-
- /*
- * Some unit types tend to spawn jobs or check other units' state
- * during coldplug. This is wrong because it is undefined whether the
- * units in question have been already coldplugged (i. e. their state
- * restored). This way, we can easily re-start an already started unit
- * or otherwise make a wrong decision based on the unit's state.
- *
- * Solve this by providing a way for coldplug functions to defer
- * such actions until after all units have been coldplugged.
- *
- * We store Unit* -> int(*)(Unit*).
- *
- * https://bugs.freedesktop.org/show_bug.cgi?id=88401
- */
- _cleanup_hashmap_free_ Hashmap *deferred_work = NULL;
- int(*proc)(Unit*);
-
- assert(m);
-
- deferred_work = hashmap_new(&trivial_hash_ops);
- if (!deferred_work)
- return -ENOMEM;
-
- /* Then, let's set up their initial state. */
- HASHMAP_FOREACH_KEY(u, k, m->units, i) {
- int q;
-
- /* ignore aliases */
- if (u->id != k)
- continue;
-
- q = unit_coldplug(u, deferred_work);
- if (q < 0)
- r = q;
- }
-
- /* After coldplugging and setting up initial state of the units,
- * let's perform operations which spawn jobs or query units' state. */
- HASHMAP_FOREACH_KEY(proc, u, deferred_work, i) {
- int q;
-
- q = proc(u);
- if (q < 0)
- r = q;
- }
-
- return r;
-}
-
-static void manager_build_unit_path_cache(Manager *m) {
- char **i;
- _cleanup_closedir_ DIR *d = NULL;
- int r;
-
- assert(m);
-
- set_free_free(m->unit_path_cache);
-
- m->unit_path_cache = set_new(&string_hash_ops);
- if (!m->unit_path_cache) {
- log_error("Failed to allocate unit path cache.");
- return;
- }
-
- /* This simply builds a list of files we know exist, so that
- * we don't always have to go to disk */
-
- STRV_FOREACH(i, m->lookup_paths.unit_path) {
- struct dirent *de;
-
- d = opendir(*i);
- if (!d) {
- if (errno != ENOENT)
- log_error_errno(errno, "Failed to open directory %s: %m", *i);
- continue;
- }
-
- while ((de = readdir(d))) {
- char *p;
-
- if (hidden_file(de->d_name))
- continue;
-
- p = strjoin(streq(*i, "/") ? "" : *i, "/", de->d_name, NULL);
- if (!p) {
- r = -ENOMEM;
- goto fail;
- }
-
- r = set_consume(m->unit_path_cache, p);
- if (r < 0)
- goto fail;
- }
-
- closedir(d);
- d = NULL;
- }
-
- return;
-
-fail:
- log_error_errno(r, "Failed to build unit path cache: %m");
-
- set_free_free(m->unit_path_cache);
- m->unit_path_cache = NULL;
-}
-
-
-static int manager_distribute_fds(Manager *m, FDSet *fds) {
- Unit *u;
- Iterator i;
- int r;
-
- assert(m);
-
- HASHMAP_FOREACH(u, m->units, i) {
-
- if (fdset_size(fds) <= 0)
- break;
-
- if (UNIT_VTABLE(u)->distribute_fds) {
- r = UNIT_VTABLE(u)->distribute_fds(u, fds);
- if (r < 0)
- return r;
- }
- }
-
- return 0;
-}
-
-int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
- int r, q;
-
- assert(m);
-
- dual_timestamp_get(&m->generators_start_timestamp);
- r = manager_run_generators(m);
- dual_timestamp_get(&m->generators_finish_timestamp);
- if (r < 0)
- return r;
-
- r = lookup_paths_init(
- &m->lookup_paths, m->running_as, true,
- NULL,
- m->generator_unit_path,
- m->generator_unit_path_early,
- m->generator_unit_path_late);
- if (r < 0)
- return r;
-
- manager_build_unit_path_cache(m);
-
- /* If we will deserialize make sure that during enumeration
- * this is already known, so we increase the counter here
- * already */
- if (serialization)
- m->n_reloading ++;
-
- /* First, enumerate what we can from all config files */
- dual_timestamp_get(&m->units_load_start_timestamp);
- r = manager_enumerate(m);
- dual_timestamp_get(&m->units_load_finish_timestamp);
-
- /* Second, deserialize if there is something to deserialize */
- if (serialization)
- r = manager_deserialize(m, serialization, fds);
-
- /* Any fds left? Find some unit which wants them. This is
- * useful to allow container managers to pass some file
- * descriptors to us pre-initialized. This enables
- * socket-based activation of entire containers. */
- if (fdset_size(fds) > 0) {
- q = manager_distribute_fds(m, fds);
- if (q < 0 && r == 0)
- r = q;
- }
-
- /* We might have deserialized the notify fd, but if we didn't
- * then let's create the bus now */
- q = manager_setup_notify(m);
- if (q < 0 && r == 0)
- r = q;
-
- /* We might have deserialized the kdbus control fd, but if we
- * didn't, then let's create the bus now. */
- manager_setup_kdbus(m);
- manager_connect_bus(m, !!serialization);
- bus_track_coldplug(m, &m->subscribed, &m->deserialized_subscribed);
-
- /* Third, fire things up! */
- q = manager_coldplug(m);
- if (q < 0 && r == 0)
- r = q;
-
- if (serialization) {
- assert(m->n_reloading > 0);
- m->n_reloading --;
-
- /* Let's wait for the UnitNew/JobNew messages being
- * sent, before we notify that the reload is
- * finished */
- m->send_reloading_done = true;
- }
-
- return r;
-}
-
-int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, sd_bus_error *e, Job **_ret) {
- int r;
- Transaction *tr;
-
- assert(m);
- assert(type < _JOB_TYPE_MAX);
- assert(unit);
- assert(mode < _JOB_MODE_MAX);
-
- if (mode == JOB_ISOLATE && type != JOB_START)
- return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Isolate is only valid for start.");
-
- if (mode == JOB_ISOLATE && !unit->allow_isolate)
- return sd_bus_error_setf(e, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
-
- log_unit_debug(unit->id,
- "Trying to enqueue job %s/%s/%s", unit->id,
- job_type_to_string(type), job_mode_to_string(mode));
-
- job_type_collapse(&type, unit);
-
- tr = transaction_new(mode == JOB_REPLACE_IRREVERSIBLY);
- if (!tr)
- return -ENOMEM;
-
- r = transaction_add_job_and_dependencies(tr, type, unit, NULL, true, override, false,
- mode == JOB_IGNORE_DEPENDENCIES || mode == JOB_IGNORE_REQUIREMENTS,
- mode == JOB_IGNORE_DEPENDENCIES, e);
- if (r < 0)
- goto tr_abort;
-
- if (mode == JOB_ISOLATE) {
- r = transaction_add_isolate_jobs(tr, m);
- if (r < 0)
- goto tr_abort;
- }
-
- r = transaction_activate(tr, m, mode, e);
- if (r < 0)
- goto tr_abort;
-
- log_unit_debug(unit->id,
- "Enqueued job %s/%s as %u", unit->id,
- job_type_to_string(type), (unsigned) tr->anchor_job->id);
-
- if (_ret)
- *_ret = tr->anchor_job;
-
- transaction_free(tr);
- return 0;
-
-tr_abort:
- transaction_abort(tr);
- transaction_free(tr);
- return r;
-}
-
-int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool override, sd_bus_error *e, Job **_ret) {
- Unit *unit;
- int r;
-
- assert(m);
- assert(type < _JOB_TYPE_MAX);
- assert(name);
- assert(mode < _JOB_MODE_MAX);
-
- r = manager_load_unit(m, name, NULL, NULL, &unit);
- if (r < 0)
- return r;
-
- return manager_add_job(m, type, unit, mode, override, e, _ret);
-}
-
-Job *manager_get_job(Manager *m, uint32_t id) {
- assert(m);
-
- return hashmap_get(m->jobs, UINT32_TO_PTR(id));
-}
-
-Unit *manager_get_unit(Manager *m, const char *name) {
- assert(m);
- assert(name);
-
- return hashmap_get(m->units, name);
-}
-
-unsigned manager_dispatch_load_queue(Manager *m) {
- Unit *u;
- unsigned n = 0;
-
- assert(m);
-
- /* Make sure we are not run recursively */
- if (m->dispatching_load_queue)
- return 0;
-
- m->dispatching_load_queue = true;
-
- /* Dispatches the load queue. Takes a unit from the queue and
- * tries to load its data until the queue is empty */
-
- while ((u = m->load_queue)) {
- assert(u->in_load_queue);
-
- unit_load(u);
- n++;
- }
-
- m->dispatching_load_queue = false;
- return n;
-}
-
-int manager_load_unit_prepare(
- Manager *m,
- const char *name,
- const char *path,
- sd_bus_error *e,
- Unit **_ret) {
-
- Unit *ret;
- UnitType t;
- int r;
-
- assert(m);
- assert(name || path);
-
- /* This will prepare the unit for loading, but not actually
- * load anything from disk. */
-
- if (path && !is_path(path))
- return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Path %s is not absolute.", path);
-
- if (!name)
- name = basename(path);
-
- t = unit_name_to_type(name);
-
- if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, TEMPLATE_INVALID))
- return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name);
-
- ret = manager_get_unit(m, name);
- if (ret) {
- *_ret = ret;
- return 1;
- }
-
- 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);
- return -ENOMEM;
- }
- }
-
- r = unit_add_name(ret, name);
- if (r < 0) {
- unit_free(ret);
- return r;
- }
-
- unit_add_to_load_queue(ret);
- unit_add_to_dbus_queue(ret);
- unit_add_to_gc_queue(ret);
-
- if (_ret)
- *_ret = ret;
-
- return 0;
-}
-
-int manager_load_unit(
- Manager *m,
- const char *name,
- const char *path,
- sd_bus_error *e,
- Unit **_ret) {
-
- int r;
-
- assert(m);
-
- /* This will load the service information files, but not actually
- * start any services or anything. */
-
- r = manager_load_unit_prepare(m, name, path, e, _ret);
- if (r != 0)
- return r;
-
- manager_dispatch_load_queue(m);
-
- if (_ret)
- *_ret = unit_follow_merge(*_ret);
-
- return 0;
-}
-
-void manager_dump_jobs(Manager *s, FILE *f, const char *prefix) {
- Iterator i;
- Job *j;
-
- assert(s);
- assert(f);
-
- HASHMAP_FOREACH(j, s->jobs, i)
- job_dump(j, f, prefix);
-}
-
-void manager_dump_units(Manager *s, FILE *f, const char *prefix) {
- Iterator i;
- Unit *u;
- const char *t;
-
- assert(s);
- assert(f);
-
- HASHMAP_FOREACH_KEY(u, t, s->units, i)
- if (u->id == t)
- unit_dump(u, f, prefix);
-}
-
-void manager_clear_jobs(Manager *m) {
- Job *j;
-
- assert(m);
-
- while ((j = hashmap_first(m->jobs)))
- /* No need to recurse. We're cancelling all jobs. */
- job_finish_and_invalidate(j, JOB_CANCELED, false);
-}
-
-static int manager_dispatch_run_queue(sd_event_source *source, void *userdata) {
- Manager *m = userdata;
- Job *j;
-
- assert(source);
- assert(m);
-
- while ((j = m->run_queue)) {
- assert(j->installed);
- assert(j->in_run_queue);
-
- job_run_and_invalidate(j);
- }
-
- if (m->n_running_jobs > 0)
- manager_watch_jobs_in_progress(m);
-
- if (m->n_on_console > 0)
- manager_watch_idle_pipe(m);
-
- return 1;
-}
-
-static unsigned manager_dispatch_dbus_queue(Manager *m) {
- Job *j;
- Unit *u;
- unsigned n = 0;
-
- assert(m);
-
- if (m->dispatching_dbus_queue)
- return 0;
-
- m->dispatching_dbus_queue = true;
-
- while ((u = m->dbus_unit_queue)) {
- assert(u->in_dbus_queue);
-
- bus_unit_send_change_signal(u);
- n++;
- }
-
- while ((j = m->dbus_job_queue)) {
- assert(j->in_dbus_queue);
-
- bus_job_send_change_signal(j);
- n++;
- }
-
- m->dispatching_dbus_queue = false;
-
- if (m->send_reloading_done) {
- m->send_reloading_done = false;
-
- bus_manager_send_reloading(m, false);
- }
-
- if (m->queued_message)
- bus_send_queued_message(m);
-
- return n;
-}
-
-static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char *buf, size_t n, FDSet *fds) {
- _cleanup_strv_free_ char **tags = NULL;
-
- assert(m);
- assert(u);
- assert(buf);
- assert(n > 0);
-
- tags = strv_split(buf, "\n\r");
- if (!tags) {
- log_oom();
- return;
- }
-
- log_unit_debug(u->id, "Got notification message for unit %s", u->id);
-
- if (UNIT_VTABLE(u)->notify_message)
- UNIT_VTABLE(u)->notify_message(u, pid, tags, fds);
-}
-
-static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
- Manager *m = userdata;
- ssize_t n;
- int r;
-
- assert(m);
- assert(m->notify_fd == fd);
-
- if (revents != EPOLLIN) {
- log_warning("Got unexpected poll event for notify fd.");
- return 0;
- }
-
- for (;;) {
- _cleanup_fdset_free_ FDSet *fds = NULL;
- char buf[NOTIFY_BUFFER_MAX+1];
- struct iovec iovec = {
- .iov_base = buf,
- .iov_len = sizeof(buf)-1,
- };
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
- CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)];
- } control = {};
- struct msghdr msghdr = {
- .msg_iov = &iovec,
- .msg_iovlen = 1,
- .msg_control = &control,
- .msg_controllen = sizeof(control),
- };
- struct cmsghdr *cmsg;
- struct ucred *ucred = NULL;
- bool found = false;
- Unit *u1, *u2, *u3;
- int *fd_array = NULL;
- unsigned n_fds = 0;
-
- n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
- if (n < 0) {
- if (errno == EAGAIN || errno == EINTR)
- break;
-
- return -errno;
- }
-
- for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) {
- if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
-
- fd_array = (int*) CMSG_DATA(cmsg);
- n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
-
- } else if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_CREDENTIALS &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
-
- ucred = (struct ucred*) CMSG_DATA(cmsg);
- }
- }
-
- if (n_fds > 0) {
- assert(fd_array);
-
- r = fdset_new_array(&fds, fd_array, n_fds);
- if (r < 0) {
- close_many(fd_array, n_fds);
- return log_oom();
- }
- }
-
- if (!ucred || ucred->pid <= 0) {
- log_warning("Received notify message without valid credentials. Ignoring.");
- continue;
- }
-
- if ((size_t) n >= sizeof(buf)) {
- log_warning("Received notify message exceeded maximum size. Ignoring.");
- continue;
- }
-
- buf[n] = 0;
-
- /* Notify every unit that might be interested, but try
- * to avoid notifying the same one multiple times. */
- u1 = manager_get_unit_by_pid(m, ucred->pid);
- if (u1) {
- manager_invoke_notify_message(m, u1, ucred->pid, buf, n, fds);
- found = true;
- }
-
- u2 = hashmap_get(m->watch_pids1, LONG_TO_PTR(ucred->pid));
- if (u2 && u2 != u1) {
- manager_invoke_notify_message(m, u2, ucred->pid, buf, n, fds);
- found = true;
- }
-
- u3 = hashmap_get(m->watch_pids2, LONG_TO_PTR(ucred->pid));
- if (u3 && u3 != u2 && u3 != u1) {
- manager_invoke_notify_message(m, u3, ucred->pid, buf, n, fds);
- found = true;
- }
-
- if (!found)
- log_warning("Cannot find unit for notify message of PID "PID_FMT".", ucred->pid);
-
- if (fdset_size(fds) > 0)
- log_warning("Got auxiliary fds with notification message, closing all.");
- }
-
- return 0;
-}
-
-static void invoke_sigchld_event(Manager *m, Unit *u, siginfo_t *si) {
- assert(m);
- assert(u);
- assert(si);
-
- log_unit_debug(u->id, "Child "PID_FMT" belongs to %s", si->si_pid, u->id);
-
- unit_unwatch_pid(u, si->si_pid);
- UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status);
-}
-
-static int manager_dispatch_sigchld(Manager *m) {
- assert(m);
-
- for (;;) {
- siginfo_t si = {};
-
- /* First we call waitd() for a PID and do not reap the
- * zombie. That way we can still access /proc/$PID for
- * it while it is a zombie. */
- if (waitid(P_ALL, 0, &si, WEXITED|WNOHANG|WNOWAIT) < 0) {
-
- if (errno == ECHILD)
- break;
-
- if (errno == EINTR)
- continue;
-
- return -errno;
- }
-
- if (si.si_pid <= 0)
- break;
-
- if (si.si_code == CLD_EXITED || si.si_code == CLD_KILLED || si.si_code == CLD_DUMPED) {
- _cleanup_free_ char *name = NULL;
- Unit *u1, *u2, *u3;
-
- get_process_comm(si.si_pid, &name);
-
- log_debug("Child "PID_FMT" (%s) died (code=%s, status=%i/%s)",
- si.si_pid, strna(name),
- sigchld_code_to_string(si.si_code),
- si.si_status,
- strna(si.si_code == CLD_EXITED
- ? exit_status_to_string(si.si_status, EXIT_STATUS_FULL)
- : signal_to_string(si.si_status)));
-
- /* And now figure out the unit this belongs
- * to, it might be multiple... */
- u1 = manager_get_unit_by_pid(m, si.si_pid);
- if (u1)
- invoke_sigchld_event(m, u1, &si);
- u2 = hashmap_get(m->watch_pids1, LONG_TO_PTR(si.si_pid));
- if (u2 && u2 != u1)
- invoke_sigchld_event(m, u2, &si);
- u3 = hashmap_get(m->watch_pids2, LONG_TO_PTR(si.si_pid));
- if (u3 && u3 != u2 && u3 != u1)
- invoke_sigchld_event(m, u3, &si);
- }
-
- /* And now, we actually reap the zombie. */
- if (waitid(P_PID, si.si_pid, &si, WEXITED) < 0) {
- if (errno == EINTR)
- continue;
-
- return -errno;
- }
- }
-
- return 0;
-}
-
-static int manager_start_target(Manager *m, const char *name, JobMode mode) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- int r;
-
- log_unit_debug(name, "Activating special unit %s", name);
-
- r = manager_add_job_by_name(m, JOB_START, name, mode, true, &error, NULL);
- if (r < 0)
- log_unit_error(name, "Failed to enqueue %s job: %s", name, bus_error_message(&error, r));
-
- return r;
-}
-
-static int manager_dispatch_signal_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
- Manager *m = userdata;
- ssize_t n;
- struct signalfd_siginfo sfsi;
- bool sigchld = false;
-
- assert(m);
- assert(m->signal_fd == fd);
-
- if (revents != EPOLLIN) {
- log_warning("Got unexpected events from signal file descriptor.");
- return 0;
- }
-
- for (;;) {
- n = read(m->signal_fd, &sfsi, sizeof(sfsi));
- if (n != sizeof(sfsi)) {
-
- if (n >= 0)
- return -EIO;
-
- if (errno == EINTR || errno == EAGAIN)
- break;
-
- return -errno;
- }
-
- log_received_signal(sfsi.ssi_signo == SIGCHLD ||
- (sfsi.ssi_signo == SIGTERM && m->running_as == SYSTEMD_USER)
- ? LOG_DEBUG : LOG_INFO,
- &sfsi);
-
- switch (sfsi.ssi_signo) {
-
- case SIGCHLD:
- sigchld = true;
- break;
-
- case SIGTERM:
- if (m->running_as == SYSTEMD_SYSTEM) {
- /* This is for compatibility with the
- * original sysvinit */
- m->exit_code = MANAGER_REEXECUTE;
- break;
- }
-
- /* Fall through */
-
- case SIGINT:
- if (m->running_as == SYSTEMD_SYSTEM) {
-
- /* If the user presses C-A-D more than
- * 7 times within 2s, we reboot
- * immediately. */
-
- if (ratelimit_test(&m->ctrl_alt_del_ratelimit))
- manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE_IRREVERSIBLY);
- else {
- log_notice("Ctrl-Alt-Del was pressed more than 7 times within 2s, rebooting immediately.");
- status_printf(NULL, true, false, "Ctrl-Alt-Del was pressed more than 7 times within 2s, rebooting immediately.");
- m->exit_code = MANAGER_REBOOT;
- }
-
- break;
- }
-
- /* Run the exit target if there is one, if not, just exit. */
- if (manager_start_target(m, SPECIAL_EXIT_TARGET, JOB_REPLACE) < 0) {
- m->exit_code = MANAGER_EXIT;
- return 0;
- }
-
- break;
-
- case SIGWINCH:
- if (m->running_as == SYSTEMD_SYSTEM)
- manager_start_target(m, SPECIAL_KBREQUEST_TARGET, JOB_REPLACE);
-
- /* This is a nop on non-init */
- break;
-
- case SIGPWR:
- if (m->running_as == SYSTEMD_SYSTEM)
- manager_start_target(m, SPECIAL_SIGPWR_TARGET, JOB_REPLACE);
-
- /* This is a nop on non-init */
- break;
-
- case SIGUSR1: {
- Unit *u;
-
- u = manager_get_unit(m, SPECIAL_DBUS_SERVICE);
-
- if (!u || UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) {
- log_info("Trying to reconnect to bus...");
- bus_init(m, true);
- }
-
- if (!u || !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u))) {
- log_info("Loading D-Bus service...");
- manager_start_target(m, SPECIAL_DBUS_SERVICE, JOB_REPLACE);
- }
-
- break;
- }
-
- case SIGUSR2: {
- _cleanup_free_ char *dump = NULL;
- _cleanup_fclose_ FILE *f = NULL;
- size_t size;
-
- f = open_memstream(&dump, &size);
- if (!f) {
- log_warning("Failed to allocate memory stream.");
- break;
- }
-
- manager_dump_units(m, f, "\t");
- manager_dump_jobs(m, f, "\t");
-
- if (ferror(f)) {
- log_warning("Failed to write status stream");
- break;
- }
-
- if (fflush(f)) {
- log_warning("Failed to flush status stream");
- break;
- }
-
- log_dump(LOG_INFO, dump);
- break;
- }
-
- case SIGHUP:
- m->exit_code = MANAGER_RELOAD;
- break;
-
- default: {
-
- /* Starting SIGRTMIN+0 */
- static const char * const target_table[] = {
- [0] = SPECIAL_DEFAULT_TARGET,
- [1] = SPECIAL_RESCUE_TARGET,
- [2] = SPECIAL_EMERGENCY_TARGET,
- [3] = SPECIAL_HALT_TARGET,
- [4] = SPECIAL_POWEROFF_TARGET,
- [5] = SPECIAL_REBOOT_TARGET,
- [6] = SPECIAL_KEXEC_TARGET
- };
-
- /* Starting SIGRTMIN+13, so that target halt and system halt are 10 apart */
- static const ManagerExitCode code_table[] = {
- [0] = MANAGER_HALT,
- [1] = MANAGER_POWEROFF,
- [2] = MANAGER_REBOOT,
- [3] = MANAGER_KEXEC
- };
-
- if ((int) sfsi.ssi_signo >= SIGRTMIN+0 &&
- (int) sfsi.ssi_signo < SIGRTMIN+(int) ELEMENTSOF(target_table)) {
- int idx = (int) sfsi.ssi_signo - SIGRTMIN;
- manager_start_target(m, target_table[idx],
- (idx == 1 || idx == 2) ? JOB_ISOLATE : JOB_REPLACE);
- break;
- }
-
- if ((int) sfsi.ssi_signo >= SIGRTMIN+13 &&
- (int) sfsi.ssi_signo < SIGRTMIN+13+(int) ELEMENTSOF(code_table)) {
- m->exit_code = code_table[sfsi.ssi_signo - SIGRTMIN - 13];
- break;
- }
-
- switch (sfsi.ssi_signo - SIGRTMIN) {
-
- case 20:
- log_debug("Enabling showing of status.");
- manager_set_show_status(m, SHOW_STATUS_YES);
- break;
-
- case 21:
- log_debug("Disabling showing of status.");
- manager_set_show_status(m, SHOW_STATUS_NO);
- break;
-
- case 22:
- log_set_max_level(LOG_DEBUG);
- log_notice("Setting log level to debug.");
- break;
-
- case 23:
- log_set_max_level(LOG_INFO);
- log_notice("Setting log level to info.");
- break;
-
- case 24:
- if (m->running_as == SYSTEMD_USER) {
- m->exit_code = MANAGER_EXIT;
- return 0;
- }
-
- /* This is a nop on init */
- break;
-
- 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.");
- break;
-
- case 27:
- log_set_target(LOG_TARGET_CONSOLE);
- log_notice("Setting log target to console.");
- break;
-
- case 28:
- log_set_target(LOG_TARGET_KMSG);
- log_notice("Setting log target to kmsg.");
- break;
-
- default:
- log_warning("Got unhandled signal <%s>.", signal_to_string(sfsi.ssi_signo));
- }
- }
- }
- }
-
- if (sigchld)
- manager_dispatch_sigchld(m);
-
- return 0;
-}
-
-static int manager_dispatch_time_change_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
- Manager *m = userdata;
- Iterator i;
- Unit *u;
-
- assert(m);
- assert(m->time_change_fd == fd);
-
- log_struct(LOG_INFO,
- LOG_MESSAGE_ID(SD_MESSAGE_TIME_CHANGE),
- LOG_MESSAGE("Time has been changed"),
- NULL);
-
- /* 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);
-
- HASHMAP_FOREACH(u, m->units, i)
- if (UNIT_VTABLE(u)->time_change)
- UNIT_VTABLE(u)->time_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;
-
- assert(m);
- assert(m->idle_pipe[2] == fd);
-
- m->no_console_output = m->n_on_console > 0;
-
- m->idle_pipe_event_source = sd_event_source_unref(m->idle_pipe_event_source);
- manager_close_idle_pipe(m);
-
- return 0;
-}
-
-static int manager_dispatch_jobs_in_progress(sd_event_source *source, usec_t usec, void *userdata) {
- Manager *m = userdata;
- int r;
- uint64_t next;
-
- assert(m);
- assert(source);
-
- manager_print_jobs_in_progress(m);
-
- next = now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_PERIOD_USEC;
- r = sd_event_source_set_time(source, next);
- if (r < 0)
- return r;
-
- return sd_event_source_set_enabled(source, SD_EVENT_ONESHOT);
-}
-
-int manager_loop(Manager *m) {
- int r;
-
- RATELIMIT_DEFINE(rl, 1*USEC_PER_SEC, 50000);
-
- assert(m);
- m->exit_code = MANAGER_OK;
-
- /* Release the path cache */
- set_free_free(m->unit_path_cache);
- m->unit_path_cache = NULL;
-
- manager_check_finished(m);
-
- /* There might still be some zombies hanging around from
- * before we were exec()'ed. Let's reap them. */
- r = manager_dispatch_sigchld(m);
- if (r < 0)
- return r;
-
- while (m->exit_code == MANAGER_OK) {
- usec_t wait_usec;
-
- if (m->runtime_watchdog > 0 && m->running_as == SYSTEMD_SYSTEM)
- watchdog_ping();
-
- if (!ratelimit_test(&rl)) {
- /* Yay, something is going seriously wrong, pause a little */
- log_warning("Looping too fast. Throttling execution a little.");
- sleep(1);
- continue;
- }
-
- if (manager_dispatch_load_queue(m) > 0)
- continue;
-
- if (manager_dispatch_gc_queue(m) > 0)
- continue;
-
- if (manager_dispatch_cleanup_queue(m) > 0)
- continue;
-
- if (manager_dispatch_cgroup_queue(m) > 0)
- continue;
-
- if (manager_dispatch_dbus_queue(m) > 0)
- continue;
-
- /* Sleep for half the watchdog time */
- if (m->runtime_watchdog > 0 && m->running_as == SYSTEMD_SYSTEM) {
- wait_usec = m->runtime_watchdog / 2;
- if (wait_usec <= 0)
- wait_usec = 1;
- } else
- wait_usec = USEC_INFINITY;
-
- r = sd_event_run(m->event, wait_usec);
- if (r < 0)
- return log_error_errno(r, "Failed to run event loop: %m");
- }
-
- return m->exit_code;
-}
-
-int manager_load_unit_from_dbus_path(Manager *m, const char *s, sd_bus_error *e, Unit **_u) {
- _cleanup_free_ char *n = NULL;
- Unit *u;
- int r;
-
- assert(m);
- assert(s);
- assert(_u);
-
- r = unit_name_from_dbus_path(s, &n);
- if (r < 0)
- return r;
-
- r = manager_load_unit(m, n, NULL, e, &u);
- if (r < 0)
- return r;
-
- *_u = u;
-
- return 0;
-}
-
-int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j) {
- const char *p;
- unsigned id;
- Job *j;
- int r;
-
- assert(m);
- assert(s);
- assert(_j);
-
- p = startswith(s, "/org/freedesktop/systemd1/job/");
- if (!p)
- return -EINVAL;
-
- r = safe_atou(p, &id);
- if (r < 0)
- return r;
-
- j = manager_get_job(m, id);
- if (!j)
- return -ENOENT;
-
- *_j = j;
-
- return 0;
-}
-
-void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
-
-#ifdef HAVE_AUDIT
- _cleanup_free_ char *p = NULL;
- const char *msg;
- int audit_fd;
-
- audit_fd = get_audit_fd();
- if (audit_fd < 0)
- return;
-
- /* Don't generate audit events if the service was already
- * started and we're just deserializing */
- if (m->n_reloading > 0)
- return;
-
- if (m->running_as != SYSTEMD_SYSTEM)
- return;
-
- if (u->type != UNIT_SERVICE)
- return;
-
- p = unit_name_to_prefix_and_instance(u->id);
- if (!p) {
- log_oom();
- return;
- }
-
- msg = strjoina("unit=", p);
- if (audit_log_user_comm_message(audit_fd, type, msg, "systemd", NULL, NULL, NULL, success) < 0) {
- if (errno == EPERM)
- /* We aren't allowed to send audit messages?
- * Then let's not retry again. */
- close_audit_fd();
- else
- log_warning_errno(errno, "Failed to send audit message: %m");
- }
-#endif
-
-}
-
-void manager_send_unit_plymouth(Manager *m, Unit *u) {
- union sockaddr_union sa = PLYMOUTH_SOCKET;
-
- int n = 0;
- _cleanup_free_ char *message = NULL;
- _cleanup_close_ int fd = -1;
-
- /* Don't generate plymouth events if the service was already
- * started and we're just deserializing */
- if (m->n_reloading > 0)
- return;
-
- if (m->running_as != SYSTEMD_SYSTEM)
- return;
-
- if (detect_container(NULL) > 0)
- return;
-
- if (u->type != UNIT_SERVICE &&
- u->type != UNIT_MOUNT &&
- u->type != UNIT_SWAP)
- return;
-
- /* We set SOCK_NONBLOCK here so that we rather drop the
- * message then wait for plymouth */
- fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
- if (fd < 0) {
- log_error_errno(errno, "socket() failed: %m");
- return;
- }
-
- if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) {
-
- if (!IN_SET(errno, EPIPE, EAGAIN, ENOENT, ECONNREFUSED, ECONNRESET, ECONNABORTED))
- log_error_errno(errno, "connect() failed: %m");
- return;
- }
-
- if (asprintf(&message, "U\002%c%s%n", (int) (strlen(u->id) + 1), u->id, &n) < 0) {
- log_oom();
- return;
- }
-
- errno = 0;
- if (write(fd, message, n + 1) != n + 1)
- if (!IN_SET(errno, EPIPE, EAGAIN, ENOENT, ECONNREFUSED, ECONNRESET, ECONNABORTED))
- log_error_errno(errno, "Failed to write Plymouth message: %m");
-}
-
-void manager_dispatch_bus_name_owner_changed(
- Manager *m,
- const char *name,
- const char* old_owner,
- const char *new_owner) {
-
- Unit *u;
-
- assert(m);
- assert(name);
-
- u = hashmap_get(m->watch_bus, name);
- if (!u)
- return;
-
- UNIT_VTABLE(u)->bus_name_owner_change(u, name, old_owner, new_owner);
-}
-
-int manager_open_serialization(Manager *m, FILE **_f) {
- const char *path;
- int fd = -1;
- FILE *f;
-
- assert(_f);
-
- path = m->running_as == SYSTEMD_SYSTEM ? "/run/systemd" : "/tmp";
- fd = open_tmpfile(path, O_RDWR|O_CLOEXEC);
- if (fd < 0)
- return -errno;
-
- log_debug("Serializing state to %s", path);
-
- f = fdopen(fd, "w+");
- if (!f) {
- safe_close(fd);
- return -errno;
- }
-
- *_f = f;
-
- return 0;
-}
-
-int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root) {
- Iterator i;
- Unit *u;
- const char *t;
- char **e;
- int r;
-
- assert(m);
- assert(f);
- assert(fds);
-
- m->n_reloading ++;
-
- fprintf(f, "current-job-id=%"PRIu32"\n", m->current_job_id);
- fprintf(f, "taint-usr=%s\n", yes_no(m->taint_usr));
- fprintf(f, "n-installed-jobs=%u\n", m->n_installed_jobs);
- fprintf(f, "n-failed-jobs=%u\n", m->n_failed_jobs);
-
- dual_timestamp_serialize(f, "firmware-timestamp", &m->firmware_timestamp);
- dual_timestamp_serialize(f, "loader-timestamp", &m->loader_timestamp);
- dual_timestamp_serialize(f, "kernel-timestamp", &m->kernel_timestamp);
- dual_timestamp_serialize(f, "initrd-timestamp", &m->initrd_timestamp);
-
- if (!in_initrd()) {
- dual_timestamp_serialize(f, "userspace-timestamp", &m->userspace_timestamp);
- dual_timestamp_serialize(f, "finish-timestamp", &m->finish_timestamp);
- dual_timestamp_serialize(f, "security-start-timestamp", &m->security_start_timestamp);
- dual_timestamp_serialize(f, "security-finish-timestamp", &m->security_finish_timestamp);
- dual_timestamp_serialize(f, "generators-start-timestamp", &m->generators_start_timestamp);
- dual_timestamp_serialize(f, "generators-finish-timestamp", &m->generators_finish_timestamp);
- dual_timestamp_serialize(f, "units-load-start-timestamp", &m->units_load_start_timestamp);
- dual_timestamp_serialize(f, "units-load-finish-timestamp", &m->units_load_finish_timestamp);
- }
-
- if (!switching_root) {
- STRV_FOREACH(e, m->environment) {
- _cleanup_free_ char *ce;
-
- ce = cescape(*e);
- if (!ce)
- return -ENOMEM;
-
- fprintf(f, "env=%s\n", *e);
- }
- }
-
- if (m->notify_fd >= 0) {
- int copy;
-
- copy = fdset_put_dup(fds, m->notify_fd);
- if (copy < 0)
- return copy;
-
- fprintf(f, "notify-fd=%i\n", copy);
- fprintf(f, "notify-socket=%s\n", m->notify_socket);
- }
-
- if (m->kdbus_fd >= 0) {
- int copy;
-
- copy = fdset_put_dup(fds, m->kdbus_fd);
- if (copy < 0)
- return copy;
-
- fprintf(f, "kdbus-fd=%i\n", copy);
- }
-
- bus_track_serialize(m->subscribed, f);
-
- fputc('\n', f);
-
- HASHMAP_FOREACH_KEY(u, t, m->units, i) {
- if (u->id != t)
- continue;
-
- /* Start marker */
- fputs(u->id, f);
- fputc('\n', f);
-
- r = unit_serialize(u, f, fds, !switching_root);
- if (r < 0) {
- m->n_reloading --;
- return r;
- }
- }
-
- assert(m->n_reloading > 0);
- m->n_reloading --;
-
- if (ferror(f))
- return -EIO;
-
- r = bus_fdset_add_all(m, fds);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-int manager_deserialize(Manager *m, FILE *f, FDSet *fds) {
- int r = 0;
-
- assert(m);
- assert(f);
-
- log_debug("Deserializing state...");
-
- m->n_reloading ++;
-
- for (;;) {
- char line[LINE_MAX], *l;
-
- if (!fgets(line, sizeof(line), f)) {
- if (feof(f))
- r = 0;
- else
- r = -errno;
-
- goto finish;
- }
-
- char_array_0(line);
- l = strstrip(line);
-
- if (l[0] == 0)
- break;
-
- if (startswith(l, "current-job-id=")) {
- uint32_t id;
-
- if (safe_atou32(l+15, &id) < 0)
- log_debug("Failed to parse current job id value %s", l+15);
- else
- m->current_job_id = MAX(m->current_job_id, id);
-
- } else if (startswith(l, "n-installed-jobs=")) {
- uint32_t n;
-
- if (safe_atou32(l+17, &n) < 0)
- log_debug("Failed to parse installed jobs counter %s", l+17);
- else
- m->n_installed_jobs += n;
-
- } else if (startswith(l, "n-failed-jobs=")) {
- uint32_t n;
-
- if (safe_atou32(l+14, &n) < 0)
- log_debug("Failed to parse failed jobs counter %s", l+14);
- else
- m->n_failed_jobs += n;
-
- } else if (startswith(l, "taint-usr=")) {
- int b;
-
- b = parse_boolean(l+10);
- if (b < 0)
- log_debug("Failed to parse taint /usr flag %s", l+10);
- else
- m->taint_usr = m->taint_usr || b;
-
- } else if (startswith(l, "firmware-timestamp="))
- dual_timestamp_deserialize(l+19, &m->firmware_timestamp);
- else if (startswith(l, "loader-timestamp="))
- dual_timestamp_deserialize(l+17, &m->loader_timestamp);
- else if (startswith(l, "kernel-timestamp="))
- dual_timestamp_deserialize(l+17, &m->kernel_timestamp);
- else if (startswith(l, "initrd-timestamp="))
- dual_timestamp_deserialize(l+17, &m->initrd_timestamp);
- else if (startswith(l, "userspace-timestamp="))
- dual_timestamp_deserialize(l+20, &m->userspace_timestamp);
- else if (startswith(l, "finish-timestamp="))
- dual_timestamp_deserialize(l+17, &m->finish_timestamp);
- else if (startswith(l, "security-start-timestamp="))
- dual_timestamp_deserialize(l+25, &m->security_start_timestamp);
- else if (startswith(l, "security-finish-timestamp="))
- dual_timestamp_deserialize(l+26, &m->security_finish_timestamp);
- else if (startswith(l, "generators-start-timestamp="))
- dual_timestamp_deserialize(l+27, &m->generators_start_timestamp);
- else if (startswith(l, "generators-finish-timestamp="))
- dual_timestamp_deserialize(l+28, &m->generators_finish_timestamp);
- else if (startswith(l, "units-load-start-timestamp="))
- dual_timestamp_deserialize(l+27, &m->units_load_start_timestamp);
- else if (startswith(l, "units-load-finish-timestamp="))
- dual_timestamp_deserialize(l+28, &m->units_load_finish_timestamp);
- else if (startswith(l, "env=")) {
- _cleanup_free_ char *uce = NULL;
- char **e;
-
- uce = cunescape(l+4);
- if (!uce) {
- r = -ENOMEM;
- goto finish;
- }
-
- e = strv_env_set(m->environment, uce);
- if (!e) {
- r = -ENOMEM;
- goto finish;
- }
-
- strv_free(m->environment);
- m->environment = e;
-
- } else if (startswith(l, "notify-fd=")) {
- int fd;
-
- if (safe_atoi(l + 10, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_debug("Failed to parse notify fd: %s", l + 10);
- else {
- m->notify_event_source = sd_event_source_unref(m->notify_event_source);
- safe_close(m->notify_fd);
- m->notify_fd = fdset_remove(fds, fd);
- }
-
- } else if (startswith(l, "notify-socket=")) {
- char *n;
-
- n = strdup(l+14);
- if (!n) {
- r = -ENOMEM;
- goto finish;
- }
-
- free(m->notify_socket);
- m->notify_socket = n;
-
- } else if (startswith(l, "kdbus-fd=")) {
- int fd;
-
- if (safe_atoi(l + 9, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_debug("Failed to parse kdbus fd: %s", l + 9);
- else {
- safe_close(m->kdbus_fd);
- m->kdbus_fd = fdset_remove(fds, fd);
- }
-
- } else {
- int k;
-
- k = bus_track_deserialize_item(&m->deserialized_subscribed, l);
- if (k < 0)
- log_debug_errno(k, "Failed to deserialize bus tracker object: %m");
- else if (k == 0)
- log_debug("Unknown serialization item '%s'", l);
- }
- }
-
- for (;;) {
- Unit *u;
- char name[UNIT_NAME_MAX+2];
-
- /* Start marker */
- if (!fgets(name, sizeof(name), f)) {
- if (feof(f))
- r = 0;
- else
- r = -errno;
-
- goto finish;
- }
-
- char_array_0(name);
-
- r = manager_load_unit(m, strstrip(name), NULL, NULL, &u);
- if (r < 0)
- goto finish;
-
- r = unit_deserialize(u, f, fds);
- if (r < 0)
- goto finish;
- }
-
-finish:
- if (ferror(f))
- r = -EIO;
-
- assert(m->n_reloading > 0);
- m->n_reloading --;
-
- return r;
-}
-
-int manager_reload(Manager *m) {
- int r, q;
- _cleanup_fclose_ FILE *f = NULL;
- _cleanup_fdset_free_ FDSet *fds = NULL;
-
- assert(m);
-
- r = manager_open_serialization(m, &f);
- if (r < 0)
- return r;
-
- m->n_reloading ++;
- bus_manager_send_reloading(m, true);
-
- fds = fdset_new();
- if (!fds) {
- m->n_reloading --;
- return -ENOMEM;
- }
-
- r = manager_serialize(m, f, fds, false);
- if (r < 0) {
- m->n_reloading --;
- return r;
- }
-
- if (fseeko(f, 0, SEEK_SET) < 0) {
- m->n_reloading --;
- return -errno;
- }
-
- /* From here on there is no way back. */
- manager_clear_jobs_and_units(m);
- manager_undo_generators(m);
- lookup_paths_free(&m->lookup_paths);
-
- /* Find new unit paths */
- q = manager_run_generators(m);
- if (q < 0 && r >= 0)
- r = q;
-
- q = lookup_paths_init(
- &m->lookup_paths, m->running_as, true,
- NULL,
- m->generator_unit_path,
- m->generator_unit_path_early,
- m->generator_unit_path_late);
- if (q < 0 && r >= 0)
- r = q;
-
- manager_build_unit_path_cache(m);
-
- /* First, enumerate what we can from all config files */
- q = manager_enumerate(m);
- if (q < 0 && r >= 0)
- r = q;
-
- /* Second, deserialize our stored data */
- q = manager_deserialize(m, f, fds);
- if (q < 0 && r >= 0)
- r = q;
-
- fclose(f);
- f = NULL;
-
- /* Re-register notify_fd as event source */
- q = manager_setup_notify(m);
- if (q < 0 && r >= 0)
- r = q;
-
- /* Third, fire things up! */
- q = manager_coldplug(m);
- if (q < 0 && r >= 0)
- r = q;
-
- assert(m->n_reloading > 0);
- m->n_reloading--;
-
- m->send_reloading_done = true;
-
- return r;
-}
-
-bool manager_is_reloading_or_reexecuting(Manager *m) {
- assert(m);
-
- return m->n_reloading != 0;
-}
-
-void manager_reset_failed(Manager *m) {
- Unit *u;
- Iterator i;
-
- assert(m);
-
- HASHMAP_FOREACH(u, m->units, i)
- unit_reset_failed(u);
-}
-
-bool manager_unit_inactive_or_pending(Manager *m, const char *name) {
- Unit *u;
-
- assert(m);
- assert(name);
-
- /* Returns true if the unit is inactive or going down */
- u = manager_get_unit(m, name);
- if (!u)
- return true;
-
- return unit_inactive_or_pending(u);
-}
-
-static void manager_notify_finished(Manager *m) {
- char userspace[FORMAT_TIMESPAN_MAX], initrd[FORMAT_TIMESPAN_MAX], kernel[FORMAT_TIMESPAN_MAX], sum[FORMAT_TIMESPAN_MAX];
- usec_t firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec;
-
- if (m->test_run)
- return;
-
- if (m->running_as == SYSTEMD_SYSTEM && detect_container(NULL) <= 0) {
-
- /* Note that m->kernel_usec.monotonic is always at 0,
- * and m->firmware_usec.monotonic and
- * m->loader_usec.monotonic should be considered
- * negative values. */
-
- firmware_usec = m->firmware_timestamp.monotonic - m->loader_timestamp.monotonic;
- loader_usec = m->loader_timestamp.monotonic - m->kernel_timestamp.monotonic;
- userspace_usec = m->finish_timestamp.monotonic - m->userspace_timestamp.monotonic;
- total_usec = m->firmware_timestamp.monotonic + m->finish_timestamp.monotonic;
-
- if (dual_timestamp_is_set(&m->initrd_timestamp)) {
-
- kernel_usec = m->initrd_timestamp.monotonic - m->kernel_timestamp.monotonic;
- initrd_usec = m->userspace_timestamp.monotonic - m->initrd_timestamp.monotonic;
-
- log_struct(LOG_INFO,
- LOG_MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
- "KERNEL_USEC="USEC_FMT, kernel_usec,
- "INITRD_USEC="USEC_FMT, initrd_usec,
- "USERSPACE_USEC="USEC_FMT, userspace_usec,
- LOG_MESSAGE("Startup finished in %s (kernel) + %s (initrd) + %s (userspace) = %s.",
- 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);
- } else {
- kernel_usec = m->userspace_timestamp.monotonic - m->kernel_timestamp.monotonic;
- initrd_usec = 0;
-
- log_struct(LOG_INFO,
- LOG_MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
- "KERNEL_USEC="USEC_FMT, kernel_usec,
- "USERSPACE_USEC="USEC_FMT, userspace_usec,
- LOG_MESSAGE("Startup finished in %s (kernel) + %s (userspace) = %s.",
- 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);
- }
- } else {
- firmware_usec = loader_usec = initrd_usec = kernel_usec = 0;
- total_usec = userspace_usec = m->finish_timestamp.monotonic - m->userspace_timestamp.monotonic;
-
- log_struct(LOG_INFO,
- LOG_MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
- "USERSPACE_USEC="USEC_FMT, userspace_usec,
- LOG_MESSAGE("Startup finished in %s.",
- format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC)),
- NULL);
- }
-
- bus_manager_send_finished(m, firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec);
-
- sd_notifyf(false,
- "READY=1\n"
- "STATUS=Startup finished in %s.",
- format_timespan(sum, sizeof(sum), total_usec, USEC_PER_MSEC));
-}
-
-void manager_check_finished(Manager *m) {
- Unit *u = NULL;
- Iterator i;
-
- assert(m);
-
- if (hashmap_size(m->jobs) > 0) {
-
- if (m->jobs_in_progress_event_source)
- /* Ignore any failure, this is only for feedback */
- (void) sd_event_source_set_time(m->jobs_in_progress_event_source,
- now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC);
-
- return;
- }
-
- manager_flip_auto_status(m, false);
-
- /* Notify Type=idle units that we are done now */
- m->idle_pipe_event_source = sd_event_source_unref(m->idle_pipe_event_source);
- manager_close_idle_pipe(m);
-
- /* Turn off confirm spawn now */
- m->confirm_spawn = false;
-
- /* No need to update ask password status when we're going non-interactive */
- manager_close_ask_password(m);
-
- /* This is no longer the first boot */
- manager_set_first_boot(m, false);
-
- if (dual_timestamp_is_set(&m->finish_timestamp))
- return;
-
- dual_timestamp_get(&m->finish_timestamp);
-
- manager_notify_finished(m);
-
- SET_FOREACH(u, m->startup_units, i)
- if (u->cgroup_path)
- cgroup_context_apply(unit_get_cgroup_context(u), unit_get_cgroup_mask(u), u->cgroup_path, manager_state(m));
-}
-
-static int create_generator_dir(Manager *m, char **generator, const char *name) {
- char *p;
- int r;
-
- assert(m);
- assert(generator);
- assert(name);
-
- if (*generator)
- return 0;
-
- if (m->running_as == SYSTEMD_SYSTEM && getpid() == 1) {
- /* systemd --system, not running --test */
-
- p = strappend("/run/systemd/", name);
- if (!p)
- return log_oom();
-
- r = mkdir_p_label(p, 0755);
- if (r < 0) {
- log_error_errno(r, "Failed to create generator directory %s: %m", p);
- free(p);
- return r;
- }
- } else if (m->running_as == SYSTEMD_USER) {
- const char *s = NULL;
-
- s = getenv("XDG_RUNTIME_DIR");
- if (!s)
- return -EINVAL;
- p = strjoin(s, "/systemd/", name, NULL);
- if (!p)
- return log_oom();
-
- r = mkdir_p_label(p, 0755);
- if (r < 0) {
- log_error_errno(r, "Failed to create generator directory %s: %m", p);
- free(p);
- return r;
- }
- } else {
- /* systemd --system --test */
-
- p = strjoin("/tmp/systemd-", name, ".XXXXXX", NULL);
- if (!p)
- return log_oom();
-
- if (!mkdtemp(p)) {
- log_error_errno(errno, "Failed to create generator directory %s: %m",
- p);
- free(p);
- return -errno;
- }
- }
-
- *generator = p;
- return 0;
-}
-
-static void trim_generator_dir(Manager *m, char **generator) {
- assert(m);
- assert(generator);
-
- if (!*generator)
- return;
-
- if (rmdir(*generator) >= 0) {
- free(*generator);
- *generator = NULL;
- }
-
- return;
-}
-
-static int manager_run_generators(Manager *m) {
- _cleanup_free_ char **paths = NULL;
- const char *argv[5];
- char **path;
- int r;
-
- assert(m);
-
- if (m->test_run)
- return 0;
-
- paths = generator_paths(m->running_as);
- if (!paths)
- return log_oom();
-
- /* Optimize by skipping the whole process by not creating output directories
- * if no generators are found. */
- STRV_FOREACH(path, paths) {
- r = access(*path, F_OK);
- if (r == 0)
- goto found;
- if (errno != ENOENT)
- log_warning_errno(errno, "Failed to open generator directory %s: %m", *path);
- }
- return 0;
-
- found:
- r = create_generator_dir(m, &m->generator_unit_path, "generator");
- if (r < 0)
- goto finish;
-
- r = create_generator_dir(m, &m->generator_unit_path_early, "generator.early");
- if (r < 0)
- goto finish;
-
- r = create_generator_dir(m, &m->generator_unit_path_late, "generator.late");
- if (r < 0)
- goto finish;
-
- argv[0] = NULL; /* Leave this empty, execute_directory() will fill something in */
- argv[1] = m->generator_unit_path;
- argv[2] = m->generator_unit_path_early;
- argv[3] = m->generator_unit_path_late;
- argv[4] = NULL;
-
- RUN_WITH_UMASK(0022)
- execute_directories((const char* const*) paths, DEFAULT_TIMEOUT_USEC, (char**) argv);
-
-finish:
- trim_generator_dir(m, &m->generator_unit_path);
- trim_generator_dir(m, &m->generator_unit_path_early);
- trim_generator_dir(m, &m->generator_unit_path_late);
- return r;
-}
-
-static void remove_generator_dir(Manager *m, char **generator) {
- assert(m);
- assert(generator);
-
- if (!*generator)
- return;
-
- strv_remove(m->lookup_paths.unit_path, *generator);
- rm_rf(*generator, false, true, false);
-
- free(*generator);
- *generator = NULL;
-}
-
-static void manager_undo_generators(Manager *m) {
- assert(m);
-
- remove_generator_dir(m, &m->generator_unit_path);
- remove_generator_dir(m, &m->generator_unit_path_early);
- remove_generator_dir(m, &m->generator_unit_path_late);
-}
-
-int manager_environment_add(Manager *m, char **minus, char **plus) {
- char **a = NULL, **b = NULL, **l;
- assert(m);
-
- l = m->environment;
-
- if (!strv_isempty(minus)) {
- a = strv_env_delete(l, 1, minus);
- if (!a)
- return -ENOMEM;
-
- l = a;
- }
-
- if (!strv_isempty(plus)) {
- b = strv_env_merge(2, l, plus);
- if (!b) {
- strv_free(a);
- return -ENOMEM;
- }
-
- l = b;
- }
-
- if (m->environment != l)
- strv_free(m->environment);
- if (a != l)
- strv_free(a);
- if (b != l)
- strv_free(b);
-
- m->environment = l;
- manager_clean_environment(m);
- strv_sort(m->environment);
-
- return 0;
-}
-
-int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit) {
- int i;
-
- assert(m);
-
- for (i = 0; i < _RLIMIT_MAX; i++) {
- if (!default_rlimit[i])
- continue;
-
- m->rlimit[i] = newdup(struct rlimit, default_rlimit[i], 1);
- if (!m->rlimit[i])
- return -ENOMEM;
- }
-
- return 0;
-}
-
-void manager_recheck_journal(Manager *m) {
- Unit *u;
-
- assert(m);
-
- if (m->running_as != SYSTEMD_SYSTEM)
- return;
-
- u = manager_get_unit(m, SPECIAL_JOURNALD_SOCKET);
- if (u && SOCKET(u)->state != SOCKET_RUNNING) {
- log_close_journal();
- return;
- }
-
- u = manager_get_unit(m, SPECIAL_JOURNALD_SERVICE);
- if (u && SERVICE(u)->state != SERVICE_RUNNING) {
- log_close_journal();
- return;
- }
-
- /* Hmm, OK, so the socket is fully up and the service is up
- * too, then let's make use of the thing. */
- log_open();
-}
-
-void manager_set_show_status(Manager *m, ShowStatus mode) {
- assert(m);
- assert(IN_SET(mode, SHOW_STATUS_AUTO, SHOW_STATUS_NO, SHOW_STATUS_YES, SHOW_STATUS_TEMPORARY));
-
- if (m->running_as != SYSTEMD_SYSTEM)
- return;
-
- m->show_status = mode;
-
- if (mode > 0)
- touch("/run/systemd/show-status");
- else
- unlink("/run/systemd/show-status");
-}
-
-static bool manager_get_show_status(Manager *m, StatusType type) {
- assert(m);
-
- if (m->running_as != SYSTEMD_SYSTEM)
- return false;
-
- if (m->no_console_output)
- return false;
-
- if (!IN_SET(manager_state(m), MANAGER_INITIALIZING, MANAGER_STARTING, MANAGER_STOPPING))
- return false;
-
- /* If we cannot find out the status properly, just proceed. */
- if (type != STATUS_TYPE_EMERGENCY && manager_check_ask_password(m) > 0)
- return false;
-
- if (m->show_status > 0)
- return true;
-
- return false;
-}
-
-void manager_set_first_boot(Manager *m, bool b) {
- assert(m);
-
- if (m->running_as != SYSTEMD_SYSTEM)
- return;
-
- m->first_boot = b;
-
- if (m->first_boot)
- touch("/run/systemd/first-boot");
- else
- unlink("/run/systemd/first-boot");
-}
-
-void manager_status_printf(Manager *m, StatusType type, const char *status, const char *format, ...) {
- va_list ap;
-
- /* If m is NULL, assume we're after shutdown and let the messages through. */
-
- if (m && !manager_get_show_status(m, type))
- return;
-
- /* XXX We should totally drop the check for ephemeral here
- * and thus effectively make 'Type=idle' pointless. */
- if (type == STATUS_TYPE_EPHEMERAL && m && m->n_on_console > 0)
- return;
-
- va_start(ap, format);
- status_vprintf(status, true, type == STATUS_TYPE_EPHEMERAL, format, ap);
- va_end(ap);
-}
-
-int manager_get_unit_by_path(Manager *m, const char *path, const char *suffix, Unit **_found) {
- _cleanup_free_ char *p = NULL;
- Unit *found;
-
- assert(m);
- assert(path);
- assert(suffix);
- assert(_found);
-
- p = unit_name_from_path(path, suffix);
- if (!p)
- return -ENOMEM;
-
- found = manager_get_unit(m, p);
- if (!found) {
- *_found = NULL;
- return 0;
- }
-
- *_found = found;
- return 1;
-}
-
-Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path) {
- char p[strlen(path)+1];
-
- assert(m);
- assert(path);
-
- strcpy(p, path);
- path_kill_slashes(p);
-
- return hashmap_get(m->units_requiring_mounts_for, streq(p, "/") ? "" : p);
-}
-
-const char *manager_get_runtime_prefix(Manager *m) {
- assert(m);
-
- return m->running_as == SYSTEMD_SYSTEM ?
- "/run" :
- getenv("XDG_RUNTIME_DIR");
-}
-
-void manager_update_failed_units(Manager *m, Unit *u, bool failed) {
- unsigned size;
-
- assert(m);
- assert(u->manager == m);
-
- size = set_size(m->failed_units);
-
- if (failed) {
- if (set_put(m->failed_units, u) < 0)
- log_oom();
- } else
- set_remove(m->failed_units, u);
-
- if (set_size(m->failed_units) != size)
- bus_manager_send_change_signal(m);
-}
-
-ManagerState manager_state(Manager *m) {
- Unit *u;
-
- assert(m);
-
- /* Did we ever finish booting? If not then we are still starting up */
- if (!dual_timestamp_is_set(&m->finish_timestamp)) {
-
- u = manager_get_unit(m, SPECIAL_BASIC_TARGET);
- if (!u || !UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u)))
- return MANAGER_INITIALIZING;
-
- return MANAGER_STARTING;
- }
-
- /* Is the special shutdown target queued? If so, we are in shutdown state */
- u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET);
- if (u && u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_TRY_RESTART, JOB_RELOAD_OR_START))
- return MANAGER_STOPPING;
-
- /* Are the rescue or emergency targets active or queued? If so we are in maintenance state */
- u = manager_get_unit(m, SPECIAL_RESCUE_TARGET);
- if (u && (UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)) ||
- (u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_TRY_RESTART, JOB_RELOAD_OR_START))))
- return MANAGER_MAINTENANCE;
-
- u = manager_get_unit(m, SPECIAL_EMERGENCY_TARGET);
- if (u && (UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)) ||
- (u->job && IN_SET(u->job->type, JOB_START, JOB_RESTART, JOB_TRY_RESTART, JOB_RELOAD_OR_START))))
- return MANAGER_MAINTENANCE;
-
- /* Are there any failed units? If so, we are in degraded mode */
- if (set_size(m->failed_units) > 0)
- return MANAGER_DEGRADED;
-
- return MANAGER_RUNNING;
-}
-
-static const char *const manager_state_table[_MANAGER_STATE_MAX] = {
- [MANAGER_INITIALIZING] = "initializing",
- [MANAGER_STARTING] = "starting",
- [MANAGER_RUNNING] = "running",
- [MANAGER_DEGRADED] = "degraded",
- [MANAGER_MAINTENANCE] = "maintenance",
- [MANAGER_STOPPING] = "stopping",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(manager_state, ManagerState);
diff --git a/src/core/manager.h b/src/core/manager.h
deleted file mode 100644
index a1caab4d4..000000000
--- a/src/core/manager.h
+++ /dev/null
@@ -1,368 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 <stdio.h>
-
-#include "sd-bus.h"
-#include "sd-event.h"
-#include "fdset.h"
-#include "cgroup-util.h"
-#include "hashmap.h"
-#include "list.h"
-#include "ratelimit.h"
-
-/* Enforce upper limit how many names we allow */
-#define MANAGER_MAX_NAMES 131072 /* 128K */
-
-typedef struct Manager Manager;
-
-typedef enum ManagerState {
- MANAGER_INITIALIZING,
- MANAGER_STARTING,
- MANAGER_RUNNING,
- MANAGER_DEGRADED,
- MANAGER_MAINTENANCE,
- MANAGER_STOPPING,
- _MANAGER_STATE_MAX,
- _MANAGER_STATE_INVALID = -1
-} ManagerState;
-
-typedef enum ManagerExitCode {
- MANAGER_OK,
- MANAGER_EXIT,
- MANAGER_RELOAD,
- MANAGER_REEXECUTE,
- MANAGER_REBOOT,
- MANAGER_POWEROFF,
- MANAGER_HALT,
- MANAGER_KEXEC,
- MANAGER_SWITCH_ROOT,
- _MANAGER_EXIT_CODE_MAX,
- _MANAGER_EXIT_CODE_INVALID = -1
-} ManagerExitCode;
-
-typedef enum StatusType {
- STATUS_TYPE_EPHEMERAL,
- STATUS_TYPE_NORMAL,
- STATUS_TYPE_EMERGENCY,
-} StatusType;
-
-#include "job.h"
-#include "path-lookup.h"
-#include "execute.h"
-#include "unit-name.h"
-#include "show-status.h"
-
-struct Manager {
- /* Note that the set of units we know of is allowed to be
- * inconsistent. However the subset of it that is loaded may
- * not, and the list of jobs may neither. */
-
- /* Active jobs and units */
- Hashmap *units; /* name string => Unit object n:1 */
- Hashmap *jobs; /* job id => Job object 1:1 */
-
- /* To make it easy to iterate through the units of a specific
- * type we maintain a per type linked list */
- LIST_HEAD(Unit, units_by_type[_UNIT_TYPE_MAX]);
-
- /* Units that need to be loaded */
- LIST_HEAD(Unit, load_queue); /* this is actually more a stack than a queue, but uh. */
-
- /* Jobs that need to be run */
- LIST_HEAD(Job, run_queue); /* more a stack than a queue, too */
-
- /* Units and jobs that have not yet been announced via
- * D-Bus. When something about a job changes it is added here
- * if it is not in there yet. This allows easy coalescing of
- * D-Bus change signals. */
- LIST_HEAD(Unit, dbus_unit_queue);
- LIST_HEAD(Job, dbus_job_queue);
-
- /* Units to remove */
- LIST_HEAD(Unit, cleanup_queue);
-
- /* Units to check when doing GC */
- LIST_HEAD(Unit, gc_queue);
-
- /* Units that should be realized */
- LIST_HEAD(Unit, cgroup_queue);
-
- sd_event *event;
-
- /* We use two hash tables here, since the same PID might be
- * watched by two different units: once the unit that forked
- * it off, and possibly a different unit to which it was
- * joined as cgroup member. Since we know that it is either
- * one or two units for each PID we just use to hashmaps
- * here. */
- Hashmap *watch_pids1; /* pid => Unit object n:1 */
- Hashmap *watch_pids2; /* pid => Unit object n:1 */
-
- /* A set contains all units which cgroup should be refreshed after startup */
- Set *startup_units;
-
- /* A set which contains all currently failed units */
- Set *failed_units;
-
- sd_event_source *run_queue_event_source;
-
- char *notify_socket;
- int notify_fd;
- sd_event_source *notify_event_source;
-
- int signal_fd;
- sd_event_source *signal_event_source;
-
- int time_change_fd;
- sd_event_source *time_change_event_source;
-
- sd_event_source *jobs_in_progress_event_source;
-
- unsigned n_snapshots;
-
- LookupPaths lookup_paths;
- Set *unit_path_cache;
-
- char **environment;
-
- usec_t runtime_watchdog;
- usec_t shutdown_watchdog;
-
- dual_timestamp firmware_timestamp;
- dual_timestamp loader_timestamp;
- dual_timestamp kernel_timestamp;
- dual_timestamp initrd_timestamp;
- dual_timestamp userspace_timestamp;
- dual_timestamp finish_timestamp;
-
- dual_timestamp security_start_timestamp;
- dual_timestamp security_finish_timestamp;
- dual_timestamp generators_start_timestamp;
- dual_timestamp generators_finish_timestamp;
- dual_timestamp units_load_start_timestamp;
- dual_timestamp units_load_finish_timestamp;
-
- char *generator_unit_path;
- char *generator_unit_path_early;
- char *generator_unit_path_late;
-
- struct udev* udev;
-
- /* Data specific to the device subsystem */
- struct udev_monitor* udev_monitor;
- sd_event_source *udev_event_source;
- Hashmap *devices_by_sysfs;
-
- /* Data specific to the mount subsystem */
- FILE *proc_self_mountinfo;
- sd_event_source *mount_event_source;
- int utab_inotify_fd;
- sd_event_source *mount_utab_event_source;
-
- /* Data specific to the swap filesystem */
- FILE *proc_swaps;
- sd_event_source *swap_event_source;
- Hashmap *swaps_by_devnode;
-
- /* Data specific to the D-Bus subsystem */
- sd_bus *api_bus, *system_bus;
- Set *private_buses;
- int private_listen_fd;
- sd_event_source *private_listen_event_source;
-
- /* Contains all the clients that are subscribed to signals via
- the API bus. Note that private bus connections are always
- considered subscribes, since they last for very short only,
- and it is much simpler that way. */
- sd_bus_track *subscribed;
- char **deserialized_subscribed;
-
- sd_bus_message *queued_message; /* This is used during reloading:
- * before the reload we queue the
- * reply message here, and
- * afterwards we send it */
- sd_bus *queued_message_bus; /* The connection to send the queued message on */
-
- Hashmap *watch_bus; /* D-Bus names => Unit object n:1 */
-
- bool send_reloading_done;
-
- uint32_t current_job_id;
- uint32_t default_unit_job_id;
-
- /* Data specific to the Automount subsystem */
- int dev_autofs_fd;
-
- /* Data specific to the cgroup subsystem */
- Hashmap *cgroup_unit;
- CGroupControllerMask cgroup_supported;
- char *cgroup_root;
-
- int gc_marker;
- unsigned n_in_gc_queue;
-
- /* Make sure the user cannot accidentally unmount our cgroup
- * file system */
- int pin_cgroupfs_fd;
-
- /* Flags */
- SystemdRunningAs running_as;
- ManagerExitCode exit_code:5;
-
- bool dispatching_load_queue:1;
- bool dispatching_dbus_queue:1;
-
- bool taint_usr:1;
- bool first_boot:1;
-
- bool test_run:1;
-
- ShowStatus show_status;
- bool confirm_spawn;
- bool no_console_output;
-
- ExecOutput default_std_output, default_std_error;
-
- usec_t default_restart_usec, default_timeout_start_usec, default_timeout_stop_usec;
-
- usec_t default_start_limit_interval;
- unsigned default_start_limit_burst;
-
- bool default_cpu_accounting;
- bool default_memory_accounting;
- bool default_blockio_accounting;
-
- usec_t default_timer_accuracy_usec;
-
- struct rlimit *rlimit[_RLIMIT_MAX];
-
- /* non-zero if we are reloading or reexecuting, */
- int n_reloading;
-
- unsigned n_installed_jobs;
- unsigned n_failed_jobs;
-
- /* Jobs in progress watching */
- unsigned n_running_jobs;
- unsigned n_on_console;
- unsigned jobs_in_progress_iteration;
-
- /* Do we have any outstanding password prompts? */
- int have_ask_password;
- int ask_password_inotify_fd;
- sd_event_source *ask_password_event_source;
-
- /* Type=idle pipes */
- int idle_pipe[4];
- sd_event_source *idle_pipe_event_source;
-
- char *switch_root;
- char *switch_root_init;
-
- /* This maps all possible path prefixes to the units needing
- * them. It's a hashmap with a path string as key and a Set as
- * value where Unit objects are contained. */
- Hashmap *units_requiring_mounts_for;
-
- /* Reference to the kdbus bus control fd */
- int kdbus_fd;
-
- /* Used for processing polkit authorization responses */
- Hashmap *polkit_registry;
-
- /* When the user hits C-A-D more than 7 times per 2s, reboot immediately... */
- RateLimit ctrl_alt_del_ratelimit;
-};
-
-int manager_new(SystemdRunningAs running_as, bool test_run, Manager **m);
-Manager* manager_free(Manager *m);
-
-int manager_enumerate(Manager *m);
-int manager_startup(Manager *m, FILE *serialization, FDSet *fds);
-
-Job *manager_get_job(Manager *m, uint32_t id);
-Unit *manager_get_unit(Manager *m, const char *name);
-
-int manager_get_unit_by_path(Manager *m, const char *path, const char *suffix, Unit **_found);
-
-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_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, bool force, sd_bus_error *e, Job **_ret);
-int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool force, sd_bus_error *e, Job **_ret);
-
-void manager_dump_units(Manager *s, FILE *f, const char *prefix);
-void manager_dump_jobs(Manager *s, FILE *f, const char *prefix);
-
-void manager_clear_jobs(Manager *m);
-
-unsigned manager_dispatch_load_queue(Manager *m);
-
-int manager_environment_add(Manager *m, char **minus, char **plus);
-int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit);
-
-int manager_loop(Manager *m);
-
-void manager_dispatch_bus_name_owner_changed(Manager *m, const char *name, const char* old_owner, const char *new_owner);
-
-int manager_open_serialization(Manager *m, FILE **_f);
-
-int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool switching_root);
-int manager_deserialize(Manager *m, FILE *f, FDSet *fds);
-
-int manager_reload(Manager *m);
-
-bool manager_is_reloading_or_reexecuting(Manager *m) _pure_;
-
-void manager_reset_failed(Manager *m);
-
-void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success);
-void manager_send_unit_plymouth(Manager *m, Unit *u);
-
-bool manager_unit_inactive_or_pending(Manager *m, const char *name);
-
-void manager_check_finished(Manager *m);
-
-void manager_recheck_journal(Manager *m);
-
-void manager_set_show_status(Manager *m, ShowStatus mode);
-void manager_set_first_boot(Manager *m, bool b);
-
-void manager_status_printf(Manager *m, StatusType type, const char *status, const char *format, ...) _printf_(4,5);
-void manager_flip_auto_status(Manager *m, bool enable);
-
-Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path);
-
-const char *manager_get_runtime_prefix(Manager *m);
-
-ManagerState manager_state(Manager *m);
-
-void manager_update_failed_units(Manager *m, Unit *u, bool failed);
-
-const char *manager_state_to_string(ManagerState m) _const_;
-ManagerState manager_state_from_string(const char *s) _pure_;
diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c
deleted file mode 100644
index 343ff066a..000000000
--- a/src/core/mount-setup.c
+++ /dev/null
@@ -1,399 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 <errno.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <ftw.h>
-
-#include "mount-setup.h"
-#include "dev-setup.h"
-#include "log.h"
-#include "macro.h"
-#include "util.h"
-#include "label.h"
-#include "set.h"
-#include "strv.h"
-#include "mkdir.h"
-#include "path-util.h"
-#include "missing.h"
-#include "virt.h"
-#include "efivars.h"
-#include "smack-util.h"
-#include "cgroup-util.h"
-
-typedef enum MountMode {
- MNT_NONE = 0,
- MNT_FATAL = 1 << 0,
- MNT_IN_CONTAINER = 1 << 1,
-} MountMode;
-
-typedef struct MountPoint {
- const char *what;
- const char *where;
- const char *type;
- const char *options;
- unsigned long flags;
- bool (*condition_fn)(void);
- MountMode mode;
-} MountPoint;
-
-/* The first three entries we might need before SELinux is up. The
- * fourth (securityfs) is needed by IMA to load a custom policy. The
- * other ones we can delay until SELinux and IMA are loaded. When
- * SMACK is enabled we need smackfs, too, so it's a fifth one. */
-#ifdef HAVE_SMACK
-#define N_EARLY_MOUNT 5
-#else
-#define N_EARLY_MOUNT 4
-#endif
-
-static const MountPoint mount_table[] = {
- { "sysfs", "/sys", "sysfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
- NULL, MNT_FATAL|MNT_IN_CONTAINER },
- { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
- NULL, MNT_FATAL|MNT_IN_CONTAINER },
- { "devtmpfs", "/dev", "devtmpfs", "mode=755", MS_NOSUID|MS_STRICTATIME,
- NULL, MNT_FATAL|MNT_IN_CONTAINER },
- { "securityfs", "/sys/kernel/security", "securityfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
- NULL, MNT_NONE },
-#ifdef HAVE_SMACK
- { "smackfs", "/sys/fs/smackfs", "smackfs", "smackfsdef=*", MS_NOSUID|MS_NOEXEC|MS_NODEV,
- mac_smack_use, MNT_FATAL },
- { "tmpfs", "/dev/shm", "tmpfs", "mode=1777,smackfsroot=*", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
- mac_smack_use, MNT_FATAL },
-#endif
- { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
- NULL, MNT_FATAL|MNT_IN_CONTAINER },
- { "devpts", "/dev/pts", "devpts", "mode=620,gid=" STRINGIFY(TTY_GID), MS_NOSUID|MS_NOEXEC,
- NULL, MNT_IN_CONTAINER },
-#ifdef HAVE_SMACK
- { "tmpfs", "/run", "tmpfs", "mode=755,smackfsroot=*", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
- mac_smack_use, MNT_FATAL },
-#endif
- { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
- NULL, MNT_FATAL|MNT_IN_CONTAINER },
- { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
- NULL, MNT_FATAL|MNT_IN_CONTAINER },
- { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV,
- NULL, MNT_IN_CONTAINER },
- { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV,
- NULL, MNT_FATAL|MNT_IN_CONTAINER },
- { "pstore", "/sys/fs/pstore", "pstore", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
- NULL, MNT_NONE },
-#ifdef ENABLE_EFI
- { "efivarfs", "/sys/firmware/efi/efivars", "efivarfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
- is_efi_boot, MNT_NONE },
-#endif
-#ifdef ENABLE_KDBUS
- { "kdbusfs", "/sys/fs/kdbus", "kdbusfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
- NULL, MNT_IN_CONTAINER },
-#endif
-};
-
-/* These are API file systems that might be mounted by other software,
- * we just list them here so that we know that we should ignore them */
-
-static const char ignore_paths[] =
- /* SELinux file systems */
- "/sys/fs/selinux\0"
- /* Container bind mounts */
- "/proc/sys\0"
- "/dev/console\0"
- "/proc/kmsg\0";
-
-bool mount_point_is_api(const char *path) {
- unsigned i;
-
- /* Checks if this mount point is considered "API", and hence
- * should be ignored */
-
- for (i = 0; i < ELEMENTSOF(mount_table); i ++)
- if (path_equal(path, mount_table[i].where))
- return true;
-
- return path_startswith(path, "/sys/fs/cgroup/");
-}
-
-bool mount_point_ignore(const char *path) {
- const char *i;
-
- NULSTR_FOREACH(i, ignore_paths)
- if (path_equal(path, i))
- return true;
-
- return false;
-}
-
-static int mount_one(const MountPoint *p, bool relabel) {
- int r;
-
- assert(p);
-
- if (p->condition_fn && !p->condition_fn())
- return 0;
-
- /* Relabel first, just in case */
- if (relabel)
- label_fix(p->where, true, true);
-
- r = path_is_mount_point(p->where, true);
- if (r < 0)
- return r;
-
- if (r > 0)
- return 0;
-
- /* Skip securityfs in a container */
- if (!(p->mode & MNT_IN_CONTAINER) && detect_container(NULL) > 0)
- return 0;
-
- /* The access mode here doesn't really matter too much, since
- * the mounted file system will take precedence anyway. */
- if (relabel)
- mkdir_p_label(p->where, 0755);
- else
- mkdir_p(p->where, 0755);
-
- log_debug("Mounting %s to %s of type %s with options %s.",
- p->what,
- p->where,
- p->type,
- strna(p->options));
-
- if (mount(p->what,
- p->where,
- p->type,
- p->flags,
- p->options) < 0) {
- log_full((p->mode & MNT_FATAL) ? LOG_ERR : LOG_DEBUG, "Failed to mount %s at %s: %m", p->type, p->where);
- return (p->mode & MNT_FATAL) ? -errno : 0;
- }
-
- /* Relabel again, since we now mounted something fresh here */
- if (relabel)
- label_fix(p->where, false, false);
-
- return 1;
-}
-
-int mount_setup_early(void) {
- unsigned i;
- int r = 0;
-
- assert_cc(N_EARLY_MOUNT <= ELEMENTSOF(mount_table));
-
- /* Do a minimal mount of /proc and friends to enable the most
- * basic stuff, such as SELinux */
- for (i = 0; i < N_EARLY_MOUNT; i ++) {
- int j;
-
- j = mount_one(mount_table + i, false);
- if (r == 0)
- r = j;
- }
-
- return r;
-}
-
-int mount_cgroup_controllers(char ***join_controllers) {
- _cleanup_set_free_free_ Set *controllers = NULL;
- int r;
-
- /* Mount all available cgroup controllers that are built into the kernel. */
-
- controllers = set_new(&string_hash_ops);
- if (!controllers)
- return log_oom();
-
- r = cg_kernel_controllers(controllers);
- if (r < 0)
- return log_error_errno(r, "Failed to enumerate cgroup controllers: %m");
-
- for (;;) {
- _cleanup_free_ char *options = NULL, *controller = NULL, *where = NULL;
- MountPoint p = {
- .what = "cgroup",
- .type = "cgroup",
- .flags = MS_NOSUID|MS_NOEXEC|MS_NODEV,
- .mode = MNT_IN_CONTAINER,
- };
- char ***k = NULL;
-
- controller = set_steal_first(controllers);
- if (!controller)
- break;
-
- if (join_controllers)
- for (k = join_controllers; *k; k++)
- if (strv_find(*k, controller))
- break;
-
- if (k && *k) {
- char **i, **j;
-
- for (i = *k, j = *k; *i; i++) {
-
- if (!streq(*i, controller)) {
- _cleanup_free_ char *t;
-
- t = set_remove(controllers, *i);
- if (!t) {
- free(*i);
- continue;
- }
- }
-
- *(j++) = *i;
- }
-
- *j = NULL;
-
- options = strv_join(*k, ",");
- if (!options)
- return log_oom();
- } else {
- options = controller;
- controller = NULL;
- }
-
- where = strappend("/sys/fs/cgroup/", options);
- if (!where)
- return log_oom();
-
- p.where = where;
- p.options = options;
-
- r = mount_one(&p, true);
- if (r < 0)
- return r;
-
- if (r > 0 && k && *k) {
- char **i;
-
- for (i = *k; *i; i++) {
- _cleanup_free_ char *t = NULL;
-
- t = strappend("/sys/fs/cgroup/", *i);
- if (!t)
- return log_oom();
-
- r = symlink(options, t);
- if (r < 0 && errno != EEXIST)
- return log_error_errno(errno, "Failed to create symlink %s: %m", t);
- }
- }
- }
-
- /* Now that we mounted everything, let's make the tmpfs the
- * cgroup file systems are mounted into read-only. */
- (void) mount("tmpfs", "/sys/fs/cgroup", "tmpfs", MS_REMOUNT|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME|MS_RDONLY, "mode=755");
-
- return 0;
-}
-
-#if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
-static int nftw_cb(
- const char *fpath,
- const struct stat *sb,
- int tflag,
- struct FTW *ftwbuf) {
-
- /* No need to label /dev twice in a row... */
- if (_unlikely_(ftwbuf->level == 0))
- return FTW_CONTINUE;
-
- label_fix(fpath, false, false);
-
- /* /run/initramfs is static data and big, no need to
- * dynamically relabel its contents at boot... */
- if (_unlikely_(ftwbuf->level == 1 &&
- tflag == FTW_D &&
- streq(fpath, "/run/initramfs")))
- return FTW_SKIP_SUBTREE;
-
- return FTW_CONTINUE;
-};
-#endif
-
-int mount_setup(bool loaded_policy) {
- unsigned i;
- int r = 0;
-
- for (i = 0; i < ELEMENTSOF(mount_table); i ++) {
- int j;
-
- j = mount_one(mount_table + i, loaded_policy);
- if (r == 0)
- r = j;
- }
-
- if (r < 0)
- return r;
-
-#if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
- /* Nodes in devtmpfs and /run need to be manually updated for
- * the appropriate labels, after mounting. The other virtual
- * API file systems like /sys and /proc do not need that, they
- * use the same label for all their files. */
- if (loaded_policy) {
- usec_t before_relabel, after_relabel;
- char timespan[FORMAT_TIMESPAN_MAX];
-
- before_relabel = now(CLOCK_MONOTONIC);
-
- nftw("/dev", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
- nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL);
-
- after_relabel = now(CLOCK_MONOTONIC);
-
- log_info("Relabelled /dev and /run in %s.",
- format_timespan(timespan, sizeof(timespan), after_relabel - before_relabel, 0));
- }
-#endif
-
- /* Create a few default symlinks, which are normally created
- * by udevd, but some scripts might need them before we start
- * udevd. */
- dev_setup(NULL);
-
- /* Mark the root directory as shared in regards to mount
- * propagation. The kernel defaults to "private", but we think
- * it makes more sense to have a default of "shared" so that
- * nspawn and the container tools work out of the box. If
- * specific setups need other settings they can reset the
- * propagation mode to private if needed. */
- if (detect_container(NULL) <= 0)
- if (mount(NULL, "/", NULL, MS_REC|MS_SHARED, NULL) < 0)
- log_warning_errno(errno, "Failed to set up the root directory for shared mount propagation: %m");
-
- /* Create a few directories we always want around, Note that
- * sd_booted() checks for /run/systemd/system, so this mkdir
- * really needs to stay for good, otherwise software that
- * copied sd-daemon.c into their sources will misdetect
- * systemd. */
- mkdir_label("/run/systemd", 0755);
- mkdir_label("/run/systemd/system", 0755);
- mkdir_label("/run/systemd/inaccessible", 0000);
-
- return 0;
-}
diff --git a/src/core/mount-setup.h b/src/core/mount-setup.h
deleted file mode 100644
index b32fbc5a5..000000000
--- a/src/core/mount-setup.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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);
-int mount_setup(bool loaded_policy);
-
-int mount_cgroup_controllers(char ***join_controllers);
-
-bool mount_point_is_api(const char *path);
-bool mount_point_ignore(const char *path);
diff --git a/src/core/mount.c b/src/core/mount.c
deleted file mode 100644
index 53594cd40..000000000
--- a/src/core/mount.c
+++ /dev/null
@@ -1,1947 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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>
-#include <sys/epoll.h>
-#include <signal.h>
-#include <libmount.h>
-#include <sys/inotify.h>
-
-#include "manager.h"
-#include "unit.h"
-#include "mount.h"
-#include "log.h"
-#include "sd-messages.h"
-#include "strv.h"
-#include "mkdir.h"
-#include "path-util.h"
-#include "mount-setup.h"
-#include "unit-name.h"
-#include "dbus-mount.h"
-#include "special.h"
-#include "exit-status.h"
-#include "fstab-util.h"
-
-#define RETRY_UMOUNT_MAX 32
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(struct libmnt_table*, mnt_free_table);
-DEFINE_TRIVIAL_CLEANUP_FUNC(struct libmnt_iter*, mnt_free_iter);
-
-static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = {
- [MOUNT_DEAD] = UNIT_INACTIVE,
- [MOUNT_MOUNTING] = UNIT_ACTIVATING,
- [MOUNT_MOUNTING_DONE] = UNIT_ACTIVE,
- [MOUNT_MOUNTED] = UNIT_ACTIVE,
- [MOUNT_REMOUNTING] = UNIT_RELOADING,
- [MOUNT_UNMOUNTING] = UNIT_DEACTIVATING,
- [MOUNT_MOUNTING_SIGTERM] = UNIT_DEACTIVATING,
- [MOUNT_MOUNTING_SIGKILL] = UNIT_DEACTIVATING,
- [MOUNT_REMOUNTING_SIGTERM] = UNIT_RELOADING,
- [MOUNT_REMOUNTING_SIGKILL] = UNIT_RELOADING,
- [MOUNT_UNMOUNTING_SIGTERM] = UNIT_DEACTIVATING,
- [MOUNT_UNMOUNTING_SIGKILL] = UNIT_DEACTIVATING,
- [MOUNT_FAILED] = UNIT_FAILED
-};
-
-static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
-static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
-
-static bool mount_needs_network(const char *options, const char *fstype) {
- if (fstab_test_option(options, "_netdev\0"))
- return true;
-
- if (fstype && fstype_is_network(fstype))
- return true;
-
- return false;
-}
-
-static bool mount_is_network(const MountParameters *p) {
- assert(p);
-
- return mount_needs_network(p->options, p->fstype);
-}
-
-static bool mount_is_bind(const MountParameters *p) {
- assert(p);
-
- if (fstab_test_option(p->options, "bind\0" "rbind\0"))
- return true;
-
- if (p->fstype && STR_IN_SET(p->fstype, "bind", "rbind"))
- return true;
-
- return false;
-}
-
-static bool mount_is_auto(const MountParameters *p) {
- assert(p);
-
- return !fstab_test_option(p->options, "noauto\0");
-}
-
-static bool needs_quota(const MountParameters *p) {
- assert(p);
-
- /* Quotas are not enabled on network filesystems,
- * but we want them, for example, on storage connected via iscsi */
- if (p->fstype && fstype_is_network(p->fstype))
- return false;
-
- if (mount_is_bind(p))
- return false;
-
- return fstab_test_option(p->options,
- "usrquota\0" "grpquota\0" "quota\0" "usrjquota\0" "grpjquota\0");
-}
-
-static void mount_init(Unit *u) {
- Mount *m = MOUNT(u);
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
-
- m->timeout_usec = u->manager->default_timeout_start_usec;
- m->directory_mode = 0755;
-
- if (unit_has_name(u, "-.mount")) {
- /* Don't allow start/stop for root directory */
- u->refuse_manual_start = true;
- u->refuse_manual_stop = true;
- } else {
- /* The stdio/kmsg bridge socket is on /, in order to avoid a
- * dep loop, don't use kmsg logging for -.mount */
- m->exec_context.std_output = u->manager->default_std_output;
- m->exec_context.std_error = u->manager->default_std_error;
- }
-
- /* We need to make sure that /bin/mount is always called in
- * the same process group as us, so that the autofs kernel
- * side doesn't send us another mount request while we are
- * already trying to comply its last one. */
- m->exec_context.same_pgrp = true;
-
- m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
-
- u->ignore_on_isolate = true;
-}
-
-static int mount_arm_timer(Mount *m) {
- int r;
-
- assert(m);
-
- if (m->timeout_usec <= 0) {
- m->timer_event_source = sd_event_source_unref(m->timer_event_source);
- return 0;
- }
-
- if (m->timer_event_source) {
- r = sd_event_source_set_time(m->timer_event_source, now(CLOCK_MONOTONIC) + m->timeout_usec);
- if (r < 0)
- return r;
-
- return sd_event_source_set_enabled(m->timer_event_source, SD_EVENT_ONESHOT);
- }
-
- return sd_event_add_time(
- UNIT(m)->manager->event,
- &m->timer_event_source,
- CLOCK_MONOTONIC,
- now(CLOCK_MONOTONIC) + m->timeout_usec, 0,
- mount_dispatch_timer, m);
-}
-
-static void mount_unwatch_control_pid(Mount *m) {
- assert(m);
-
- if (m->control_pid <= 0)
- return;
-
- unit_unwatch_pid(UNIT(m), m->control_pid);
- m->control_pid = 0;
-}
-
-static void mount_parameters_done(MountParameters *p) {
- assert(p);
-
- free(p->what);
- free(p->options);
- free(p->fstype);
-
- p->what = p->options = p->fstype = NULL;
-}
-
-static void mount_done(Unit *u) {
- Mount *m = MOUNT(u);
-
- assert(m);
-
- free(m->where);
- m->where = NULL;
-
- mount_parameters_done(&m->parameters_proc_self_mountinfo);
- mount_parameters_done(&m->parameters_fragment);
-
- m->exec_runtime = exec_runtime_unref(m->exec_runtime);
- exec_command_done_array(m->exec_command, _MOUNT_EXEC_COMMAND_MAX);
- m->control_command = NULL;
-
- mount_unwatch_control_pid(m);
-
- m->timer_event_source = sd_event_source_unref(m->timer_event_source);
-}
-
-_pure_ static MountParameters* get_mount_parameters_fragment(Mount *m) {
- assert(m);
-
- if (m->from_fragment)
- return &m->parameters_fragment;
-
- return NULL;
-}
-
-_pure_ static MountParameters* get_mount_parameters(Mount *m) {
- assert(m);
-
- if (m->from_proc_self_mountinfo)
- return &m->parameters_proc_self_mountinfo;
-
- return get_mount_parameters_fragment(m);
-}
-
-static int mount_add_mount_links(Mount *m) {
- _cleanup_free_ char *parent = NULL;
- MountParameters *pm;
- Unit *other;
- Iterator i;
- Set *s;
- int r;
-
- assert(m);
-
- if (!path_equal(m->where, "/")) {
- /* Adds in links to other mount points that might lie further
- * up in the hierarchy */
- r = path_get_parent(m->where, &parent);
- if (r < 0)
- return r;
-
- r = unit_require_mounts_for(UNIT(m), parent);
- if (r < 0)
- return r;
- }
-
- /* Adds in links to other mount points that might be needed
- * for the source path (if this is a bind mount) to be
- * available. */
- pm = get_mount_parameters_fragment(m);
- if (pm && pm->what &&
- path_is_absolute(pm->what) &&
- !mount_is_network(pm)) {
-
- r = unit_require_mounts_for(UNIT(m), pm->what);
- if (r < 0)
- return r;
- }
-
- /* Adds in links to other units that use this path or paths
- * further down in the hierarchy */
- s = manager_get_units_requiring_mounts_for(UNIT(m)->manager, m->where);
- SET_FOREACH(other, s, i) {
-
- if (other->load_state != UNIT_LOADED)
- continue;
-
- if (other == UNIT(m))
- continue;
-
- r = unit_add_dependency(other, UNIT_AFTER, UNIT(m), true);
- if (r < 0)
- return r;
-
- if (UNIT(m)->fragment_path) {
- /* If we have fragment configuration, then make this dependency required */
- r = unit_add_dependency(other, UNIT_REQUIRES, UNIT(m), true);
- if (r < 0)
- return r;
- }
- }
-
- return 0;
-}
-
-static int mount_add_device_links(Mount *m) {
- MountParameters *p;
- bool device_wants_mount = false;
- int r;
-
- assert(m);
-
- p = get_mount_parameters(m);
- if (!p)
- return 0;
-
- if (!p->what)
- return 0;
-
- if (mount_is_bind(p))
- return 0;
-
- if (!is_device_path(p->what))
- return 0;
-
- if (path_equal(m->where, "/"))
- return 0;
-
- if (mount_is_auto(p) && UNIT(m)->manager->running_as == SYSTEMD_SYSTEM)
- device_wants_mount = true;
-
- r = unit_add_node_link(UNIT(m), p->what, device_wants_mount);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-static int mount_add_quota_links(Mount *m) {
- int r;
- MountParameters *p;
-
- assert(m);
-
- if (UNIT(m)->manager->running_as != SYSTEMD_SYSTEM)
- return 0;
-
- p = get_mount_parameters_fragment(m);
- if (!p)
- return 0;
-
- if (!needs_quota(p))
- return 0;
-
- r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTACHECK_SERVICE, NULL, true);
- if (r < 0)
- return r;
-
- r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTAON_SERVICE, NULL, true);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-static bool should_umount(Mount *m) {
- MountParameters *p;
-
- if (path_equal(m->where, "/") ||
- path_equal(m->where, "/usr"))
- return false;
-
- p = get_mount_parameters(m);
- if (p && fstab_test_option(p->options, "x-initrd.mount\0") &&
- !in_initrd())
- return false;
-
- return true;
-}
-
-static int mount_add_default_dependencies(Mount *m) {
- const char *after, *after2, *online;
- MountParameters *p;
- int r;
-
- assert(m);
-
- if (UNIT(m)->manager->running_as != SYSTEMD_SYSTEM)
- return 0;
-
- /* We do not add any default dependencies to / and /usr, since
- * they are guaranteed to stay mounted the whole time, since
- * our system is on it. Also, don't bother with anything
- * mounted below virtual file systems, it's also going to be
- * virtual, and hence not worth the effort. */
- if (path_equal(m->where, "/") ||
- path_equal(m->where, "/usr") ||
- path_startswith(m->where, "/proc") ||
- path_startswith(m->where, "/sys") ||
- path_startswith(m->where, "/dev"))
- return 0;
-
- p = get_mount_parameters(m);
- if (!p)
- return 0;
-
- if (mount_is_network(p)) {
- after = SPECIAL_REMOTE_FS_PRE_TARGET;
- after2 = SPECIAL_NETWORK_TARGET;
- online = SPECIAL_NETWORK_ONLINE_TARGET;
- } else {
- after = SPECIAL_LOCAL_FS_PRE_TARGET;
- after2 = NULL;
- online = NULL;
- }
-
- r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, NULL, true);
- if (r < 0)
- return r;
-
- if (after2) {
- r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after2, NULL, true);
- if (r < 0)
- return r;
- }
-
- if (online) {
- r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, online, NULL, true);
- if (r < 0)
- return r;
- }
-
- if (should_umount(m)) {
- r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-static int mount_verify(Mount *m) {
- _cleanup_free_ char *e = NULL;
- bool b;
-
- assert(m);
-
- if (UNIT(m)->load_state != UNIT_LOADED)
- return 0;
-
- if (!m->from_fragment && !m->from_proc_self_mountinfo)
- return -ENOENT;
-
- e = unit_name_from_path(m->where, ".mount");
- if (!e)
- return -ENOMEM;
-
- b = unit_has_name(UNIT(m), e);
- if (!b) {
- log_unit_error(UNIT(m)->id, "%s's Where= setting doesn't match unit name. Refusing.", UNIT(m)->id);
- return -EINVAL;
- }
-
- if (mount_point_is_api(m->where) || mount_point_ignore(m->where)) {
- log_unit_error(UNIT(m)->id, "Cannot create mount unit for API file system %s. Refusing.", m->where);
- return -EINVAL;
- }
-
- if (UNIT(m)->fragment_path && !m->parameters_fragment.what) {
- log_unit_error(UNIT(m)->id, "%s's What setting is missing. Refusing.", UNIT(m)->id);
- return -EBADMSG;
- }
-
- if (m->exec_context.pam_name && m->kill_context.kill_mode != KILL_CONTROL_GROUP) {
- log_unit_error(UNIT(m)->id, "%s has PAM enabled. Kill mode must be set to control-group'. Refusing.",UNIT(m)->id);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int mount_add_extras(Mount *m) {
- Unit *u = UNIT(m);
- int r;
-
- assert(m);
-
- if (u->fragment_path)
- m->from_fragment = true;
-
- if (!m->where) {
- m->where = unit_name_to_path(u->id);
- if (!m->where)
- return -ENOMEM;
- }
-
- path_kill_slashes(m->where);
-
- if (!u->description) {
- r = unit_set_description(u, m->where);
- if (r < 0)
- return r;
- }
-
- r = mount_add_device_links(m);
- if (r < 0)
- return r;
-
- r = mount_add_mount_links(m);
- if (r < 0)
- return r;
-
- r = mount_add_quota_links(m);
- if (r < 0)
- return r;
-
- r = unit_patch_contexts(u);
- if (r < 0)
- return r;
-
- r = unit_add_exec_dependencies(u, &m->exec_context);
- if (r < 0)
- return r;
-
- r = unit_add_default_slice(u, &m->cgroup_context);
- if (r < 0)
- return r;
-
- if (u->default_dependencies) {
- r = mount_add_default_dependencies(m);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-static int mount_load(Unit *u) {
- Mount *m = MOUNT(u);
- int r;
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
-
- if (m->from_proc_self_mountinfo)
- r = unit_load_fragment_and_dropin_optional(u);
- else
- r = unit_load_fragment_and_dropin(u);
-
- if (r < 0)
- return r;
-
- /* This is a new unit? Then let's add in some extras */
- if (u->load_state == UNIT_LOADED) {
- r = mount_add_extras(m);
- if (r < 0)
- return r;
- }
-
- return mount_verify(m);
-}
-
-static int mount_notify_automount(Mount *m, int status) {
- Unit *p;
- int r;
- Iterator i;
-
- assert(m);
-
- SET_FOREACH(p, UNIT(m)->dependencies[UNIT_TRIGGERED_BY], i)
- if (p->type == UNIT_AUTOMOUNT) {
- r = automount_send_ready(AUTOMOUNT(p), status);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-static void mount_set_state(Mount *m, MountState state) {
- MountState old_state;
- assert(m);
-
- old_state = m->state;
- m->state = state;
-
- if (state != MOUNT_MOUNTING &&
- state != MOUNT_MOUNTING_DONE &&
- state != MOUNT_REMOUNTING &&
- state != MOUNT_UNMOUNTING &&
- state != MOUNT_MOUNTING_SIGTERM &&
- state != MOUNT_MOUNTING_SIGKILL &&
- state != MOUNT_UNMOUNTING_SIGTERM &&
- state != MOUNT_UNMOUNTING_SIGKILL &&
- state != MOUNT_REMOUNTING_SIGTERM &&
- state != MOUNT_REMOUNTING_SIGKILL) {
- m->timer_event_source = sd_event_source_unref(m->timer_event_source);
- mount_unwatch_control_pid(m);
- m->control_command = NULL;
- m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
- }
-
- if (state == MOUNT_MOUNTED ||
- state == MOUNT_REMOUNTING)
- mount_notify_automount(m, 0);
- else if (state == MOUNT_DEAD ||
- state == MOUNT_UNMOUNTING ||
- state == MOUNT_MOUNTING_SIGTERM ||
- state == MOUNT_MOUNTING_SIGKILL ||
- state == MOUNT_REMOUNTING_SIGTERM ||
- state == MOUNT_REMOUNTING_SIGKILL ||
- state == MOUNT_UNMOUNTING_SIGTERM ||
- state == MOUNT_UNMOUNTING_SIGKILL ||
- state == MOUNT_FAILED) {
- if (state != old_state)
- mount_notify_automount(m, -ENODEV);
- }
-
- if (state != old_state)
- log_unit_debug(UNIT(m)->id,
- "%s changed %s -> %s",
- UNIT(m)->id,
- 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);
- m->reload_result = MOUNT_SUCCESS;
-}
-
-static int mount_coldplug(Unit *u, Hashmap *deferred_work) {
- Mount *m = MOUNT(u);
- MountState new_state = MOUNT_DEAD;
- int r;
-
- assert(m);
- assert(m->state == MOUNT_DEAD);
-
- if (m->deserialized_state != m->state)
- new_state = m->deserialized_state;
- else if (m->from_proc_self_mountinfo)
- new_state = MOUNT_MOUNTED;
-
- if (new_state == m->state)
- return 0;
-
- if (new_state == MOUNT_MOUNTING ||
- new_state == MOUNT_MOUNTING_DONE ||
- new_state == MOUNT_REMOUNTING ||
- new_state == MOUNT_UNMOUNTING ||
- new_state == MOUNT_MOUNTING_SIGTERM ||
- new_state == MOUNT_MOUNTING_SIGKILL ||
- new_state == MOUNT_UNMOUNTING_SIGTERM ||
- new_state == MOUNT_UNMOUNTING_SIGKILL ||
- new_state == MOUNT_REMOUNTING_SIGTERM ||
- new_state == MOUNT_REMOUNTING_SIGKILL) {
-
- if (m->control_pid <= 0)
- return -EBADMSG;
-
- r = unit_watch_pid(UNIT(m), m->control_pid);
- if (r < 0)
- return r;
-
- r = mount_arm_timer(m);
- if (r < 0)
- return r;
- }
-
- mount_set_state(m, new_state);
- return 0;
-}
-
-static void mount_dump(Unit *u, FILE *f, const char *prefix) {
- Mount *m = MOUNT(u);
- MountParameters *p;
-
- assert(m);
- assert(f);
-
- p = get_mount_parameters(m);
-
- fprintf(f,
- "%sMount State: %s\n"
- "%sResult: %s\n"
- "%sWhere: %s\n"
- "%sWhat: %s\n"
- "%sFile System Type: %s\n"
- "%sOptions: %s\n"
- "%sFrom /proc/self/mountinfo: %s\n"
- "%sFrom fragment: %s\n"
- "%sDirectoryMode: %04o\n",
- prefix, mount_state_to_string(m->state),
- prefix, mount_result_to_string(m->result),
- prefix, m->where,
- prefix, p ? strna(p->what) : "n/a",
- prefix, p ? strna(p->fstype) : "n/a",
- prefix, p ? strna(p->options) : "n/a",
- prefix, yes_no(m->from_proc_self_mountinfo),
- prefix, yes_no(m->from_fragment),
- prefix, m->directory_mode);
-
- if (m->control_pid > 0)
- fprintf(f,
- "%sControl PID: "PID_FMT"\n",
- prefix, m->control_pid);
-
- exec_context_dump(&m->exec_context, f, prefix);
- kill_context_dump(&m->kill_context, f, prefix);
-}
-
-static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
- pid_t pid;
- int r;
- ExecParameters exec_params = {
- .apply_permissions = true,
- .apply_chroot = true,
- .apply_tty_stdin = true,
- };
-
- assert(m);
- assert(c);
- assert(_pid);
-
- (void) unit_realize_cgroup(UNIT(m));
- if (m->reset_cpu_usage) {
- (void) unit_reset_cpu_usage(UNIT(m));
- m->reset_cpu_usage = false;
- }
-
- r = unit_setup_exec_runtime(UNIT(m));
- if (r < 0)
- goto fail;
-
- r = mount_arm_timer(m);
- if (r < 0)
- goto fail;
-
- exec_params.environment = UNIT(m)->manager->environment;
- exec_params.confirm_spawn = UNIT(m)->manager->confirm_spawn;
- exec_params.cgroup_supported = UNIT(m)->manager->cgroup_supported;
- exec_params.cgroup_path = UNIT(m)->cgroup_path;
- exec_params.cgroup_delegate = m->cgroup_context.delegate;
- exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(m)->manager);
- exec_params.unit_id = UNIT(m)->id;
-
- r = exec_spawn(c,
- &m->exec_context,
- &exec_params,
- m->exec_runtime,
- &pid);
- if (r < 0)
- goto fail;
-
- r = unit_watch_pid(UNIT(m), pid);
- if (r < 0)
- /* FIXME: we need to do something here */
- goto fail;
-
- *_pid = pid;
-
- return 0;
-
-fail:
- m->timer_event_source = sd_event_source_unref(m->timer_event_source);
-
- return r;
-}
-
-static void mount_enter_dead(Mount *m, MountResult f) {
- assert(m);
-
- if (f != MOUNT_SUCCESS)
- m->result = f;
-
- exec_runtime_destroy(m->exec_runtime);
- m->exec_runtime = exec_runtime_unref(m->exec_runtime);
-
- exec_context_destroy_runtime_directory(&m->exec_context, manager_get_runtime_prefix(UNIT(m)->manager));
-
- mount_set_state(m, m->result != MOUNT_SUCCESS ? MOUNT_FAILED : MOUNT_DEAD);
-}
-
-static void mount_enter_mounted(Mount *m, MountResult f) {
- assert(m);
-
- if (f != MOUNT_SUCCESS)
- m->result = f;
-
- mount_set_state(m, MOUNT_MOUNTED);
-}
-
-static void mount_enter_signal(Mount *m, MountState state, MountResult f) {
- int r;
-
- assert(m);
-
- if (f != MOUNT_SUCCESS)
- m->result = f;
-
- r = unit_kill_context(
- UNIT(m),
- &m->kill_context,
- (state != MOUNT_MOUNTING_SIGTERM && state != MOUNT_UNMOUNTING_SIGTERM && state != MOUNT_REMOUNTING_SIGTERM) ?
- KILL_KILL : KILL_TERMINATE,
- -1,
- m->control_pid,
- false);
- if (r < 0)
- goto fail;
-
- if (r > 0) {
- r = mount_arm_timer(m);
- if (r < 0)
- goto fail;
-
- mount_set_state(m, state);
- } else if (state == MOUNT_REMOUNTING_SIGTERM)
- mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, MOUNT_SUCCESS);
- else if (state == MOUNT_REMOUNTING_SIGKILL)
- mount_enter_mounted(m, MOUNT_SUCCESS);
- else if (state == MOUNT_MOUNTING_SIGTERM)
- mount_enter_signal(m, MOUNT_MOUNTING_SIGKILL, MOUNT_SUCCESS);
- else if (state == MOUNT_UNMOUNTING_SIGTERM)
- mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, MOUNT_SUCCESS);
- else
- mount_enter_dead(m, MOUNT_SUCCESS);
-
- return;
-
-fail:
- log_unit_warning(UNIT(m)->id,
- "%s failed to kill processes: %s", UNIT(m)->id, strerror(-r));
-
- if (state == MOUNT_REMOUNTING_SIGTERM || state == MOUNT_REMOUNTING_SIGKILL)
- mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
- else
- mount_enter_dead(m, MOUNT_FAILURE_RESOURCES);
-}
-
-void warn_if_dir_nonempty(const char *unit, const char* where) {
- int r;
-
- assert(unit);
- assert(where);
-
- r = dir_is_empty(where);
- if (r > 0)
- return;
- else if (r == 0)
- log_unit_struct(unit,
- LOG_NOTICE,
- LOG_MESSAGE_ID(SD_MESSAGE_OVERMOUNTING),
- LOG_MESSAGE("%s: Directory %s to mount over is not empty, mounting anyway.",
- unit, where),
- "WHERE=%s", where,
- NULL);
- else
- log_unit_warning(unit,
- "MESSAGE=Failed to check directory %s: %s",
- where, strerror(-r));
-}
-
-static int fail_if_symlink(const char *unit, const char* where) {
- assert(where);
-
- if (is_symlink(where) > 0) {
- log_unit_struct(unit,
- LOG_ERR,
- LOG_MESSAGE_ID(SD_MESSAGE_OVERMOUNTING),
- LOG_MESSAGE("%s: Mount on symlink %s not allowed.",
- unit, where),
- "WHERE=%s", where,
- NULL);
-
- return -ELOOP;
- }
- return 0;
-}
-
-static void mount_enter_unmounting(Mount *m) {
- int r;
-
- assert(m);
-
- /* Start counting our attempts */
- if (!IN_SET(m->state,
- MOUNT_UNMOUNTING,
- MOUNT_UNMOUNTING_SIGTERM,
- MOUNT_UNMOUNTING_SIGKILL))
- m->n_retry_umount = 0;
-
- m->control_command_id = MOUNT_EXEC_UNMOUNT;
- m->control_command = m->exec_command + MOUNT_EXEC_UNMOUNT;
-
- r = exec_command_set(m->control_command, "/bin/umount", m->where, NULL);
- if (r >= 0 && UNIT(m)->manager->running_as == SYSTEMD_SYSTEM)
- r = exec_command_append(m->control_command, "-n", NULL);
- if (r < 0)
- goto fail;
-
- mount_unwatch_control_pid(m);
-
- r = mount_spawn(m, m->control_command, &m->control_pid);
- if (r < 0)
- goto fail;
-
- mount_set_state(m, MOUNT_UNMOUNTING);
-
- return;
-
-fail:
- log_unit_warning(UNIT(m)->id,
- "%s failed to run 'umount' task: %s",
- UNIT(m)->id, strerror(-r));
- mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
-}
-
-static void mount_enter_mounting(Mount *m) {
- int r;
- MountParameters *p;
-
- assert(m);
-
- m->control_command_id = MOUNT_EXEC_MOUNT;
- m->control_command = m->exec_command + MOUNT_EXEC_MOUNT;
-
- mkdir_p_label(m->where, m->directory_mode);
-
- warn_if_dir_nonempty(m->meta.id, m->where);
-
- /* Create the source directory for bind-mounts if needed */
- p = get_mount_parameters_fragment(m);
- if (p && mount_is_bind(p))
- mkdir_p_label(p->what, m->directory_mode);
-
- r = fail_if_symlink(m->meta.id, m->where);
- if (r < 0)
- goto fail;
-
- if (m->from_fragment) {
- _cleanup_free_ char *opts = NULL;
-
- r = fstab_filter_options(m->parameters_fragment.options,
- "nofail\0" "noauto\0" "auto\0", NULL, NULL, &opts);
- if (r < 0)
- goto fail;
-
- r = exec_command_set(m->control_command, "/bin/mount",
- m->parameters_fragment.what, m->where, NULL);
- if (r >= 0 && UNIT(m)->manager->running_as == SYSTEMD_SYSTEM)
- r = exec_command_append(m->control_command, "-n", NULL);
- if (r >= 0 && m->sloppy_options)
- r = exec_command_append(m->control_command, "-s", NULL);
- if (r >= 0 && m->parameters_fragment.fstype)
- r = exec_command_append(m->control_command, "-t", m->parameters_fragment.fstype, NULL);
- if (r >= 0 && !isempty(opts))
- r = exec_command_append(m->control_command, "-o", opts, NULL);
- } else
- r = -ENOENT;
-
- if (r < 0)
- goto fail;
-
- mount_unwatch_control_pid(m);
-
- r = mount_spawn(m, m->control_command, &m->control_pid);
- if (r < 0)
- goto fail;
-
- mount_set_state(m, MOUNT_MOUNTING);
-
- return;
-
-fail:
- log_unit_warning(UNIT(m)->id,
- "%s failed to run 'mount' task: %s",
- UNIT(m)->id, strerror(-r));
- mount_enter_dead(m, MOUNT_FAILURE_RESOURCES);
-}
-
-static void mount_enter_remounting(Mount *m) {
- int r;
-
- assert(m);
-
- m->control_command_id = MOUNT_EXEC_REMOUNT;
- m->control_command = m->exec_command + MOUNT_EXEC_REMOUNT;
-
- if (m->from_fragment) {
- const char *o;
-
- if (m->parameters_fragment.options)
- o = strjoina("remount,", m->parameters_fragment.options);
- else
- o = "remount";
-
- r = exec_command_set(m->control_command, "/bin/mount",
- m->parameters_fragment.what, m->where,
- "-o", o, NULL);
- if (r >= 0 && UNIT(m)->manager->running_as == SYSTEMD_SYSTEM)
- r = exec_command_append(m->control_command, "-n", NULL);
- if (r >= 0 && m->sloppy_options)
- r = exec_command_append(m->control_command, "-s", NULL);
- if (r >= 0 && m->parameters_fragment.fstype)
- r = exec_command_append(m->control_command, "-t", m->parameters_fragment.fstype, NULL);
- } else
- r = -ENOENT;
-
- if (r < 0)
- goto fail;
-
- mount_unwatch_control_pid(m);
-
- r = mount_spawn(m, m->control_command, &m->control_pid);
- if (r < 0)
- goto fail;
-
- mount_set_state(m, MOUNT_REMOUNTING);
-
- return;
-
-fail:
- log_unit_warning(UNIT(m)->id,
- "%s failed to run 'remount' task: %s",
- UNIT(m)->id, strerror(-r));
- m->reload_result = MOUNT_FAILURE_RESOURCES;
- mount_enter_mounted(m, MOUNT_SUCCESS);
-}
-
-static int mount_start(Unit *u) {
- Mount *m = MOUNT(u);
-
- assert(m);
-
- /* We cannot fulfill this request right now, try again later
- * please! */
- if (m->state == MOUNT_UNMOUNTING ||
- m->state == MOUNT_UNMOUNTING_SIGTERM ||
- m->state == MOUNT_UNMOUNTING_SIGKILL ||
- m->state == MOUNT_MOUNTING_SIGTERM ||
- m->state == MOUNT_MOUNTING_SIGKILL)
- return -EAGAIN;
-
- /* Already on it! */
- if (m->state == MOUNT_MOUNTING)
- return 0;
-
- assert(m->state == MOUNT_DEAD || m->state == MOUNT_FAILED);
-
- m->result = MOUNT_SUCCESS;
- m->reload_result = MOUNT_SUCCESS;
- m->reset_cpu_usage = true;
-
- mount_enter_mounting(m);
- return 1;
-}
-
-static int mount_stop(Unit *u) {
- Mount *m = MOUNT(u);
-
- assert(m);
-
- /* Already on it */
- if (m->state == MOUNT_UNMOUNTING ||
- m->state == MOUNT_UNMOUNTING_SIGKILL ||
- m->state == MOUNT_UNMOUNTING_SIGTERM ||
- m->state == MOUNT_MOUNTING_SIGTERM ||
- m->state == MOUNT_MOUNTING_SIGKILL)
- return 0;
-
- assert(m->state == MOUNT_MOUNTING ||
- m->state == MOUNT_MOUNTING_DONE ||
- m->state == MOUNT_MOUNTED ||
- m->state == MOUNT_REMOUNTING ||
- m->state == MOUNT_REMOUNTING_SIGTERM ||
- m->state == MOUNT_REMOUNTING_SIGKILL);
-
- mount_enter_unmounting(m);
- return 1;
-}
-
-static int mount_reload(Unit *u) {
- Mount *m = MOUNT(u);
-
- assert(m);
-
- if (m->state == MOUNT_MOUNTING_DONE)
- return -EAGAIN;
-
- assert(m->state == MOUNT_MOUNTED);
-
- mount_enter_remounting(m);
- return 0;
-}
-
-static int mount_serialize(Unit *u, FILE *f, FDSet *fds) {
- Mount *m = MOUNT(u);
-
- assert(m);
- assert(f);
- assert(fds);
-
- unit_serialize_item(u, f, "state", mount_state_to_string(m->state));
- unit_serialize_item(u, f, "result", mount_result_to_string(m->result));
- unit_serialize_item(u, f, "reload-result", mount_result_to_string(m->reload_result));
-
- if (m->control_pid > 0)
- unit_serialize_item_format(u, f, "control-pid", PID_FMT, m->control_pid);
-
- if (m->control_command_id >= 0)
- unit_serialize_item(u, f, "control-command", mount_exec_command_to_string(m->control_command_id));
-
- return 0;
-}
-
-static int mount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Mount *m = MOUNT(u);
-
- assert(u);
- assert(key);
- assert(value);
- assert(fds);
-
- if (streq(key, "state")) {
- MountState state;
-
- if ((state = mount_state_from_string(value)) < 0)
- log_unit_debug(u->id, "Failed to parse state value %s", value);
- else
- m->deserialized_state = state;
- } else if (streq(key, "result")) {
- MountResult f;
-
- f = mount_result_from_string(value);
- if (f < 0)
- log_unit_debug(UNIT(m)->id,
- "Failed to parse result value %s", value);
- else if (f != MOUNT_SUCCESS)
- m->result = f;
-
- } else if (streq(key, "reload-result")) {
- MountResult f;
-
- f = mount_result_from_string(value);
- if (f < 0)
- log_unit_debug(UNIT(m)->id,
- "Failed to parse reload result value %s", value);
- else if (f != MOUNT_SUCCESS)
- m->reload_result = f;
-
- } else if (streq(key, "control-pid")) {
- pid_t pid;
-
- if (parse_pid(value, &pid) < 0)
- log_unit_debug(UNIT(m)->id,
- "Failed to parse control-pid value %s", value);
- else
- m->control_pid = pid;
- } else if (streq(key, "control-command")) {
- MountExecCommand id;
-
- if ((id = mount_exec_command_from_string(value)) < 0)
- log_unit_debug(UNIT(m)->id,
- "Failed to parse exec-command value %s", value);
- else {
- m->control_command_id = id;
- m->control_command = m->exec_command + id;
- }
- } else
- log_unit_debug(UNIT(m)->id,
- "Unknown serialization key '%s'", key);
-
- return 0;
-}
-
-_pure_ static UnitActiveState mount_active_state(Unit *u) {
- assert(u);
-
- return state_translation_table[MOUNT(u)->state];
-}
-
-_pure_ static const char *mount_sub_state_to_string(Unit *u) {
- assert(u);
-
- return mount_state_to_string(MOUNT(u)->state);
-}
-
-_pure_ static bool mount_check_gc(Unit *u) {
- Mount *m = MOUNT(u);
-
- assert(m);
-
- return m->from_proc_self_mountinfo;
-}
-
-static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
- Mount *m = MOUNT(u);
- MountResult f;
-
- assert(m);
- assert(pid >= 0);
-
- if (pid != m->control_pid)
- return;
-
- m->control_pid = 0;
-
- if (is_clean_exit(code, status, NULL))
- f = MOUNT_SUCCESS;
- else if (code == CLD_EXITED)
- f = MOUNT_FAILURE_EXIT_CODE;
- else if (code == CLD_KILLED)
- f = MOUNT_FAILURE_SIGNAL;
- else if (code == CLD_DUMPED)
- f = MOUNT_FAILURE_CORE_DUMP;
- else
- assert_not_reached("Unknown code");
-
- if (f != MOUNT_SUCCESS)
- m->result = f;
-
- if (m->control_command) {
- exec_status_exit(&m->control_command->exec_status, &m->exec_context, pid, code, status);
-
- m->control_command = NULL;
- m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
- }
-
- log_unit_full(u->id,
- f == MOUNT_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
- "%s mount process exited, code=%s status=%i",
- u->id, sigchld_code_to_string(code), status);
-
- /* Note that mount(8) returning and the kernel sending us a
- * mount table change event might happen out-of-order. If an
- * operation succeed we assume the kernel will follow soon too
- * and already change into the resulting state. If it fails
- * we check if the kernel still knows about the mount. and
- * change state accordingly. */
-
- switch (m->state) {
-
- case MOUNT_MOUNTING:
- case MOUNT_MOUNTING_DONE:
- case MOUNT_MOUNTING_SIGKILL:
- case MOUNT_MOUNTING_SIGTERM:
-
- if (f == MOUNT_SUCCESS)
- mount_enter_mounted(m, f);
- else if (m->from_proc_self_mountinfo)
- mount_enter_mounted(m, f);
- else
- mount_enter_dead(m, f);
- break;
-
- case MOUNT_REMOUNTING:
- case MOUNT_REMOUNTING_SIGKILL:
- case MOUNT_REMOUNTING_SIGTERM:
-
- m->reload_result = f;
- if (m->from_proc_self_mountinfo)
- mount_enter_mounted(m, MOUNT_SUCCESS);
- else
- mount_enter_dead(m, MOUNT_SUCCESS);
-
- break;
-
- case MOUNT_UNMOUNTING:
- case MOUNT_UNMOUNTING_SIGKILL:
- case MOUNT_UNMOUNTING_SIGTERM:
-
- if (f == MOUNT_SUCCESS) {
-
- if (m->from_proc_self_mountinfo) {
-
- /* Still a mount point? If so, let's
- * try again. Most likely there were
- * multiple mount points stacked on
- * top of each other. Note that due to
- * the io event priority logic we can
- * be sure the new mountinfo is loaded
- * before we process the SIGCHLD for
- * the mount command. */
-
- if (m->n_retry_umount < RETRY_UMOUNT_MAX) {
- log_unit_debug(u->id, "%s: mount still present, trying again.", u->id);
- m->n_retry_umount++;
- mount_enter_unmounting(m);
- } else {
- log_unit_debug(u->id, "%s: mount still present after %u attempts to unmount, giving up.", u->id, m->n_retry_umount);
- mount_enter_mounted(m, f);
- }
- } else
- mount_enter_dead(m, f);
-
- } else if (m->from_proc_self_mountinfo)
- mount_enter_mounted(m, f);
- else
- mount_enter_dead(m, f);
- break;
-
- default:
- assert_not_reached("Uh, control process died at wrong time.");
- }
-
- /* Notify clients about changed exit status */
- unit_add_to_dbus_queue(u);
-}
-
-static int mount_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
- Mount *m = MOUNT(userdata);
-
- assert(m);
- assert(m->timer_event_source == source);
-
- switch (m->state) {
-
- case MOUNT_MOUNTING:
- case MOUNT_MOUNTING_DONE:
- log_unit_warning(UNIT(m)->id,
- "%s mounting timed out. Stopping.", UNIT(m)->id);
- mount_enter_signal(m, MOUNT_MOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
- break;
-
- case MOUNT_REMOUNTING:
- log_unit_warning(UNIT(m)->id,
- "%s remounting timed out. Stopping.", UNIT(m)->id);
- m->reload_result = MOUNT_FAILURE_TIMEOUT;
- mount_enter_mounted(m, MOUNT_SUCCESS);
- break;
-
- case MOUNT_UNMOUNTING:
- log_unit_warning(UNIT(m)->id,
- "%s unmounting timed out. Stopping.", UNIT(m)->id);
- mount_enter_signal(m, MOUNT_UNMOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
- break;
-
- case MOUNT_MOUNTING_SIGTERM:
- if (m->kill_context.send_sigkill) {
- log_unit_warning(UNIT(m)->id,
- "%s mounting timed out. Killing.", UNIT(m)->id);
- mount_enter_signal(m, MOUNT_MOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
- } else {
- log_unit_warning(UNIT(m)->id,
- "%s mounting timed out. Skipping SIGKILL. Ignoring.",
- UNIT(m)->id);
-
- if (m->from_proc_self_mountinfo)
- mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
- else
- mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
- }
- break;
-
- case MOUNT_REMOUNTING_SIGTERM:
- if (m->kill_context.send_sigkill) {
- log_unit_warning(UNIT(m)->id,
- "%s remounting timed out. Killing.", UNIT(m)->id);
- mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
- } else {
- log_unit_warning(UNIT(m)->id,
- "%s remounting timed out. Skipping SIGKILL. Ignoring.",
- UNIT(m)->id);
-
- if (m->from_proc_self_mountinfo)
- mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
- else
- mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
- }
- break;
-
- case MOUNT_UNMOUNTING_SIGTERM:
- if (m->kill_context.send_sigkill) {
- log_unit_warning(UNIT(m)->id,
- "%s unmounting timed out. Killing.", UNIT(m)->id);
- mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
- } else {
- log_unit_warning(UNIT(m)->id,
- "%s unmounting timed out. Skipping SIGKILL. Ignoring.",
- UNIT(m)->id);
-
- if (m->from_proc_self_mountinfo)
- mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
- else
- mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
- }
- break;
-
- case MOUNT_MOUNTING_SIGKILL:
- case MOUNT_REMOUNTING_SIGKILL:
- case MOUNT_UNMOUNTING_SIGKILL:
- log_unit_warning(UNIT(m)->id,
- "%s mount process still around after SIGKILL. Ignoring.",
- UNIT(m)->id);
-
- if (m->from_proc_self_mountinfo)
- mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
- else
- mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
- break;
-
- default:
- assert_not_reached("Timeout at wrong time.");
- }
-
- return 0;
-}
-
-static int mount_setup_unit(
- Manager *m,
- const char *what,
- const char *where,
- const char *options,
- const char *fstype,
- bool set_flags) {
-
- _cleanup_free_ char *e = NULL, *w = NULL, *o = NULL, *f = NULL;
- bool load_extras = false;
- MountParameters *p;
- bool delete, changed = false;
- Unit *u;
- int r;
-
- assert(m);
- assert(what);
- assert(where);
- assert(options);
- assert(fstype);
-
- /* Ignore API mount points. They should never be referenced in
- * dependencies ever. */
- if (mount_point_is_api(where) || mount_point_ignore(where))
- return 0;
-
- if (streq(fstype, "autofs"))
- return 0;
-
- /* probably some kind of swap, ignore */
- if (!is_path(where))
- return 0;
-
- e = unit_name_from_path(where, ".mount");
- if (!e)
- return -ENOMEM;
-
- u = manager_get_unit(m, e);
- if (!u) {
- delete = true;
-
- u = unit_new(m, sizeof(Mount));
- if (!u)
- return log_oom();
-
- r = unit_add_name(u, e);
- if (r < 0)
- goto fail;
-
- MOUNT(u)->where = strdup(where);
- if (!MOUNT(u)->where) {
- r = -ENOMEM;
- goto fail;
- }
-
- u->source_path = strdup("/proc/self/mountinfo");
- if (!u->source_path) {
- r = -ENOMEM;
- goto fail;
- }
-
- if (m->running_as == SYSTEMD_SYSTEM) {
- const char* target;
-
- target = mount_needs_network(options, fstype) ? SPECIAL_REMOTE_FS_TARGET : SPECIAL_LOCAL_FS_TARGET;
- r = unit_add_dependency_by_name(u, UNIT_BEFORE, target, NULL, true);
- if (r < 0)
- goto fail;
-
- if (should_umount(MOUNT(u))) {
- r = unit_add_dependency_by_name(u, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
- if (r < 0)
- goto fail;
- }
- }
-
- unit_add_to_load_queue(u);
- changed = true;
- } else {
- delete = false;
-
- if (!MOUNT(u)->where) {
- MOUNT(u)->where = strdup(where);
- if (!MOUNT(u)->where) {
- r = -ENOMEM;
- goto fail;
- }
- }
-
- if (m->running_as == SYSTEMD_SYSTEM &&
- mount_needs_network(options, fstype)) {
- /* _netdev option may have shown up late, or on a
- * remount. Add remote-fs dependencies, even though
- * local-fs ones may already be there. */
- unit_add_dependency_by_name(u, UNIT_BEFORE, SPECIAL_REMOTE_FS_TARGET, NULL, true);
- load_extras = true;
- }
-
- if (u->load_state == UNIT_NOT_FOUND) {
- u->load_state = UNIT_LOADED;
- u->load_error = 0;
-
- /* Load in the extras later on, after we
- * finished initialization of the unit */
- load_extras = true;
- changed = true;
- }
- }
-
- w = strdup(what);
- o = strdup(options);
- f = strdup(fstype);
- if (!w || !o || !f) {
- r = -ENOMEM;
- goto fail;
- }
-
- p = &MOUNT(u)->parameters_proc_self_mountinfo;
-
- changed = changed ||
- !streq_ptr(p->options, options) ||
- !streq_ptr(p->what, what) ||
- !streq_ptr(p->fstype, fstype);
-
- if (set_flags) {
- MOUNT(u)->is_mounted = true;
- MOUNT(u)->just_mounted = !MOUNT(u)->from_proc_self_mountinfo;
- MOUNT(u)->just_changed = changed;
- }
-
- MOUNT(u)->from_proc_self_mountinfo = true;
-
- free(p->what);
- p->what = w;
- w = NULL;
-
- free(p->options);
- p->options = o;
- o = NULL;
-
- free(p->fstype);
- p->fstype = f;
- f = NULL;
-
- if (load_extras) {
- r = mount_add_extras(MOUNT(u));
- if (r < 0)
- goto fail;
- }
-
- if (changed)
- unit_add_to_dbus_queue(u);
-
- return 0;
-
-fail:
- log_warning_errno(r, "Failed to set up mount unit: %m");
-
- if (delete && u)
- unit_free(u);
-
- return r;
-}
-
-static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
- _cleanup_(mnt_free_tablep) struct libmnt_table *t = NULL;
- _cleanup_(mnt_free_iterp) struct libmnt_iter *i = NULL;
- int r = 0;
-
- assert(m);
-
- t = mnt_new_table();
- if (!t)
- return log_oom();
-
- i = mnt_new_iter(MNT_ITER_FORWARD);
- if (!i)
- return log_oom();
-
- r = mnt_table_parse_mtab(t, NULL);
- if (r < 0)
- return log_error_errno(r, "Failed to parse /proc/self/mountinfo: %m");
-
- r = 0;
- for (;;) {
- const char *device, *path, *options, *fstype;
- _cleanup_free_ const char *d = NULL, *p = NULL;
- struct libmnt_fs *fs;
- int k;
-
- k = mnt_table_next_fs(t, i, &fs);
- if (k == 1)
- break;
- if (k < 0)
- return log_error_errno(k, "Failed to get next entry from /proc/self/mountinfo: %m");
-
- device = mnt_fs_get_source(fs);
- path = mnt_fs_get_target(fs);
- options = mnt_fs_get_options(fs);
- fstype = mnt_fs_get_fstype(fs);
-
- d = cunescape(device);
- if (!d)
- return log_oom();
-
- p = cunescape(path);
- if (!p)
- return log_oom();
-
- (void) device_found_node(m, d, true, DEVICE_FOUND_MOUNT, set_flags);
-
- k = mount_setup_unit(m, d, p, options, fstype, set_flags);
- if (r == 0 && k < 0)
- r = k;
- }
-
- return r;
-}
-
-static void mount_shutdown(Manager *m) {
- assert(m);
-
- m->mount_event_source = sd_event_source_unref(m->mount_event_source);
- m->mount_utab_event_source = sd_event_source_unref(m->mount_utab_event_source);
-
- if (m->proc_self_mountinfo) {
- fclose(m->proc_self_mountinfo);
- m->proc_self_mountinfo = NULL;
- }
- m->utab_inotify_fd = safe_close(m->utab_inotify_fd);
-}
-
-static int mount_get_timeout(Unit *u, uint64_t *timeout) {
- Mount *m = MOUNT(u);
- int r;
-
- if (!m->timer_event_source)
- return 0;
-
- r = sd_event_source_get_time(m->timer_event_source, timeout);
- if (r < 0)
- return r;
-
- return 1;
-}
-
-static int mount_enumerate(Manager *m) {
- int r;
- assert(m);
-
- mnt_init_debug(0);
-
- if (!m->proc_self_mountinfo) {
- m->proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
- if (!m->proc_self_mountinfo)
- return -errno;
-
- r = sd_event_add_io(m->event, &m->mount_event_source, fileno(m->proc_self_mountinfo), EPOLLPRI, mount_dispatch_io, m);
- if (r < 0)
- goto fail;
-
- /* Dispatch this before we dispatch SIGCHLD, so that
- * we always get the events from /proc/self/mountinfo
- * before the SIGCHLD of /bin/mount. */
- r = sd_event_source_set_priority(m->mount_event_source, -10);
- if (r < 0)
- goto fail;
- }
-
- if (m->utab_inotify_fd < 0) {
- m->utab_inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
- if (m->utab_inotify_fd < 0) {
- r = -errno;
- goto fail;
- }
-
- (void) mkdir_p_label("/run/mount", 0755);
-
- r = inotify_add_watch(m->utab_inotify_fd, "/run/mount", IN_MOVED_TO);
- if (r < 0) {
- r = -errno;
- goto fail;
- }
-
- r = sd_event_add_io(m->event, &m->mount_utab_event_source, m->utab_inotify_fd, EPOLLIN, mount_dispatch_io, m);
- if (r < 0)
- goto fail;
-
- r = sd_event_source_set_priority(m->mount_utab_event_source, -10);
- if (r < 0)
- goto fail;
- }
-
- r = mount_load_proc_self_mountinfo(m, false);
- if (r < 0)
- goto fail;
-
- return 0;
-
-fail:
- mount_shutdown(m);
- return r;
-}
-
-static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
- Manager *m = userdata;
- Unit *u;
- int r;
-
- assert(m);
- assert(revents & (EPOLLPRI | EPOLLIN));
-
- /* The manager calls this for every fd event happening on the
- * /proc/self/mountinfo file, which informs us about mounting
- * table changes, and for /run/mount events which we watch
- * for mount options. */
-
- if (fd == m->utab_inotify_fd) {
- bool rescan = false;
-
- /* FIXME: We *really* need to replace this with
- * libmount's own API for this, we should not hardcode
- * internal behaviour of libmount here. */
-
- for (;;) {
- union inotify_event_buffer buffer;
- struct inotify_event *e;
- ssize_t l;
-
- l = read(fd, &buffer, sizeof(buffer));
- if (l < 0) {
- if (errno == EAGAIN || errno == EINTR)
- break;
-
- log_error_errno(errno, "Failed to read utab inotify: %m");
- break;
- }
-
- FOREACH_INOTIFY_EVENT(e, buffer, l) {
- /* Only care about changes to utab,
- * but we have to monitor the
- * directory to reliably get
- * notifications about when utab is
- * replaced using rename(2) */
- if ((e->mask & IN_Q_OVERFLOW) || streq(e->name, "utab"))
- rescan = true;
- }
- }
-
- if (!rescan)
- return 0;
- }
-
- r = mount_load_proc_self_mountinfo(m, true);
- if (r < 0) {
- /* Reset flags, just in case, for later calls */
- LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_MOUNT]) {
- Mount *mount = MOUNT(u);
-
- mount->is_mounted = mount->just_mounted = mount->just_changed = false;
- }
-
- return 0;
- }
-
- manager_dispatch_load_queue(m);
-
- LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_MOUNT]) {
- Mount *mount = MOUNT(u);
-
- if (!mount->is_mounted) {
-
- mount->from_proc_self_mountinfo = false;
-
- switch (mount->state) {
-
- case MOUNT_MOUNTED:
- /* This has just been unmounted by
- * somebody else, follow the state
- * change. */
- mount_enter_dead(mount, MOUNT_SUCCESS);
- break;
-
- default:
- break;
- }
-
- if (mount->parameters_proc_self_mountinfo.what)
- (void) device_found_node(m, mount->parameters_proc_self_mountinfo.what, false, DEVICE_FOUND_MOUNT, true);
-
-
- } else if (mount->just_mounted || mount->just_changed) {
-
- /* New or changed mount entry */
-
- switch (mount->state) {
-
- case MOUNT_DEAD:
- case MOUNT_FAILED:
- /* This has just been mounted by
- * somebody else, follow the state
- * change. */
- mount_enter_mounted(mount, MOUNT_SUCCESS);
- break;
-
- case MOUNT_MOUNTING:
- mount_set_state(mount, MOUNT_MOUNTING_DONE);
- break;
-
- default:
- /* Nothing really changed, but let's
- * issue an notification call
- * nonetheless, in case somebody is
- * waiting for this. (e.g. file system
- * ro/rw remounts.) */
- mount_set_state(mount, mount->state);
- break;
- }
- }
-
- /* Reset the flags for later calls */
- mount->is_mounted = mount->just_mounted = mount->just_changed = false;
- }
-
- return 0;
-}
-
-static void mount_reset_failed(Unit *u) {
- Mount *m = MOUNT(u);
-
- assert(m);
-
- if (m->state == MOUNT_FAILED)
- mount_set_state(m, MOUNT_DEAD);
-
- m->result = MOUNT_SUCCESS;
- m->reload_result = MOUNT_SUCCESS;
-}
-
-static int mount_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
- return unit_kill_common(u, who, signo, -1, MOUNT(u)->control_pid, error);
-}
-
-static const char* const mount_state_table[_MOUNT_STATE_MAX] = {
- [MOUNT_DEAD] = "dead",
- [MOUNT_MOUNTING] = "mounting",
- [MOUNT_MOUNTING_DONE] = "mounting-done",
- [MOUNT_MOUNTED] = "mounted",
- [MOUNT_REMOUNTING] = "remounting",
- [MOUNT_UNMOUNTING] = "unmounting",
- [MOUNT_MOUNTING_SIGTERM] = "mounting-sigterm",
- [MOUNT_MOUNTING_SIGKILL] = "mounting-sigkill",
- [MOUNT_REMOUNTING_SIGTERM] = "remounting-sigterm",
- [MOUNT_REMOUNTING_SIGKILL] = "remounting-sigkill",
- [MOUNT_UNMOUNTING_SIGTERM] = "unmounting-sigterm",
- [MOUNT_UNMOUNTING_SIGKILL] = "unmounting-sigkill",
- [MOUNT_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(mount_state, MountState);
-
-static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = {
- [MOUNT_EXEC_MOUNT] = "ExecMount",
- [MOUNT_EXEC_UNMOUNT] = "ExecUnmount",
- [MOUNT_EXEC_REMOUNT] = "ExecRemount",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(mount_exec_command, MountExecCommand);
-
-static const char* const mount_result_table[_MOUNT_RESULT_MAX] = {
- [MOUNT_SUCCESS] = "success",
- [MOUNT_FAILURE_RESOURCES] = "resources",
- [MOUNT_FAILURE_TIMEOUT] = "timeout",
- [MOUNT_FAILURE_EXIT_CODE] = "exit-code",
- [MOUNT_FAILURE_SIGNAL] = "signal",
- [MOUNT_FAILURE_CORE_DUMP] = "core-dump"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(mount_result, MountResult);
-
-const UnitVTable mount_vtable = {
- .object_size = sizeof(Mount),
- .exec_context_offset = offsetof(Mount, exec_context),
- .cgroup_context_offset = offsetof(Mount, cgroup_context),
- .kill_context_offset = offsetof(Mount, kill_context),
- .exec_runtime_offset = offsetof(Mount, exec_runtime),
-
- .sections =
- "Unit\0"
- "Mount\0"
- "Install\0",
- .private_section = "Mount",
-
- .no_alias = true,
- .no_instances = true,
-
- .init = mount_init,
- .load = mount_load,
- .done = mount_done,
-
- .coldplug = mount_coldplug,
-
- .dump = mount_dump,
-
- .start = mount_start,
- .stop = mount_stop,
- .reload = mount_reload,
-
- .kill = mount_kill,
-
- .serialize = mount_serialize,
- .deserialize_item = mount_deserialize_item,
-
- .active_state = mount_active_state,
- .sub_state_to_string = mount_sub_state_to_string,
-
- .check_gc = mount_check_gc,
-
- .sigchld_event = mount_sigchld_event,
-
- .reset_failed = mount_reset_failed,
-
- .bus_interface = "org.freedesktop.systemd1.Mount",
- .bus_vtable = bus_mount_vtable,
- .bus_set_property = bus_mount_set_property,
- .bus_commit_properties = bus_mount_commit_properties,
-
- .get_timeout = mount_get_timeout,
-
- .can_transient = true,
-
- .enumerate = mount_enumerate,
- .shutdown = mount_shutdown,
-
- .status_message_formats = {
- .starting_stopping = {
- [0] = "Mounting %s...",
- [1] = "Unmounting %s...",
- },
- .finished_start_job = {
- [JOB_DONE] = "Mounted %s.",
- [JOB_FAILED] = "Failed to mount %s.",
- [JOB_DEPENDENCY] = "Dependency failed for %s.",
- [JOB_TIMEOUT] = "Timed out mounting %s.",
- },
- .finished_stop_job = {
- [JOB_DONE] = "Unmounted %s.",
- [JOB_FAILED] = "Failed unmounting %s.",
- [JOB_TIMEOUT] = "Timed out unmounting %s.",
- },
- },
-};
diff --git a/src/core/mount.h b/src/core/mount.h
deleted file mode 100644
index 072b0e044..000000000
--- a/src/core/mount.h
+++ /dev/null
@@ -1,132 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 "execute.h"
-
-typedef enum MountState {
- MOUNT_DEAD,
- MOUNT_MOUNTING, /* /bin/mount is running, but the mount is not done yet. */
- MOUNT_MOUNTING_DONE, /* /bin/mount is running, and the mount is done. */
- MOUNT_MOUNTED,
- MOUNT_REMOUNTING,
- MOUNT_UNMOUNTING,
- MOUNT_MOUNTING_SIGTERM,
- MOUNT_MOUNTING_SIGKILL,
- MOUNT_REMOUNTING_SIGTERM,
- MOUNT_REMOUNTING_SIGKILL,
- MOUNT_UNMOUNTING_SIGTERM,
- MOUNT_UNMOUNTING_SIGKILL,
- MOUNT_FAILED,
- _MOUNT_STATE_MAX,
- _MOUNT_STATE_INVALID = -1
-} MountState;
-
-typedef enum MountExecCommand {
- MOUNT_EXEC_MOUNT,
- MOUNT_EXEC_UNMOUNT,
- MOUNT_EXEC_REMOUNT,
- _MOUNT_EXEC_COMMAND_MAX,
- _MOUNT_EXEC_COMMAND_INVALID = -1
-} MountExecCommand;
-
-typedef enum MountResult {
- MOUNT_SUCCESS,
- MOUNT_FAILURE_RESOURCES,
- MOUNT_FAILURE_TIMEOUT,
- MOUNT_FAILURE_EXIT_CODE,
- MOUNT_FAILURE_SIGNAL,
- MOUNT_FAILURE_CORE_DUMP,
- _MOUNT_RESULT_MAX,
- _MOUNT_RESULT_INVALID = -1
-} MountResult;
-
-typedef struct MountParameters {
- char *what;
- char *options;
- char *fstype;
-} MountParameters;
-
-struct Mount {
- Unit meta;
-
- char *where;
-
- MountParameters parameters_proc_self_mountinfo;
- MountParameters parameters_fragment;
-
- bool from_proc_self_mountinfo:1;
- bool from_fragment:1;
-
- /* Used while looking for mount points that vanished or got
- * added from/to /proc/self/mountinfo */
- bool is_mounted:1;
- bool just_mounted:1;
- bool just_changed:1;
-
- bool reset_cpu_usage:1;
-
- bool sloppy_options;
-
- MountResult result;
- MountResult reload_result;
-
- mode_t directory_mode;
-
- usec_t timeout_usec;
-
- ExecCommand exec_command[_MOUNT_EXEC_COMMAND_MAX];
-
- ExecContext exec_context;
- KillContext kill_context;
- CGroupContext cgroup_context;
-
- ExecRuntime *exec_runtime;
-
- MountState state, deserialized_state;
-
- ExecCommand* control_command;
- MountExecCommand control_command_id;
- pid_t control_pid;
-
- sd_event_source *timer_event_source;
-
- unsigned n_retry_umount;
-};
-
-extern const UnitVTable mount_vtable;
-
-void mount_fd_event(Manager *m, int events);
-
-const char* mount_state_to_string(MountState i) _const_;
-MountState mount_state_from_string(const char *s) _pure_;
-
-const char* mount_exec_command_to_string(MountExecCommand i) _const_;
-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_;
-
-void warn_if_dir_nonempty(const char *unit, const char* where);
diff --git a/src/core/namespace.c b/src/core/namespace.c
deleted file mode 100644
index 718da2384..000000000
--- a/src/core/namespace.c
+++ /dev/null
@@ -1,702 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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/mount.h>
-#include <string.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sched.h>
-#include <linux/fs.h>
-
-#include "strv.h"
-#include "util.h"
-#include "path-util.h"
-#include "missing.h"
-#include "loopback-setup.h"
-#include "dev-setup.h"
-#include "selinux-util.h"
-#include "namespace.h"
-
-typedef enum MountMode {
- /* This is ordered by priority! */
- INACCESSIBLE,
- READONLY,
- PRIVATE_TMP,
- PRIVATE_VAR_TMP,
- PRIVATE_DEV,
- PRIVATE_BUS_ENDPOINT,
- READWRITE
-} MountMode;
-
-typedef struct BindMount {
- const char *path;
- MountMode mode;
- bool done;
- bool ignore;
-} BindMount;
-
-static int append_mounts(BindMount **p, char **strv, MountMode mode) {
- char **i;
-
- assert(p);
-
- STRV_FOREACH(i, strv) {
-
- (*p)->ignore = false;
- (*p)->done = false;
-
- if ((mode == INACCESSIBLE || mode == READONLY || mode == READWRITE) && (*i)[0] == '-') {
- (*p)->ignore = true;
- (*i)++;
- }
-
- if (!path_is_absolute(*i))
- return -EINVAL;
-
- (*p)->path = *i;
- (*p)->mode = mode;
- (*p)++;
- }
-
- return 0;
-}
-
-static int mount_path_compare(const void *a, const void *b) {
- const BindMount *p = a, *q = b;
- int d;
-
- d = path_compare(p->path, q->path);
-
- if (!d) {
- /* If the paths are equal, check the mode */
- if (p->mode < q->mode)
- return -1;
-
- if (p->mode > q->mode)
- return 1;
-
- return 0;
- }
-
- /* If the paths are not equal, then order prefixes first */
- return d;
-}
-
-static void drop_duplicates(BindMount *m, unsigned *n) {
- BindMount *f, *t, *previous;
-
- assert(m);
- assert(n);
-
- for (f = m, t = m, previous = NULL; f < m+*n; f++) {
-
- /* The first one wins */
- if (previous && path_equal(f->path, previous->path))
- continue;
-
- *t = *f;
-
- previous = t;
-
- t++;
- }
-
- *n = t - m;
-}
-
-static int mount_dev(BindMount *m) {
- static const char devnodes[] =
- "/dev/null\0"
- "/dev/zero\0"
- "/dev/full\0"
- "/dev/random\0"
- "/dev/urandom\0"
- "/dev/tty\0";
-
- char temporary_mount[] = "/tmp/namespace-dev-XXXXXX";
- const char *d, *dev = NULL, *devpts = NULL, *devshm = NULL, *devhugepages = NULL, *devmqueue = NULL, *devlog = NULL, *devptmx = NULL;
- _cleanup_umask_ mode_t u;
- int r;
-
- assert(m);
-
- u = umask(0000);
-
- if (!mkdtemp(temporary_mount))
- return -errno;
-
- dev = strjoina(temporary_mount, "/dev");
- (void) mkdir(dev, 0755);
- if (mount("tmpfs", dev, "tmpfs", MS_NOSUID|MS_STRICTATIME, "mode=755") < 0) {
- r = -errno;
- goto fail;
- }
-
- devpts = strjoina(temporary_mount, "/dev/pts");
- (void) mkdir(devpts, 0755);
- if (mount("/dev/pts", devpts, NULL, MS_BIND, NULL) < 0) {
- r = -errno;
- goto fail;
- }
-
- devptmx = strjoina(temporary_mount, "/dev/ptmx");
- if (symlink("pts/ptmx", devptmx) < 0) {
- r = -errno;
- goto fail;
- }
-
- devshm = strjoina(temporary_mount, "/dev/shm");
- (void) mkdir(devshm, 01777);
- r = mount("/dev/shm", devshm, NULL, MS_BIND, NULL);
- if (r < 0) {
- r = -errno;
- goto fail;
- }
-
- devmqueue = strjoina(temporary_mount, "/dev/mqueue");
- (void) mkdir(devmqueue, 0755);
- (void) mount("/dev/mqueue", devmqueue, NULL, MS_BIND, NULL);
-
- devhugepages = strjoina(temporary_mount, "/dev/hugepages");
- (void) mkdir(devhugepages, 0755);
- (void) mount("/dev/hugepages", devhugepages, NULL, MS_BIND, NULL);
-
- devlog = strjoina(temporary_mount, "/dev/log");
- (void) symlink("/run/systemd/journal/dev-log", devlog);
-
- NULSTR_FOREACH(d, devnodes) {
- _cleanup_free_ char *dn = NULL;
- struct stat st;
-
- r = stat(d, &st);
- if (r < 0) {
-
- if (errno == ENOENT)
- continue;
-
- r = -errno;
- goto fail;
- }
-
- if (!S_ISBLK(st.st_mode) &&
- !S_ISCHR(st.st_mode)) {
- r = -EINVAL;
- goto fail;
- }
-
- if (st.st_rdev == 0)
- continue;
-
- dn = strappend(temporary_mount, d);
- if (!dn) {
- r = -ENOMEM;
- goto fail;
- }
-
- 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) {
- r = -errno;
- goto fail;
- }
- }
-
- dev_setup(temporary_mount);
-
- if (mount(dev, "/dev/", NULL, MS_MOVE, NULL) < 0) {
- r = -errno;
- goto fail;
- }
-
- rmdir(dev);
- rmdir(temporary_mount);
-
- return 0;
-
-fail:
- if (devpts)
- umount(devpts);
-
- if (devshm)
- umount(devshm);
-
- if (devhugepages)
- umount(devhugepages);
-
- if (devmqueue)
- umount(devmqueue);
-
- umount(dev);
- rmdir(dev);
- rmdir(temporary_mount);
-
- return r;
-}
-
-static int mount_kdbus(BindMount *m) {
-
- char temporary_mount[] = "/tmp/kdbus-dev-XXXXXX";
- _cleanup_free_ char *basepath = NULL;
- _cleanup_umask_ mode_t u;
- char *busnode = NULL, *root;
- struct stat st;
- int r;
-
- assert(m);
-
- u = umask(0000);
-
- if (!mkdtemp(temporary_mount))
- return log_error_errno(errno, "Failed create temp dir: %m");
-
- root = strjoina(temporary_mount, "/kdbus");
- (void) mkdir(root, 0755);
- if (mount("tmpfs", root, "tmpfs", MS_NOSUID|MS_STRICTATIME, "mode=777") < 0) {
- r = -errno;
- goto fail;
- }
-
- /* create a new /dev/null dev node copy so we have some fodder to
- * bind-mount the custom endpoint over. */
- if (stat("/dev/null", &st) < 0) {
- log_error_errno(errno, "Failed to stat /dev/null: %m");
- r = -errno;
- goto fail;
- }
-
- busnode = strjoina(root, "/bus");
- if (mknod(busnode, (st.st_mode & ~07777) | 0600, st.st_rdev) < 0) {
- log_error_errno(errno, "mknod() for %s failed: %m", busnode);
- r = -errno;
- goto fail;
- }
-
- r = mount(m->path, busnode, NULL, MS_BIND, NULL);
- if (r < 0) {
- log_error_errno(errno, "bind mount of %s failed: %m", m->path);
- r = -errno;
- goto fail;
- }
-
- basepath = dirname_malloc(m->path);
- if (!basepath) {
- r = -ENOMEM;
- goto fail;
- }
-
- if (mount(root, basepath, NULL, MS_MOVE, NULL) < 0) {
- log_error_errno(errno, "bind mount of %s failed: %m", basepath);
- r = -errno;
- goto fail;
- }
-
- rmdir(temporary_mount);
- return 0;
-
-fail:
- if (busnode) {
- umount(busnode);
- unlink(busnode);
- }
-
- umount(root);
- rmdir(root);
- rmdir(temporary_mount);
-
- return r;
-}
-
-static int apply_mount(
- BindMount *m,
- const char *tmp_dir,
- const char *var_tmp_dir) {
-
- const char *what;
- int r;
-
- assert(m);
-
- switch (m->mode) {
-
- case INACCESSIBLE:
-
- /* First, get rid of everything that is below if there
- * is anything... Then, overmount it with an
- * inaccessible directory. */
- umount_recursive(m->path, 0);
-
- what = "/run/systemd/inaccessible";
- break;
-
- case READONLY:
- case READWRITE:
- /* Nothing to mount here, we just later toggle the
- * MS_RDONLY bit for the mount point */
- return 0;
-
- case PRIVATE_TMP:
- what = tmp_dir;
- break;
-
- case PRIVATE_VAR_TMP:
- what = var_tmp_dir;
- break;
-
- case PRIVATE_DEV:
- return mount_dev(m);
-
- case PRIVATE_BUS_ENDPOINT:
- return mount_kdbus(m);
-
- default:
- assert_not_reached("Unknown mode");
- }
-
- assert(what);
-
- r = mount(what, m->path, NULL, MS_BIND|MS_REC, NULL);
- if (r >= 0)
- log_debug("Successfully mounted %s to %s", what, m->path);
- else if (m->ignore && errno == ENOENT)
- return 0;
-
- return r;
-}
-
-static int make_read_only(BindMount *m) {
- int r;
-
- assert(m);
-
- if (IN_SET(m->mode, INACCESSIBLE, READONLY))
- r = bind_remount_recursive(m->path, true);
- else if (IN_SET(m->mode, READWRITE, PRIVATE_TMP, PRIVATE_VAR_TMP, PRIVATE_DEV))
- r = bind_remount_recursive(m->path, false);
- else
- r = 0;
-
- if (m->ignore && r == -ENOENT)
- return 0;
-
- return r;
-}
-
-int setup_namespace(
- char** read_write_dirs,
- char** read_only_dirs,
- char** inaccessible_dirs,
- const char* tmp_dir,
- const char* var_tmp_dir,
- const char* bus_endpoint_path,
- bool private_dev,
- ProtectHome protect_home,
- ProtectSystem protect_system,
- unsigned long mount_flags) {
-
- BindMount *m, *mounts = NULL;
- unsigned n;
- int r = 0;
-
- if (mount_flags == 0)
- mount_flags = MS_SHARED;
-
- if (unshare(CLONE_NEWNS) < 0)
- return -errno;
-
- n = !!tmp_dir + !!var_tmp_dir + !!bus_endpoint_path +
- strv_length(read_write_dirs) +
- strv_length(read_only_dirs) +
- strv_length(inaccessible_dirs) +
- private_dev +
- (protect_home != PROTECT_HOME_NO ? 3 : 0) +
- (protect_system != PROTECT_SYSTEM_NO ? 2 : 0) +
- (protect_system == PROTECT_SYSTEM_FULL ? 1 : 0);
-
- if (n > 0) {
- m = mounts = (BindMount *) alloca0(n * sizeof(BindMount));
- r = append_mounts(&m, read_write_dirs, READWRITE);
- if (r < 0)
- return r;
-
- r = append_mounts(&m, read_only_dirs, READONLY);
- if (r < 0)
- return r;
-
- r = append_mounts(&m, inaccessible_dirs, INACCESSIBLE);
- if (r < 0)
- return r;
-
- if (tmp_dir) {
- m->path = "/tmp";
- m->mode = PRIVATE_TMP;
- m++;
- }
-
- if (var_tmp_dir) {
- m->path = "/var/tmp";
- m->mode = PRIVATE_VAR_TMP;
- m++;
- }
-
- if (private_dev) {
- m->path = "/dev";
- m->mode = PRIVATE_DEV;
- m++;
- }
-
- if (bus_endpoint_path) {
- m->path = bus_endpoint_path;
- m->mode = PRIVATE_BUS_ENDPOINT;
- m++;
- }
-
- if (protect_home != PROTECT_HOME_NO) {
- r = append_mounts(&m, STRV_MAKE("-/home", "-/run/user", "-/root"), protect_home == PROTECT_HOME_READ_ONLY ? READONLY : INACCESSIBLE);
- if (r < 0)
- return r;
- }
-
- if (protect_system != PROTECT_SYSTEM_NO) {
- r = append_mounts(&m, protect_system == PROTECT_SYSTEM_FULL ? STRV_MAKE("/usr", "-/boot", "/etc") : STRV_MAKE("/usr", "-/boot"), READONLY);
- if (r < 0)
- return r;
- }
-
- assert(mounts + n == m);
-
- qsort(mounts, n, sizeof(BindMount), mount_path_compare);
- drop_duplicates(mounts, &n);
- }
-
- if (n > 0) {
- /* Remount / as SLAVE so that nothing now mounted in the namespace
- shows up in the parent */
- if (mount(NULL, "/", NULL, MS_SLAVE|MS_REC, NULL) < 0)
- return -errno;
-
- for (m = mounts; m < mounts + n; ++m) {
- r = apply_mount(m, tmp_dir, var_tmp_dir);
- if (r < 0)
- goto fail;
- }
-
- for (m = mounts; m < mounts + n; ++m) {
- r = make_read_only(m);
- if (r < 0)
- goto fail;
- }
- }
-
- /* Remount / as the desired mode. Not that this will not
- * reestablish propagation from our side to the host, since
- * what's disconnected is disconnected. */
- if (mount(NULL, "/", NULL, mount_flags | MS_REC, NULL) < 0) {
- r = -errno;
- goto fail;
- }
-
- return 0;
-
-fail:
- if (n > 0) {
- for (m = mounts; m < mounts + n; ++m)
- if (m->done)
- (void) umount2(m->path, MNT_DETACH);
- }
-
- return r;
-}
-
-static int setup_one_tmp_dir(const char *id, const char *prefix, char **path) {
- _cleanup_free_ char *x = NULL;
- char bid[SD_ID128_STRING_MAX];
- sd_id128_t boot_id;
- int r;
-
- assert(id);
- assert(prefix);
- assert(path);
-
- /* We include the boot id in the directory so that after a
- * reboot we can easily identify obsolete directories. */
-
- r = sd_id128_get_boot(&boot_id);
- if (r < 0)
- return r;
-
- x = strjoin(prefix, "/systemd-private-", sd_id128_to_string(boot_id, bid), "-", id, "-XXXXXX", NULL);
- if (!x)
- return -ENOMEM;
-
- RUN_WITH_UMASK(0077)
- if (!mkdtemp(x))
- return -errno;
-
- RUN_WITH_UMASK(0000) {
- char *y;
-
- y = strjoina(x, "/tmp");
-
- if (mkdir(y, 0777 | S_ISVTX) < 0)
- return -errno;
- }
-
- *path = x;
- x = NULL;
-
- return 0;
-}
-
-int setup_tmp_dirs(const char *id, char **tmp_dir, char **var_tmp_dir) {
- char *a, *b;
- int r;
-
- assert(id);
- assert(tmp_dir);
- assert(var_tmp_dir);
-
- r = setup_one_tmp_dir(id, "/tmp", &a);
- if (r < 0)
- return r;
-
- r = setup_one_tmp_dir(id, "/var/tmp", &b);
- if (r < 0) {
- char *t;
-
- t = strjoina(a, "/tmp");
- rmdir(t);
- rmdir(a);
-
- free(a);
- return r;
- }
-
- *tmp_dir = a;
- *var_tmp_dir = b;
-
- return 0;
-}
-
-int setup_netns(int netns_storage_socket[2]) {
- _cleanup_close_ int netns = -1;
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(int))];
- } control = {};
- struct msghdr mh = {
- .msg_control = &control,
- .msg_controllen = sizeof(control),
- };
- struct cmsghdr *cmsg;
- int r;
-
- assert(netns_storage_socket);
- assert(netns_storage_socket[0] >= 0);
- assert(netns_storage_socket[1] >= 0);
-
- /* We use the passed socketpair as a storage buffer for our
- * namespace reference fd. Whatever process runs this first
- * shall create a new namespace, all others should just join
- * it. To serialize that we use a file lock on the socket
- * pair.
- *
- * It's a bit crazy, but hey, works great! */
-
- if (lockf(netns_storage_socket[0], F_LOCK, 0) < 0)
- return -errno;
-
- if (recvmsg(netns_storage_socket[0], &mh, MSG_DONTWAIT|MSG_CMSG_CLOEXEC) < 0) {
- if (errno != EAGAIN) {
- r = -errno;
- goto fail;
- }
-
- /* Nothing stored yet, so let's create a new namespace */
-
- if (unshare(CLONE_NEWNET) < 0) {
- r = -errno;
- goto fail;
- }
-
- loopback_setup();
-
- netns = open("/proc/self/ns/net", O_RDONLY|O_CLOEXEC|O_NOCTTY);
- if (netns < 0) {
- r = -errno;
- goto fail;
- }
-
- r = 1;
- } else {
- /* Yay, found something, so let's join the namespace */
-
- for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) {
- if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
- assert(cmsg->cmsg_len == CMSG_LEN(sizeof(int)));
- netns = *(int*) CMSG_DATA(cmsg);
- }
- }
-
- if (setns(netns, CLONE_NEWNET) < 0) {
- r = -errno;
- goto fail;
- }
-
- r = 0;
- }
-
- cmsg = CMSG_FIRSTHDR(&mh);
- cmsg->cmsg_level = SOL_SOCKET;
- cmsg->cmsg_type = SCM_RIGHTS;
- cmsg->cmsg_len = CMSG_LEN(sizeof(int));
- memcpy(CMSG_DATA(cmsg), &netns, sizeof(int));
- mh.msg_controllen = cmsg->cmsg_len;
-
- if (sendmsg(netns_storage_socket[1], &mh, MSG_DONTWAIT|MSG_NOSIGNAL) < 0) {
- r = -errno;
- goto fail;
- }
-
-fail:
- lockf(netns_storage_socket[0], F_ULOCK, 0);
-
- return r;
-}
-
-static const char *const protect_home_table[_PROTECT_HOME_MAX] = {
- [PROTECT_HOME_NO] = "no",
- [PROTECT_HOME_YES] = "yes",
- [PROTECT_HOME_READ_ONLY] = "read-only",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(protect_home, ProtectHome);
-
-static const char *const protect_system_table[_PROTECT_SYSTEM_MAX] = {
- [PROTECT_SYSTEM_NO] = "no",
- [PROTECT_SYSTEM_YES] = "yes",
- [PROTECT_SYSTEM_FULL] = "full",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(protect_system, ProtectSystem);
diff --git a/src/core/namespace.h b/src/core/namespace.h
deleted file mode 100644
index 42b92e780..000000000
--- a/src/core/namespace.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 "macro.h"
-
-typedef enum ProtectHome {
- PROTECT_HOME_NO,
- PROTECT_HOME_YES,
- PROTECT_HOME_READ_ONLY,
- _PROTECT_HOME_MAX,
- _PROTECT_HOME_INVALID = -1
-} ProtectHome;
-
-typedef enum ProtectSystem {
- PROTECT_SYSTEM_NO,
- PROTECT_SYSTEM_YES,
- PROTECT_SYSTEM_FULL,
- _PROTECT_SYSTEM_MAX,
- _PROTECT_SYSTEM_INVALID = -1
-} ProtectSystem;
-
-int setup_namespace(char **read_write_dirs,
- char **read_only_dirs,
- char **inaccessible_dirs,
- const char *tmp_dir,
- const char *var_tmp_dir,
- const char *endpoint_path,
- bool private_dev,
- ProtectHome protect_home,
- ProtectSystem protect_system,
- unsigned long mount_flags);
-
-int setup_tmp_dirs(const char *id,
- char **tmp_dir,
- char **var_tmp_dir);
-
-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_;
-
-const char* protect_system_to_string(ProtectSystem p) _const_;
-ProtectSystem protect_system_from_string(const char *s) _pure_;
diff --git a/src/core/org.freedesktop.systemd1.conf b/src/core/org.freedesktop.systemd1.conf
deleted file mode 100644
index 6a7a37ee9..000000000
--- a/src/core/org.freedesktop.systemd1.conf
+++ /dev/null
@@ -1,212 +0,0 @@
-<?xml version="1.0"?> <!--*-nxml-*-->
-<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
- "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
-
-<!--
- This file is part of systemd.
-
- 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.
--->
-
-<busconfig>
-
- <policy user="root">
- <allow own="org.freedesktop.systemd1"/>
-
- <!-- Root clients can do everything -->
- <allow send_destination="org.freedesktop.systemd1"/>
- <allow receive_sender="org.freedesktop.systemd1"/>
-
- <!-- systemd may receive activator requests -->
- <allow receive_interface="org.freedesktop.systemd1.Activator"
- receive_member="ActivationRequest"/>
- </policy>
-
- <policy context="default">
- <deny send_destination="org.freedesktop.systemd1"/>
-
- <!-- Completely open to anyone -->
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.DBus.Introspectable"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.DBus.Peer"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.DBus.Properties"
- send_member="Get"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.DBus.Properties"
- send_member="GetAll"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="GetUnit"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="GetUnitByPID"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="LoadUnit"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="GetJob"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="ListUnits"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="ListUnitsFiltered"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="ListUnitFiles"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="GetUnitFileState"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="ListJobs"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="Subscribe"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="Unsubscribe"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="Dump"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="GetDefaultTarget"/>
-
- <!-- Managed via polkit or other criteria -->
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="StartUnit"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="StartUnitReplace"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="StopUnit"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="ReloadUnit"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="RestartUnit"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="TryRestartUnit"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="ReloadOrRestartUnit"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="ReloadOrTryRestartUnit"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="KillUnit"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="ResetFailedUnit"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="SetUnitProperties"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="StartTransientUnit"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="CancelJob"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="Reload"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="Reexecute"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="EnableUnitFiles"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="DisableUnitFiles"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="ReenableUnitFiles"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="LinkUnitFiles"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="PresetUnitFiles"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="PresetUnitFilesWithMode"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="MaskUnitFiles"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="UnmaskUnitFiles"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="SetDefaultTarget"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="PresetAllUnitFiles"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Manager"
- send_member="AddDependencyUnitFiles"/>
-
- <allow send_destination="org.freedesktop.systemd1"
- send_interface="org.freedesktop.systemd1.Job"
- send_member="Cancel"/>
-
- <allow receive_sender="org.freedesktop.systemd1"/>
- </policy>
-
-</busconfig>
diff --git a/src/core/org.freedesktop.systemd1.policy.in.in b/src/core/org.freedesktop.systemd1.policy.in.in
deleted file mode 100644
index cc39a9e1c..000000000
--- a/src/core/org.freedesktop.systemd1.policy.in.in
+++ /dev/null
@@ -1,70 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?> <!--*-nxml-*-->
-<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
- "http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
-
-<!--
- This file is part of systemd.
-
- 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.
--->
-
-<policyconfig>
-
- <vendor>The systemd Project</vendor>
- <vendor_url>http://www.freedesktop.org/wiki/Software/systemd</vendor_url>
-
- <action id="org.freedesktop.systemd1.reply-password">
- <_description>Send passphrase back to system</_description>
- <_message>Authentication is required to send the entered passphrase back to the system.</_message>
- <defaults>
- <allow_any>no</allow_any>
- <allow_inactive>no</allow_inactive>
- <allow_active>auth_admin_keep</allow_active>
- </defaults>
- <annotate key="org.freedesktop.policykit.exec.path">@rootlibexecdir@/systemd-reply-password</annotate>
- </action>
-
- <action id="org.freedesktop.systemd1.manage-units">
- <_description>Manage system services or other units</_description>
- <_message>Authentication is required to manage system services or other units.</_message>
- <defaults>
- <allow_any>auth_admin</allow_any>
- <allow_inactive>auth_admin</allow_inactive>
- <allow_active>auth_admin_keep</allow_active>
- </defaults>
- </action>
-
- <action id="org.freedesktop.systemd1.manage-unit-files">
- <_description>Manage system service or unit files</_description>
- <_message>Authentication is required to manage system service or unit files.</_message>
- <defaults>
- <allow_any>auth_admin</allow_any>
- <allow_inactive>auth_admin</allow_inactive>
- <allow_active>auth_admin_keep</allow_active>
- </defaults>
- </action>
-
- <action id="org.freedesktop.systemd1.set-environment">
- <_description>Set or unset system and service manager environment variables</_description>
- <_message>Authentication is required to set or unset system and service manager environment variables.</_message>
- <defaults>
- <allow_any>auth_admin</allow_any>
- <allow_inactive>auth_admin</allow_inactive>
- <allow_active>auth_admin_keep</allow_active>
- </defaults>
- </action>
-
- <action id="org.freedesktop.systemd1.reload-daemon">
- <_description>Reload the systemd state</_description>
- <_message>Authentication is required to reload the systemd state.</_message>
- <defaults>
- <allow_any>auth_admin</allow_any>
- <allow_inactive>auth_admin</allow_inactive>
- <allow_active>auth_admin_keep</allow_active>
- </defaults>
- </action>
-
-</policyconfig>
diff --git a/src/core/org.freedesktop.systemd1.service b/src/core/org.freedesktop.systemd1.service
deleted file mode 100644
index d4df3e93a..000000000
--- a/src/core/org.freedesktop.systemd1.service
+++ /dev/null
@@ -1,11 +0,0 @@
-# This file is part of systemd.
-#
-# 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.
-
-[D-BUS Service]
-Name=org.freedesktop.systemd1
-Exec=/bin/false
-User=root
diff --git a/src/core/path.c b/src/core/path.c
deleted file mode 100644
index 6be9ac84b..000000000
--- a/src/core/path.c
+++ /dev/null
@@ -1,789 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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/inotify.h>
-#include <sys/epoll.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include "unit.h"
-#include "unit-name.h"
-#include "path.h"
-#include "mkdir.h"
-#include "dbus-path.h"
-#include "special.h"
-#include "macro.h"
-#include "bus-util.h"
-#include "bus-error.h"
-
-static const UnitActiveState state_translation_table[_PATH_STATE_MAX] = {
- [PATH_DEAD] = UNIT_INACTIVE,
- [PATH_WAITING] = UNIT_ACTIVE,
- [PATH_RUNNING] = UNIT_ACTIVE,
- [PATH_FAILED] = UNIT_FAILED
-};
-
-static int path_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
-
-int path_spec_watch(PathSpec *s, sd_event_io_handler_t handler) {
-
- static const int flags_table[_PATH_TYPE_MAX] = {
- [PATH_EXISTS] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB,
- [PATH_EXISTS_GLOB] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB,
- [PATH_CHANGED] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CLOSE_WRITE|IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO,
- [PATH_MODIFIED] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CLOSE_WRITE|IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO|IN_MODIFY,
- [PATH_DIRECTORY_NOT_EMPTY] = IN_DELETE_SELF|IN_MOVE_SELF|IN_ATTRIB|IN_CREATE|IN_MOVED_TO
- };
-
- bool exists = false;
- char *slash, *oldslash = NULL;
- int r;
-
- assert(s);
- assert(s->unit);
- assert(handler);
-
- path_spec_unwatch(s);
-
- s->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
- if (s->inotify_fd < 0) {
- r = -errno;
- goto fail;
- }
-
- r = sd_event_add_io(s->unit->manager->event, &s->event_source, s->inotify_fd, EPOLLIN, handler, s);
- if (r < 0)
- goto fail;
-
- /* This assumes the path was passed through path_kill_slashes()! */
-
- for (slash = strchr(s->path, '/'); ; slash = strchr(slash+1, '/')) {
- char *cut = NULL;
- int flags;
- char tmp;
-
- if (slash) {
- cut = slash + (slash == s->path);
- tmp = *cut;
- *cut = '\0';
-
- flags = IN_MOVE_SELF | IN_DELETE_SELF | IN_ATTRIB | IN_CREATE | IN_MOVED_TO;
- } else
- flags = flags_table[s->type];
-
- r = inotify_add_watch(s->inotify_fd, s->path, flags);
- if (r < 0) {
- if (errno == EACCES || errno == ENOENT) {
- if (cut)
- *cut = tmp;
- break;
- }
-
- log_warning("Failed to add watch on %s: %s", s->path,
- errno == ENOSPC ? "too many watches" : strerror(-r));
- r = -errno;
- if (cut)
- *cut = tmp;
- goto fail;
- } else {
- exists = true;
-
- /* Path exists, we don't need to watch parent
- too closely. */
- if (oldslash) {
- char *cut2 = oldslash + (oldslash == s->path);
- char tmp2 = *cut2;
- *cut2 = '\0';
-
- inotify_add_watch(s->inotify_fd, s->path, IN_MOVE_SELF);
- /* Error is ignored, the worst can happen is
- we get spurious events. */
-
- *cut2 = tmp2;
- }
- }
-
- if (cut)
- *cut = tmp;
-
- if (slash)
- oldslash = slash;
- else {
- /* whole path has been iterated over */
- s->primary_wd = r;
- break;
- }
- }
-
- if (!exists) {
- log_error_errno(errno, "Failed to add watch on any of the components of %s: %m",
- s->path);
- r = -errno; /* either EACCESS or ENOENT */
- goto fail;
- }
-
- return 0;
-
-fail:
- path_spec_unwatch(s);
- return r;
-}
-
-void path_spec_unwatch(PathSpec *s) {
- assert(s);
-
- s->event_source = sd_event_source_unref(s->event_source);
- s->inotify_fd = safe_close(s->inotify_fd);
-}
-
-int path_spec_fd_event(PathSpec *s, uint32_t revents) {
- union inotify_event_buffer buffer;
- struct inotify_event *e;
- ssize_t l;
- int r = 0;
-
- if (revents != EPOLLIN) {
- log_error("Got invalid poll event on inotify.");
- return -EINVAL;
- }
-
- l = read(s->inotify_fd, &buffer, sizeof(buffer));
- if (l < 0) {
- if (errno == EAGAIN || errno == EINTR)
- return 0;
-
- return log_error_errno(errno, "Failed to read inotify event: %m");
- }
-
- FOREACH_INOTIFY_EVENT(e, buffer, l) {
- if ((s->type == PATH_CHANGED || s->type == PATH_MODIFIED) &&
- s->primary_wd == e->wd)
- r = 1;
- }
-
- return r;
-}
-
-static bool path_spec_check_good(PathSpec *s, bool initial) {
- bool good = false;
-
- switch (s->type) {
-
- case PATH_EXISTS:
- good = access(s->path, F_OK) >= 0;
- break;
-
- case PATH_EXISTS_GLOB:
- good = glob_exists(s->path) > 0;
- break;
-
- case PATH_DIRECTORY_NOT_EMPTY: {
- int k;
-
- k = dir_is_empty(s->path);
- good = !(k == -ENOENT || k > 0);
- break;
- }
-
- case PATH_CHANGED:
- case PATH_MODIFIED: {
- bool b;
-
- b = access(s->path, F_OK) >= 0;
- good = !initial && b != s->previous_exists;
- s->previous_exists = b;
- break;
- }
-
- default:
- ;
- }
-
- return good;
-}
-
-static void path_spec_mkdir(PathSpec *s, mode_t mode) {
- int r;
-
- if (s->type == PATH_EXISTS || s->type == PATH_EXISTS_GLOB)
- return;
-
- r = mkdir_p_label(s->path, mode);
- if (r < 0)
- log_warning_errno(r, "mkdir(%s) failed: %m", s->path);
-}
-
-static void path_spec_dump(PathSpec *s, FILE *f, const char *prefix) {
- fprintf(f,
- "%s%s: %s\n",
- prefix,
- path_type_to_string(s->type),
- s->path);
-}
-
-void path_spec_done(PathSpec *s) {
- assert(s);
- assert(s->inotify_fd == -1);
-
- free(s->path);
-}
-
-static void path_init(Unit *u) {
- Path *p = PATH(u);
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
-
- p->directory_mode = 0755;
-}
-
-void path_free_specs(Path *p) {
- PathSpec *s;
-
- assert(p);
-
- while ((s = p->specs)) {
- path_spec_unwatch(s);
- LIST_REMOVE(spec, p->specs, s);
- path_spec_done(s);
- free(s);
- }
-}
-
-static void path_done(Unit *u) {
- Path *p = PATH(u);
-
- assert(p);
-
- path_free_specs(p);
-}
-
-static int path_add_mount_links(Path *p) {
- PathSpec *s;
- int r;
-
- assert(p);
-
- LIST_FOREACH(spec, s, p->specs) {
- r = unit_require_mounts_for(UNIT(p), s->path);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-static int path_verify(Path *p) {
- assert(p);
-
- if (UNIT(p)->load_state != UNIT_LOADED)
- return 0;
-
- if (!p->specs) {
- log_unit_error(UNIT(p)->id,
- "%s lacks path setting. Refusing.", UNIT(p)->id);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int path_add_default_dependencies(Path *p) {
- int r;
-
- assert(p);
-
- r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE,
- SPECIAL_PATHS_TARGET, NULL, true);
- if (r < 0)
- return r;
-
- if (UNIT(p)->manager->running_as == SYSTEMD_SYSTEM) {
- r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES,
- SPECIAL_SYSINIT_TARGET, NULL, true);
- if (r < 0)
- return r;
- }
-
- return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS,
- SPECIAL_SHUTDOWN_TARGET, NULL, true);
-}
-
-static int path_load(Unit *u) {
- Path *p = PATH(u);
- int r;
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
-
- r = unit_load_fragment_and_dropin(u);
- if (r < 0)
- return r;
-
- if (u->load_state == UNIT_LOADED) {
-
- if (set_isempty(u->dependencies[UNIT_TRIGGERS])) {
- Unit *x;
-
- r = unit_load_related_unit(u, ".service", &x);
- if (r < 0)
- return r;
-
- r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true);
- if (r < 0)
- return r;
- }
-
- r = path_add_mount_links(p);
- if (r < 0)
- return r;
-
- if (UNIT(p)->default_dependencies) {
- r = path_add_default_dependencies(p);
- if (r < 0)
- return r;
- }
- }
-
- return path_verify(p);
-}
-
-static void path_dump(Unit *u, FILE *f, const char *prefix) {
- Path *p = PATH(u);
- Unit *trigger;
- PathSpec *s;
-
- assert(p);
- assert(f);
-
- trigger = UNIT_TRIGGER(u);
-
- fprintf(f,
- "%sPath State: %s\n"
- "%sResult: %s\n"
- "%sUnit: %s\n"
- "%sMakeDirectory: %s\n"
- "%sDirectoryMode: %04o\n",
- prefix, path_state_to_string(p->state),
- prefix, path_result_to_string(p->result),
- prefix, trigger ? trigger->id : "n/a",
- prefix, yes_no(p->make_directory),
- prefix, p->directory_mode);
-
- LIST_FOREACH(spec, s, p->specs)
- path_spec_dump(s, f, prefix);
-}
-
-static void path_unwatch(Path *p) {
- PathSpec *s;
-
- assert(p);
-
- LIST_FOREACH(spec, s, p->specs)
- path_spec_unwatch(s);
-}
-
-static int path_watch(Path *p) {
- int r;
- PathSpec *s;
-
- assert(p);
-
- LIST_FOREACH(spec, s, p->specs) {
- r = path_spec_watch(s, path_dispatch_io);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-static void path_set_state(Path *p, PathState state) {
- PathState old_state;
- assert(p);
-
- old_state = p->state;
- p->state = state;
-
- if (state != PATH_WAITING &&
- (state != PATH_RUNNING || p->inotify_triggered))
- path_unwatch(p);
-
- if (state != old_state)
- log_debug("%s changed %s -> %s",
- UNIT(p)->id,
- 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);
-}
-
-static void path_enter_waiting(Path *p, bool initial, bool recheck);
-
-static int path_enter_waiting_coldplug(Unit *u) {
- path_enter_waiting(PATH(u), true, true);
- return 0;
-}
-
-static int path_coldplug(Unit *u, Hashmap *deferred_work) {
- Path *p = PATH(u);
-
- assert(p);
- assert(p->state == PATH_DEAD);
-
- if (p->deserialized_state != p->state) {
-
- if (p->deserialized_state == PATH_WAITING ||
- p->deserialized_state == PATH_RUNNING) {
- hashmap_put(deferred_work, u, &path_enter_waiting_coldplug);
- path_set_state(p, PATH_WAITING);
- } else
- path_set_state(p, p->deserialized_state);
- }
-
- return 0;
-}
-
-static void path_enter_dead(Path *p, PathResult f) {
- assert(p);
-
- if (f != PATH_SUCCESS)
- p->result = f;
-
- path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD);
-}
-
-static void path_enter_running(Path *p) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- int r;
-
- assert(p);
-
- /* Don't start job if we are supposed to go down */
- if (unit_stop_pending(UNIT(p)))
- return;
-
- r = manager_add_job(UNIT(p)->manager, JOB_START, UNIT_TRIGGER(UNIT(p)),
- JOB_REPLACE, true, &error, NULL);
- if (r < 0)
- goto fail;
-
- p->inotify_triggered = false;
-
- r = path_watch(p);
- if (r < 0)
- goto fail;
-
- path_set_state(p, PATH_RUNNING);
- return;
-
-fail:
- log_warning("%s failed to queue unit startup job: %s",
- UNIT(p)->id, bus_error_message(&error, r));
- path_enter_dead(p, PATH_FAILURE_RESOURCES);
-}
-
-static bool path_check_good(Path *p, bool initial) {
- PathSpec *s;
- bool good = false;
-
- assert(p);
-
- LIST_FOREACH(spec, s, p->specs) {
- good = path_spec_check_good(s, initial);
-
- if (good)
- break;
- }
-
- return good;
-}
-
-static void path_enter_waiting(Path *p, bool initial, bool recheck) {
- int r;
-
- if (recheck)
- if (path_check_good(p, initial)) {
- log_debug("%s got triggered.", UNIT(p)->id);
- path_enter_running(p);
- return;
- }
-
- r = path_watch(p);
- if (r < 0)
- goto fail;
-
- /* Hmm, so now we have created inotify watches, but the file
- * might have appeared/been removed by now, so we must
- * recheck */
-
- if (recheck)
- if (path_check_good(p, false)) {
- log_debug("%s got triggered.", UNIT(p)->id);
- path_enter_running(p);
- return;
- }
-
- path_set_state(p, PATH_WAITING);
- return;
-
-fail:
- log_warning_errno(r, "%s failed to enter waiting state: %m", UNIT(p)->id);
- path_enter_dead(p, PATH_FAILURE_RESOURCES);
-}
-
-static void path_mkdir(Path *p) {
- PathSpec *s;
-
- assert(p);
-
- if (!p->make_directory)
- return;
-
- LIST_FOREACH(spec, s, p->specs)
- path_spec_mkdir(s, p->directory_mode);
-}
-
-static int path_start(Unit *u) {
- Path *p = PATH(u);
-
- assert(p);
- assert(p->state == PATH_DEAD || p->state == PATH_FAILED);
-
- if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED)
- return -ENOENT;
-
- path_mkdir(p);
-
- p->result = PATH_SUCCESS;
- path_enter_waiting(p, true, true);
-
- return 1;
-}
-
-static int path_stop(Unit *u) {
- Path *p = PATH(u);
-
- assert(p);
- assert(p->state == PATH_WAITING || p->state == PATH_RUNNING);
-
- path_enter_dead(p, PATH_SUCCESS);
- return 1;
-}
-
-static int path_serialize(Unit *u, FILE *f, FDSet *fds) {
- Path *p = PATH(u);
-
- assert(u);
- assert(f);
- assert(fds);
-
- unit_serialize_item(u, f, "state", path_state_to_string(p->state));
- unit_serialize_item(u, f, "result", path_result_to_string(p->result));
-
- return 0;
-}
-
-static int path_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Path *p = PATH(u);
-
- assert(u);
- assert(key);
- assert(value);
- assert(fds);
-
- if (streq(key, "state")) {
- PathState state;
-
- state = path_state_from_string(value);
- if (state < 0)
- log_debug("Failed to parse state value %s", value);
- else
- p->deserialized_state = state;
-
- } else if (streq(key, "result")) {
- PathResult f;
-
- f = path_result_from_string(value);
- if (f < 0)
- log_debug("Failed to parse result value %s", value);
- else if (f != PATH_SUCCESS)
- p->result = f;
-
- } else
- log_debug("Unknown serialization key '%s'", key);
-
- return 0;
-}
-
-_pure_ static UnitActiveState path_active_state(Unit *u) {
- assert(u);
-
- return state_translation_table[PATH(u)->state];
-}
-
-_pure_ static const char *path_sub_state_to_string(Unit *u) {
- assert(u);
-
- return path_state_to_string(PATH(u)->state);
-}
-
-static int path_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
- PathSpec *s = userdata;
- Path *p;
- int changed;
-
- assert(s);
- assert(s->unit);
- assert(fd >= 0);
-
- p = PATH(s->unit);
-
- if (p->state != PATH_WAITING &&
- p->state != PATH_RUNNING)
- return 0;
-
- /* log_debug("inotify wakeup on %s.", u->id); */
-
- LIST_FOREACH(spec, s, p->specs)
- if (path_spec_owns_inotify_fd(s, fd))
- break;
-
- if (!s) {
- log_error("Got event on unknown fd.");
- goto fail;
- }
-
- changed = path_spec_fd_event(s, revents);
- if (changed < 0)
- goto fail;
-
- /* If we are already running, then remember that one event was
- * dispatched so that we restart the service only if something
- * actually changed on disk */
- p->inotify_triggered = true;
-
- if (changed)
- path_enter_running(p);
- else
- path_enter_waiting(p, false, true);
-
- return 0;
-
-fail:
- path_enter_dead(p, PATH_FAILURE_RESOURCES);
- return 0;
-}
-
-static void path_trigger_notify(Unit *u, Unit *other) {
- Path *p = PATH(u);
-
- assert(u);
- assert(other);
-
- /* Invoked whenever the unit we trigger changes state or gains
- * or loses a job */
-
- if (other->load_state != UNIT_LOADED)
- return;
-
- if (p->state == PATH_RUNNING &&
- UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
- log_unit_debug(UNIT(p)->id,
- "%s got notified about unit deactivation.",
- UNIT(p)->id);
-
- /* Hmm, so inotify was triggered since the
- * last activation, so I guess we need to
- * recheck what is going on. */
- path_enter_waiting(p, false, p->inotify_triggered);
- }
-}
-
-static void path_reset_failed(Unit *u) {
- Path *p = PATH(u);
-
- assert(p);
-
- if (p->state == PATH_FAILED)
- path_set_state(p, PATH_DEAD);
-
- p->result = PATH_SUCCESS;
-}
-
-static const char* const path_state_table[_PATH_STATE_MAX] = {
- [PATH_DEAD] = "dead",
- [PATH_WAITING] = "waiting",
- [PATH_RUNNING] = "running",
- [PATH_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(path_state, PathState);
-
-static const char* const path_type_table[_PATH_TYPE_MAX] = {
- [PATH_EXISTS] = "PathExists",
- [PATH_EXISTS_GLOB] = "PathExistsGlob",
- [PATH_DIRECTORY_NOT_EMPTY] = "DirectoryNotEmpty",
- [PATH_CHANGED] = "PathChanged",
- [PATH_MODIFIED] = "PathModified",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(path_type, PathType);
-
-static const char* const path_result_table[_PATH_RESULT_MAX] = {
- [PATH_SUCCESS] = "success",
- [PATH_FAILURE_RESOURCES] = "resources",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(path_result, PathResult);
-
-const UnitVTable path_vtable = {
- .object_size = sizeof(Path),
-
- .sections =
- "Unit\0"
- "Path\0"
- "Install\0",
-
- .init = path_init,
- .done = path_done,
- .load = path_load,
-
- .coldplug = path_coldplug,
-
- .dump = path_dump,
-
- .start = path_start,
- .stop = path_stop,
-
- .serialize = path_serialize,
- .deserialize_item = path_deserialize_item,
-
- .active_state = path_active_state,
- .sub_state_to_string = path_sub_state_to_string,
-
- .trigger_notify = path_trigger_notify,
-
- .reset_failed = path_reset_failed,
-
- .bus_interface = "org.freedesktop.systemd1.Path",
- .bus_vtable = bus_path_vtable
-};
diff --git a/src/core/path.h b/src/core/path.h
deleted file mode 100644
index dec39333e..000000000
--- a/src/core/path.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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;
-
-#include "unit.h"
-
-typedef enum PathState {
- PATH_DEAD,
- PATH_WAITING,
- PATH_RUNNING,
- PATH_FAILED,
- _PATH_STATE_MAX,
- _PATH_STATE_INVALID = -1
-} PathState;
-
-typedef enum PathType {
- PATH_EXISTS,
- PATH_EXISTS_GLOB,
- PATH_DIRECTORY_NOT_EMPTY,
- PATH_CHANGED,
- PATH_MODIFIED,
- _PATH_TYPE_MAX,
- _PATH_TYPE_INVALID = -1
-} PathType;
-
-typedef struct PathSpec {
- Unit *unit;
-
- char *path;
-
- sd_event_source *event_source;
-
- LIST_FIELDS(struct PathSpec, spec);
-
- PathType type;
- int inotify_fd;
- int primary_wd;
-
- bool previous_exists;
-} PathSpec;
-
-int path_spec_watch(PathSpec *s, sd_event_io_handler_t handler);
-void path_spec_unwatch(PathSpec *s);
-int path_spec_fd_event(PathSpec *s, uint32_t events);
-void path_spec_done(PathSpec *s);
-
-static inline bool path_spec_owns_inotify_fd(PathSpec *s, int fd) {
- return s->inotify_fd == fd;
-}
-
-typedef enum PathResult {
- PATH_SUCCESS,
- PATH_FAILURE_RESOURCES,
- _PATH_RESULT_MAX,
- _PATH_RESULT_INVALID = -1
-} PathResult;
-
-struct Path {
- Unit meta;
-
- LIST_HEAD(PathSpec, specs);
-
- PathState state, deserialized_state;
-
- bool inotify_triggered;
-
- bool make_directory;
- mode_t directory_mode;
-
- PathResult result;
-};
-
-void path_free_specs(Path *p);
-
-extern const UnitVTable path_vtable;
-
-const char* path_state_to_string(PathState i) _const_;
-PathState path_state_from_string(const char *s) _pure_;
-
-const char* path_type_to_string(PathType i) _const_;
-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_;
diff --git a/src/core/scope.c b/src/core/scope.c
deleted file mode 100644
index 8b2bb29ed..000000000
--- a/src/core/scope.c
+++ /dev/null
@@ -1,561 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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>
-
-#include "unit.h"
-#include "scope.h"
-#include "log.h"
-#include "dbus-scope.h"
-#include "special.h"
-#include "unit-name.h"
-#include "load-dropin.h"
-
-static const UnitActiveState state_translation_table[_SCOPE_STATE_MAX] = {
- [SCOPE_DEAD] = UNIT_INACTIVE,
- [SCOPE_RUNNING] = UNIT_ACTIVE,
- [SCOPE_ABANDONED] = UNIT_ACTIVE,
- [SCOPE_STOP_SIGTERM] = UNIT_DEACTIVATING,
- [SCOPE_STOP_SIGKILL] = UNIT_DEACTIVATING,
- [SCOPE_FAILED] = UNIT_FAILED
-};
-
-static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
-
-static void scope_init(Unit *u) {
- Scope *s = SCOPE(u);
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
-
- s->timeout_stop_usec = u->manager->default_timeout_stop_usec;
-
- UNIT(s)->ignore_on_isolate = true;
- UNIT(s)->ignore_on_snapshot = true;
-}
-
-static void scope_done(Unit *u) {
- Scope *s = SCOPE(u);
-
- assert(u);
-
- free(s->controller);
-
- s->timer_event_source = sd_event_source_unref(s->timer_event_source);
-}
-
-static int scope_arm_timer(Scope *s) {
- int r;
-
- assert(s);
-
- if (s->timeout_stop_usec <= 0) {
- s->timer_event_source = sd_event_source_unref(s->timer_event_source);
- return 0;
- }
-
- if (s->timer_event_source) {
- r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_stop_usec);
- if (r < 0)
- return r;
-
- return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
- }
-
- return sd_event_add_time(
- UNIT(s)->manager->event,
- &s->timer_event_source,
- CLOCK_MONOTONIC,
- now(CLOCK_MONOTONIC) + s->timeout_stop_usec, 0,
- scope_dispatch_timer, s);
-}
-
-static void scope_set_state(Scope *s, ScopeState state) {
- ScopeState old_state;
- assert(s);
-
- old_state = s->state;
- s->state = 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))
- unit_unwatch_all_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);
-}
-
-static int scope_add_default_dependencies(Scope *s) {
- int r;
-
- assert(s);
-
- /* Make sure scopes are unloaded on shutdown */
- r = unit_add_two_dependencies_by_name(
- UNIT(s),
- UNIT_BEFORE, UNIT_CONFLICTS,
- SPECIAL_SHUTDOWN_TARGET, NULL, true);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-static int scope_verify(Scope *s) {
- assert(s);
-
- if (UNIT(s)->load_state != UNIT_LOADED)
- return 0;
-
- if (set_isempty(UNIT(s)->pids) && UNIT(s)->manager->n_reloading <= 0) {
- log_unit_error(UNIT(s)->id, "Scope %s has no PIDs. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int scope_load(Unit *u) {
- Scope *s = SCOPE(u);
- int r;
-
- assert(s);
- assert(u->load_state == UNIT_STUB);
-
- if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
- return -ENOENT;
-
- u->load_state = UNIT_LOADED;
-
- r = unit_load_dropin(u);
- if (r < 0)
- return r;
-
- r = unit_patch_contexts(u);
- if (r < 0)
- return r;
-
- r = unit_add_default_slice(u, &s->cgroup_context);
- if (r < 0)
- return r;
-
- if (u->default_dependencies) {
- r = scope_add_default_dependencies(s);
- if (r < 0)
- return r;
- }
-
- return scope_verify(s);
-}
-
-static int scope_coldplug(Unit *u, Hashmap *deferred_work) {
- Scope *s = SCOPE(u);
- int r;
-
- assert(s);
- assert(s->state == SCOPE_DEAD);
-
- if (s->deserialized_state != s->state) {
-
- if (IN_SET(s->deserialized_state, SCOPE_STOP_SIGKILL, SCOPE_STOP_SIGTERM)) {
- r = scope_arm_timer(s);
- if (r < 0)
- return r;
- }
-
- if (!IN_SET(s->deserialized_state, SCOPE_DEAD, SCOPE_FAILED))
- unit_watch_all_pids(UNIT(s));
-
- scope_set_state(s, s->deserialized_state);
- }
-
- return 0;
-}
-
-static void scope_dump(Unit *u, FILE *f, const char *prefix) {
- Scope *s = SCOPE(u);
-
- assert(s);
- assert(f);
-
- fprintf(f,
- "%sScope State: %s\n"
- "%sResult: %s\n",
- prefix, scope_state_to_string(s->state),
- prefix, scope_result_to_string(s->result));
-
- cgroup_context_dump(&s->cgroup_context, f, prefix);
- kill_context_dump(&s->kill_context, f, prefix);
-}
-
-static void scope_enter_dead(Scope *s, ScopeResult f) {
- assert(s);
-
- if (f != SCOPE_SUCCESS)
- s->result = f;
-
- scope_set_state(s, s->result != SCOPE_SUCCESS ? SCOPE_FAILED : SCOPE_DEAD);
-}
-
-static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) {
- bool skip_signal = false;
- int r;
-
- assert(s);
-
- if (f != SCOPE_SUCCESS)
- s->result = f;
-
- unit_watch_all_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 beserk mode */
- if (state == SCOPE_STOP_SIGTERM)
- skip_signal = bus_scope_send_request_stop(s) > 0;
-
- if (!skip_signal) {
- r = unit_kill_context(
- UNIT(s),
- &s->kill_context,
- state != SCOPE_STOP_SIGTERM ? KILL_KILL : KILL_TERMINATE,
- -1, -1, false);
- if (r < 0)
- goto fail;
- } else
- r = 1;
-
- if (r > 0) {
- r = scope_arm_timer(s);
- if (r < 0)
- goto fail;
-
- scope_set_state(s, state);
- } else if (state == SCOPE_STOP_SIGTERM)
- scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_SUCCESS);
- else
- scope_enter_dead(s, SCOPE_SUCCESS);
-
- return;
-
-fail:
- log_unit_warning(UNIT(s)->id,
- "%s failed to kill processes: %s", UNIT(s)->id, strerror(-r));
-
- scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
-}
-
-static int scope_start(Unit *u) {
- Scope *s = SCOPE(u);
- int r;
-
- assert(s);
-
- if (s->state == SCOPE_FAILED)
- return -EPERM;
-
- if (s->state == SCOPE_STOP_SIGTERM ||
- s->state == SCOPE_STOP_SIGKILL)
- return -EAGAIN;
-
- assert(s->state == SCOPE_DEAD);
-
- if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
- return -ENOENT;
-
- (void) unit_realize_cgroup(u);
- (void) unit_reset_cpu_usage(u);
-
- r = unit_attach_pids_to_cgroup(u);
- if (r < 0)
- return r;
-
- s->result = SCOPE_SUCCESS;
-
- scope_set_state(s, SCOPE_RUNNING);
- return 1;
-}
-
-static int scope_stop(Unit *u) {
- Scope *s = SCOPE(u);
-
- assert(s);
-
- if (s->state == SCOPE_STOP_SIGTERM ||
- s->state == SCOPE_STOP_SIGKILL)
- return 0;
-
- assert(s->state == SCOPE_RUNNING ||
- s->state == SCOPE_ABANDONED);
-
- scope_enter_signal(s, SCOPE_STOP_SIGTERM, SCOPE_SUCCESS);
- return 1;
-}
-
-static void scope_reset_failed(Unit *u) {
- Scope *s = SCOPE(u);
-
- assert(s);
-
- if (s->state == SCOPE_FAILED)
- scope_set_state(s, SCOPE_DEAD);
-
- s->result = SCOPE_SUCCESS;
-}
-
-static int scope_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
- return unit_kill_common(u, who, signo, -1, -1, error);
-}
-
-static int scope_get_timeout(Unit *u, uint64_t *timeout) {
- Scope *s = SCOPE(u);
- int r;
-
- if (!s->timer_event_source)
- return 0;
-
- r = sd_event_source_get_time(s->timer_event_source, timeout);
- if (r < 0)
- return r;
-
- return 1;
-}
-
-static int scope_serialize(Unit *u, FILE *f, FDSet *fds) {
- Scope *s = SCOPE(u);
-
- assert(s);
- assert(f);
- assert(fds);
-
- unit_serialize_item(u, f, "state", scope_state_to_string(s->state));
- return 0;
-}
-
-static int scope_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Scope *s = SCOPE(u);
-
- assert(u);
- assert(key);
- assert(value);
- assert(fds);
-
- if (streq(key, "state")) {
- ScopeState state;
-
- state = scope_state_from_string(value);
- if (state < 0)
- log_debug("Failed to parse state value %s", value);
- else
- s->deserialized_state = state;
-
- } else
- log_debug("Unknown serialization key '%s'", key);
-
- return 0;
-}
-
-static bool scope_check_gc(Unit *u) {
- assert(u);
-
- /* Never clean up scopes that still have a process around,
- * even if the scope is formally dead. */
-
- if (u->cgroup_path) {
- int r;
-
- r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, true);
- if (r <= 0)
- return true;
- }
-
- return false;
-}
-
-static void scope_notify_cgroup_empty_event(Unit *u) {
- Scope *s = SCOPE(u);
- assert(u);
-
- log_unit_debug(u->id, "%s: cgroup is empty", u->id);
-
- if (IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED, SCOPE_STOP_SIGTERM, SCOPE_STOP_SIGKILL))
- scope_enter_dead(s, SCOPE_SUCCESS);
-}
-
-static void scope_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, 0, 0);
- unit_watch_all_pids(u);
-
- /* If the PID set is empty now, then let's finish this off */
- if (set_isempty(u->pids))
- scope_notify_cgroup_empty_event(u);
-}
-
-static int scope_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
- Scope *s = SCOPE(userdata);
-
- assert(s);
- assert(s->timer_event_source == source);
-
- switch (s->state) {
-
- case SCOPE_STOP_SIGTERM:
- if (s->kill_context.send_sigkill) {
- log_unit_warning(UNIT(s)->id, "%s stopping timed out. Killing.", UNIT(s)->id);
- scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_FAILURE_TIMEOUT);
- } else {
- log_unit_warning(UNIT(s)->id, "%s stopping timed out. Skipping SIGKILL.", UNIT(s)->id);
- scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
- }
-
- break;
-
- case SCOPE_STOP_SIGKILL:
- log_unit_warning(UNIT(s)->id, "%s still around after SIGKILL. Ignoring.", UNIT(s)->id);
- scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
- break;
-
- default:
- assert_not_reached("Timeout at wrong time.");
- }
-
- return 0;
-}
-
-int scope_abandon(Scope *s) {
- assert(s);
-
- if (!IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED))
- return -ESTALE;
-
- free(s->controller);
- s->controller = NULL;
-
- /* 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));
-
- /* If the PID set is empty now, then let's finish this off */
- if (set_isempty(UNIT(s)->pids))
- scope_notify_cgroup_empty_event(UNIT(s));
- else
- scope_set_state(s, SCOPE_ABANDONED);
-
- return 0;
-}
-
-_pure_ static UnitActiveState scope_active_state(Unit *u) {
- assert(u);
-
- return state_translation_table[SCOPE(u)->state];
-}
-
-_pure_ static const char *scope_sub_state_to_string(Unit *u) {
- assert(u);
-
- return scope_state_to_string(SCOPE(u)->state);
-}
-
-static const char* const scope_state_table[_SCOPE_STATE_MAX] = {
- [SCOPE_DEAD] = "dead",
- [SCOPE_RUNNING] = "running",
- [SCOPE_ABANDONED] = "abandoned",
- [SCOPE_STOP_SIGTERM] = "stop-sigterm",
- [SCOPE_STOP_SIGKILL] = "stop-sigkill",
- [SCOPE_FAILED] = "failed",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(scope_state, ScopeState);
-
-static const char* const scope_result_table[_SCOPE_RESULT_MAX] = {
- [SCOPE_SUCCESS] = "success",
- [SCOPE_FAILURE_RESOURCES] = "resources",
- [SCOPE_FAILURE_TIMEOUT] = "timeout",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(scope_result, ScopeResult);
-
-const UnitVTable scope_vtable = {
- .object_size = sizeof(Scope),
- .cgroup_context_offset = offsetof(Scope, cgroup_context),
- .kill_context_offset = offsetof(Scope, kill_context),
-
- .sections =
- "Unit\0"
- "Scope\0"
- "Install\0",
- .private_section = "Scope",
-
- .no_alias = true,
- .no_instances = true,
-
- .init = scope_init,
- .load = scope_load,
- .done = scope_done,
-
- .coldplug = scope_coldplug,
-
- .dump = scope_dump,
-
- .start = scope_start,
- .stop = scope_stop,
-
- .kill = scope_kill,
-
- .get_timeout = scope_get_timeout,
-
- .serialize = scope_serialize,
- .deserialize_item = scope_deserialize_item,
-
- .active_state = scope_active_state,
- .sub_state_to_string = scope_sub_state_to_string,
-
- .check_gc = scope_check_gc,
-
- .sigchld_event = scope_sigchld_event,
-
- .reset_failed = scope_reset_failed,
-
- .notify_cgroup_empty = scope_notify_cgroup_empty_event,
-
- .bus_interface = "org.freedesktop.systemd1.Scope",
- .bus_vtable = bus_scope_vtable,
- .bus_set_property = bus_scope_set_property,
- .bus_commit_properties = bus_scope_commit_properties,
-
- .can_transient = true
-};
diff --git a/src/core/scope.h b/src/core/scope.h
deleted file mode 100644
index 4452fe2c9..000000000
--- a/src/core/scope.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 "kill.h"
-
-typedef enum ScopeState {
- SCOPE_DEAD,
- SCOPE_RUNNING,
- SCOPE_ABANDONED,
- SCOPE_STOP_SIGTERM,
- SCOPE_STOP_SIGKILL,
- SCOPE_FAILED,
- _SCOPE_STATE_MAX,
- _SCOPE_STATE_INVALID = -1
-} ScopeState;
-
-typedef enum ScopeResult {
- SCOPE_SUCCESS,
- SCOPE_FAILURE_RESOURCES,
- SCOPE_FAILURE_TIMEOUT,
- _SCOPE_RESULT_MAX,
- _SCOPE_RESULT_INVALID = -1
-} ScopeResult;
-
-struct Scope {
- Unit meta;
-
- CGroupContext cgroup_context;
- KillContext kill_context;
-
- ScopeState state, deserialized_state;
- ScopeResult result;
-
- usec_t timeout_stop_usec;
-
- char *controller;
-
- sd_event_source *timer_event_source;
-};
-
-extern const UnitVTable scope_vtable;
-
-int scope_abandon(Scope *s);
-
-const char* scope_state_to_string(ScopeState i) _const_;
-ScopeState scope_state_from_string(const char *s) _pure_;
-
-const char* scope_result_to_string(ScopeResult i) _const_;
-ScopeResult scope_result_from_string(const char *s) _pure_;
diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c
deleted file mode 100644
index a8c9a4b88..000000000
--- a/src/core/selinux-access.c
+++ /dev/null
@@ -1,279 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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/>.
-***/
-
-#include "selinux-access.h"
-
-#ifdef HAVE_SELINUX
-
-#include <stdio.h>
-#include <errno.h>
-#include <selinux/selinux.h>
-#include <selinux/avc.h>
-#ifdef HAVE_AUDIT
-#include <libaudit.h>
-#endif
-
-#include "sd-bus.h"
-#include "bus-util.h"
-#include "util.h"
-#include "log.h"
-#include "selinux-util.h"
-#include "audit-fd.h"
-#include "strv.h"
-
-static bool initialized = false;
-
-struct audit_info {
- sd_bus_creds *creds;
- const char *path;
- const char *cmdline;
-};
-
-/*
- Any time an access gets denied this callback will be called
- with the audit data. We then need to just copy the audit data into the msgbuf.
-*/
-static int audit_callback(
- void *auditdata,
- security_class_t cls,
- char *msgbuf,
- size_t msgbufsize) {
-
- const struct audit_info *audit = auditdata;
- uid_t uid = 0, login_uid = 0;
- gid_t gid = 0;
- char login_uid_buf[DECIMAL_STR_MAX(uid_t) + 1] = "n/a";
- char uid_buf[DECIMAL_STR_MAX(uid_t) + 1] = "n/a";
- char gid_buf[DECIMAL_STR_MAX(gid_t) + 1] = "n/a";
-
- if (sd_bus_creds_get_audit_login_uid(audit->creds, &login_uid) >= 0)
- xsprintf(login_uid_buf, UID_FMT, login_uid);
- if (sd_bus_creds_get_euid(audit->creds, &uid) >= 0)
- xsprintf(uid_buf, UID_FMT, uid);
- if (sd_bus_creds_get_egid(audit->creds, &gid) >= 0)
- xsprintf(gid_buf, GID_FMT, gid);
-
- snprintf(msgbuf, msgbufsize,
- "auid=%s uid=%s gid=%s%s%s%s%s%s%s",
- login_uid_buf, uid_buf, gid_buf,
- audit->path ? " path=\"" : "", strempty(audit->path), audit->path ? "\"" : "",
- audit->cmdline ? " cmdline=\"" : "", strempty(audit->cmdline), audit->cmdline ? "\"" : "");
-
- return 0;
-}
-
-/*
- Any time an access gets denied this callback will be called
- code copied from dbus. If audit is turned on the messages will go as
- user_avc's into the /var/log/audit/audit.log, otherwise they will be
- sent to syslog.
-*/
-_printf_(2, 3) static int log_callback(int type, const char *fmt, ...) {
- va_list ap;
-
-#ifdef HAVE_AUDIT
- if (get_audit_fd() >= 0) {
- _cleanup_free_ char *buf = NULL;
- int r;
-
- va_start(ap, fmt);
- r = vasprintf(&buf, fmt, ap);
- va_end(ap);
-
- if (r >= 0) {
- audit_log_user_avc_message(get_audit_fd(), AUDIT_USER_AVC, buf, NULL, NULL, NULL, 0);
- return 0;
- }
- }
-#endif
-
- va_start(ap, fmt);
- log_internalv(LOG_AUTH | LOG_INFO, 0, __FILE__, __LINE__, __FUNCTION__, fmt, ap);
- va_end(ap);
-
- return 0;
-}
-
-/*
- Function must be called once to initialize the SELinux AVC environment.
- Sets up callbacks.
- If you want to cleanup memory you should need to call selinux_access_finish.
-*/
-static int access_init(void) {
- int r = 0;
-
- if (avc_open(NULL, 0))
- return log_error_errno(errno, "avc_open() failed: %m");
-
- selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback) audit_callback);
- selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) log_callback);
-
- if (security_getenforce() < 0){
- r = -errno;
- avc_destroy();
- }
-
- return r;
-}
-
-static int mac_selinux_access_init(sd_bus_error *error) {
- int r;
-
- if (initialized)
- return 0;
-
- if (!mac_selinux_use())
- return 0;
-
- r = access_init();
- if (r < 0)
- return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to initialize SELinux.");
-
- initialized = true;
- return 0;
-}
-#endif
-
-void mac_selinux_access_free(void) {
-
-#ifdef HAVE_SELINUX
- if (!initialized)
- return;
-
- avc_destroy();
- initialized = false;
-#endif
-}
-
-/*
- This function communicates with the kernel to check whether or not it should
- allow the access.
- If the machine is in permissive mode it will return ok. Audit messages will
- still be generated if the access would be denied in enforcing mode.
-*/
-int mac_selinux_generic_access_check(
- sd_bus_message *message,
- const char *path,
- const char *permission,
- sd_bus_error *error) {
-
-#ifdef HAVE_SELINUX
- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
- const char *tclass = NULL, *scon = NULL;
- struct audit_info audit_info = {};
- _cleanup_free_ char *cl = NULL;
- security_context_t fcon = NULL;
- char **cmdline = NULL;
- int r = 0;
-
- assert(message);
- assert(permission);
- assert(error);
-
- if (!mac_selinux_use())
- return 0;
-
- r = mac_selinux_access_init(error);
- if (r < 0)
- return r;
-
- r = sd_bus_query_sender_creds(
- message,
- SD_BUS_CREDS_PID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EGID|
- SD_BUS_CREDS_CMDLINE|SD_BUS_CREDS_AUDIT_LOGIN_UID|
- SD_BUS_CREDS_SELINUX_CONTEXT|
- SD_BUS_CREDS_AUGMENT /* get more bits from /proc */,
- &creds);
- if (r < 0)
- goto finish;
-
- r = sd_bus_creds_get_selinux_context(creds, &scon);
- if (r < 0)
- goto finish;
-
- if (path) {
- /* Get the file context of the unit file */
-
- r = getfilecon(path, &fcon);
- if (r < 0) {
- r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get file context on %s.", path);
- goto finish;
- }
-
- tclass = "service";
- } else {
- r = getcon(&fcon);
- if (r < 0) {
- r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to get current context.");
- goto finish;
- }
-
- tclass = "system";
- }
-
- sd_bus_creds_get_cmdline(creds, &cmdline);
- cl = strv_join(cmdline, " ");
-
- audit_info.creds = creds;
- audit_info.path = path;
- audit_info.cmdline = cl;
-
- r = selinux_check_access((security_context_t) scon, fcon, tclass, permission, &audit_info);
- if (r < 0)
- r = sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "SELinux policy denies access.");
-
- log_debug("SELinux access check scon=%s tcon=%s tclass=%s perm=%s path=%s cmdline=%s: %i", scon, fcon, tclass, permission, path, cl, r);
-
-finish:
- freecon(fcon);
-
- if (r < 0 && security_getenforce() != 1) {
- sd_bus_error_free(error);
- r = 0;
- }
-
- return r;
-#else
- return 0;
-#endif
-}
-
-int mac_selinux_unit_access_check_strv(char **units,
- sd_bus_message *message,
- Manager *m,
- const char *permission,
- sd_bus_error *error) {
-#ifdef HAVE_SELINUX
- char **i;
- Unit *u;
- int r;
-
- STRV_FOREACH(i, units) {
- u = manager_get_unit(m, *i);
- if (u) {
- r = mac_selinux_unit_access_check(u, message, permission, error);
- if (r < 0)
- return r;
- }
- }
-#endif
- return 0;
-}
diff --git a/src/core/selinux-access.h b/src/core/selinux-access.h
deleted file mode 100644
index b5758e2e4..000000000
--- a/src/core/selinux-access.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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/>.
-***/
-
-#include "sd-bus.h"
-#include "bus-util.h"
-#include "manager.h"
-
-void mac_selinux_access_free(void);
-
-int mac_selinux_generic_access_check(sd_bus_message *message, const char *path, const char *permission, sd_bus_error *error);
-
-int mac_selinux_unit_access_check_strv(char **units, sd_bus_message *message, Manager *m, const char *permission, sd_bus_error *error);
-
-#ifdef HAVE_SELINUX
-
-#define mac_selinux_access_check(message, permission, error) \
- mac_selinux_generic_access_check((message), NULL, (permission), (error))
-
-#define mac_selinux_unit_access_check(unit, message, permission, error) \
- ({ \
- Unit *_unit = (unit); \
- mac_selinux_generic_access_check((message), _unit->source_path ?: _unit->fragment_path, (permission), (error)); \
- })
-
-#else
-
-#define mac_selinux_access_check(message, permission, error) 0
-#define mac_selinux_unit_access_check(unit, message, permission, error) 0
-
-#endif
diff --git a/src/core/selinux-setup.c b/src/core/selinux-setup.c
deleted file mode 100644
index a4678500e..000000000
--- a/src/core/selinux-setup.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-
-#ifdef HAVE_SELINUX
-#include <selinux/selinux.h>
-#endif
-
-#include "selinux-setup.h"
-#include "selinux-util.h"
-#include "macro.h"
-#include "util.h"
-#include "log.h"
-
-#ifdef HAVE_SELINUX
-static int null_log(int type, const char *fmt, ...) {
- return 0;
-}
-#endif
-
-int mac_selinux_setup(bool *loaded_policy) {
-
-#ifdef HAVE_SELINUX
- int enforce = 0;
- usec_t before_load, after_load;
- security_context_t con;
- int r;
- union selinux_callback cb;
- 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
- * it. For the real root, we check below if we've already
- * loaded policy, and return gracefully.
- */
- if (in_initrd() && access(selinux_path(), F_OK) < 0)
- return 0;
-
- /* Already initialized by somebody else? */
- r = getcon_raw(&con);
- if (r == 0) {
- initialized = !streq(con, "kernel");
- freecon(con);
- }
-
- /* Make sure we have no fds open while loading the policy and
- * transitioning */
- log_close();
-
- /* Now load the policy */
- before_load = now(CLOCK_MONOTONIC);
- r = selinux_init_load_policy(&enforce);
- if (r == 0) {
- char timespan[FORMAT_TIMESPAN_MAX];
- char *label;
-
- mac_selinux_retest();
-
- /* Transition to the new context */
- r = mac_selinux_get_create_label_from_exe(SYSTEMD_BINARY_PATH, &label);
- if (r < 0 || label == NULL) {
- log_open();
- log_error("Failed to compute init label, ignoring.");
- } else {
- r = setcon(label);
-
- log_open();
- if (r < 0)
- log_error("Failed to transition into init label '%s', ignoring.", label);
-
- mac_selinux_free(label);
- }
-
- after_load = now(CLOCK_MONOTONIC);
-
- log_info("Successfully loaded SELinux policy in %s.",
- format_timespan(timespan, sizeof(timespan), after_load - before_load, 0));
-
- *loaded_policy = true;
-
- } else {
- log_open();
-
- if (enforce > 0) {
- if (!initialized) {
- log_emergency("Failed to load SELinux policy.");
- return -EIO;
- }
-
- log_warning("Failed to load new SELinux policy. Continuing with old policy.");
- } else
- log_debug("Unable to load SELinux policy. Ignoring.");
- }
-#endif
-
- return 0;
-}
diff --git a/src/core/selinux-setup.h b/src/core/selinux-setup.h
deleted file mode 100644
index 9ac227657..000000000
--- a/src/core/selinux-setup.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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
deleted file mode 100644
index beaf21340..000000000
--- a/src/core/service.c
+++ /dev/null
@@ -1,3212 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 <unistd.h>
-
-#include "async.h"
-#include "manager.h"
-#include "unit.h"
-#include "service.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
-#include "log.h"
-#include "strv.h"
-#include "unit-name.h"
-#include "unit-printf.h"
-#include "dbus-service.h"
-#include "special.h"
-#include "exit-status.h"
-#include "def.h"
-#include "path-util.h"
-#include "util.h"
-#include "utf8.h"
-#include "env-util.h"
-#include "fileio.h"
-#include "bus-error.h"
-#include "bus-util.h"
-#include "bus-kernel.h"
-
-static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
- [SERVICE_DEAD] = UNIT_INACTIVE,
- [SERVICE_START_PRE] = UNIT_ACTIVATING,
- [SERVICE_START] = UNIT_ACTIVATING,
- [SERVICE_START_POST] = UNIT_ACTIVATING,
- [SERVICE_RUNNING] = UNIT_ACTIVE,
- [SERVICE_EXITED] = UNIT_ACTIVE,
- [SERVICE_RELOAD] = UNIT_RELOADING,
- [SERVICE_STOP] = UNIT_DEACTIVATING,
- [SERVICE_STOP_SIGABRT] = UNIT_DEACTIVATING,
- [SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING,
- [SERVICE_STOP_SIGKILL] = UNIT_DEACTIVATING,
- [SERVICE_STOP_POST] = UNIT_DEACTIVATING,
- [SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING,
- [SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING,
- [SERVICE_FAILED] = UNIT_FAILED,
- [SERVICE_AUTO_RESTART] = UNIT_ACTIVATING
-};
-
-/* For Type=idle we never want to delay any other jobs, hence we
- * consider idle jobs active as soon as we start working on them */
-static const UnitActiveState state_translation_table_idle[_SERVICE_STATE_MAX] = {
- [SERVICE_DEAD] = UNIT_INACTIVE,
- [SERVICE_START_PRE] = UNIT_ACTIVE,
- [SERVICE_START] = UNIT_ACTIVE,
- [SERVICE_START_POST] = UNIT_ACTIVE,
- [SERVICE_RUNNING] = UNIT_ACTIVE,
- [SERVICE_EXITED] = UNIT_ACTIVE,
- [SERVICE_RELOAD] = UNIT_RELOADING,
- [SERVICE_STOP] = UNIT_DEACTIVATING,
- [SERVICE_STOP_SIGABRT] = UNIT_DEACTIVATING,
- [SERVICE_STOP_SIGTERM] = UNIT_DEACTIVATING,
- [SERVICE_STOP_SIGKILL] = UNIT_DEACTIVATING,
- [SERVICE_STOP_POST] = UNIT_DEACTIVATING,
- [SERVICE_FINAL_SIGTERM] = UNIT_DEACTIVATING,
- [SERVICE_FINAL_SIGKILL] = UNIT_DEACTIVATING,
- [SERVICE_FAILED] = UNIT_FAILED,
- [SERVICE_AUTO_RESTART] = UNIT_ACTIVATING
-};
-
-static int service_dispatch_io(sd_event_source *source, int fd, uint32_t events, void *userdata);
-static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
-static int service_dispatch_watchdog(sd_event_source *source, usec_t usec, void *userdata);
-
-static void service_enter_signal(Service *s, ServiceState state, ServiceResult f);
-static void service_enter_reload_by_notify(Service *s);
-
-static void service_init(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
-
- s->timeout_start_usec = u->manager->default_timeout_start_usec;
- s->timeout_stop_usec = u->manager->default_timeout_stop_usec;
- s->restart_usec = u->manager->default_restart_usec;
- s->type = _SERVICE_TYPE_INVALID;
- s->socket_fd = -1;
- s->bus_endpoint_fd = -1;
- s->guess_main_pid = true;
-
- RATELIMIT_INIT(s->start_limit, u->manager->default_start_limit_interval, u->manager->default_start_limit_burst);
-
- s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
-}
-
-static void service_unwatch_control_pid(Service *s) {
- assert(s);
-
- if (s->control_pid <= 0)
- return;
-
- unit_unwatch_pid(UNIT(s), s->control_pid);
- s->control_pid = 0;
-}
-
-static void service_unwatch_main_pid(Service *s) {
- assert(s);
-
- if (s->main_pid <= 0)
- return;
-
- unit_unwatch_pid(UNIT(s), s->main_pid);
- s->main_pid = 0;
-}
-
-static void service_unwatch_pid_file(Service *s) {
- if (!s->pid_file_pathspec)
- return;
-
- log_unit_debug(UNIT(s)->id, "Stopping watch for %s's PID file %s", UNIT(s)->id, s->pid_file_pathspec->path);
- path_spec_unwatch(s->pid_file_pathspec);
- path_spec_done(s->pid_file_pathspec);
- free(s->pid_file_pathspec);
- s->pid_file_pathspec = NULL;
-}
-
-static int service_set_main_pid(Service *s, pid_t pid) {
- pid_t ppid;
-
- assert(s);
-
- if (pid <= 1)
- return -EINVAL;
-
- if (pid == getpid())
- return -EINVAL;
-
- if (s->main_pid == pid && s->main_pid_known)
- return 0;
-
- if (s->main_pid != pid) {
- service_unwatch_main_pid(s);
- exec_status_start(&s->main_exec_status, pid);
- }
-
- s->main_pid = pid;
- s->main_pid_known = true;
-
- if (get_parent_of_pid(pid, &ppid) >= 0 && ppid != getpid()) {
- log_unit_warning(UNIT(s)->id, "%s: Supervising process "PID_FMT" which is not our child. We'll most likely not notice when it exits.", UNIT(s)->id, pid);
- s->main_pid_alien = true;
- } else
- s->main_pid_alien = false;
-
- return 0;
-}
-
-static void service_close_socket_fd(Service *s) {
- assert(s);
-
- s->socket_fd = asynchronous_close(s->socket_fd);
-}
-
-static void service_connection_unref(Service *s) {
- assert(s);
-
- if (!UNIT_ISSET(s->accept_socket))
- return;
-
- socket_connection_unref(SOCKET(UNIT_DEREF(s->accept_socket)));
- unit_ref_unset(&s->accept_socket);
-}
-
-static void service_stop_watchdog(Service *s) {
- assert(s);
-
- s->watchdog_event_source = sd_event_source_unref(s->watchdog_event_source);
- s->watchdog_timestamp = DUAL_TIMESTAMP_NULL;
-}
-
-static void service_start_watchdog(Service *s) {
- int r;
-
- assert(s);
-
- if (s->watchdog_usec <= 0)
- return;
-
- if (s->watchdog_event_source) {
- r = sd_event_source_set_time(s->watchdog_event_source, s->watchdog_timestamp.monotonic + s->watchdog_usec);
- if (r < 0) {
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to reset watchdog timer: %m", UNIT(s)->id);
- return;
- }
-
- r = sd_event_source_set_enabled(s->watchdog_event_source, SD_EVENT_ONESHOT);
- } else {
- r = sd_event_add_time(
- UNIT(s)->manager->event,
- &s->watchdog_event_source,
- CLOCK_MONOTONIC,
- s->watchdog_timestamp.monotonic + s->watchdog_usec, 0,
- service_dispatch_watchdog, s);
- if (r < 0) {
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to add watchdog timer: %m", UNIT(s)->id);
- return;
- }
-
- /* Let's process everything else which might be a sign
- * of living before we consider a service died. */
- r = sd_event_source_set_priority(s->watchdog_event_source, SD_EVENT_PRIORITY_IDLE);
- }
-
- if (r < 0)
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to install watchdog timer: %m", UNIT(s)->id);
-}
-
-static void service_reset_watchdog(Service *s) {
- assert(s);
-
- dual_timestamp_get(&s->watchdog_timestamp);
- service_start_watchdog(s);
-}
-
-static void service_fd_store_unlink(ServiceFDStore *fs) {
-
- if (!fs)
- return;
-
- if (fs->service) {
- assert(fs->service->n_fd_store > 0);
- LIST_REMOVE(fd_store, fs->service->fd_store, fs);
- fs->service->n_fd_store--;
- }
-
- if (fs->event_source) {
- sd_event_source_set_enabled(fs->event_source, SD_EVENT_OFF);
- sd_event_source_unref(fs->event_source);
- }
-
- safe_close(fs->fd);
- free(fs);
-}
-
-static void service_release_resources(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
-
- if (!s->fd_store)
- return;
-
- log_debug("Releasing all resources for %s", u->id);
-
- while (s->fd_store)
- service_fd_store_unlink(s->fd_store);
-
- assert(s->n_fd_store == 0);
-}
-
-static void service_done(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
-
- free(s->pid_file);
- s->pid_file = NULL;
-
- free(s->status_text);
- s->status_text = NULL;
-
- free(s->reboot_arg);
- s->reboot_arg = NULL;
-
- s->exec_runtime = exec_runtime_unref(s->exec_runtime);
- exec_command_free_array(s->exec_command, _SERVICE_EXEC_COMMAND_MAX);
- s->control_command = NULL;
- s->main_command = NULL;
-
- exit_status_set_free(&s->restart_prevent_status);
- exit_status_set_free(&s->restart_force_status);
- exit_status_set_free(&s->success_status);
-
- /* This will leak a process, but at least no memory or any of
- * our resources */
- service_unwatch_main_pid(s);
- service_unwatch_control_pid(s);
- service_unwatch_pid_file(s);
-
- if (s->bus_name) {
- unit_unwatch_bus_name(u, s->bus_name);
- free(s->bus_name);
- s->bus_name = NULL;
- }
-
- s->bus_endpoint_fd = safe_close(s->bus_endpoint_fd);
- service_close_socket_fd(s);
- service_connection_unref(s);
-
- unit_ref_unset(&s->accept_socket);
-
- service_stop_watchdog(s);
-
- s->timer_event_source = sd_event_source_unref(s->timer_event_source);
-
- service_release_resources(u);
-}
-
-static int on_fd_store_io(sd_event_source *e, int fd, uint32_t revents, void *userdata) {
- ServiceFDStore *fs = userdata;
-
- assert(e);
- assert(fs);
-
- /* If we get either EPOLLHUP or EPOLLERR, it's time to remove this entry from the fd store */
- service_fd_store_unlink(fs);
- return 0;
-}
-
-static int service_add_fd_store(Service *s, int fd) {
- ServiceFDStore *fs;
- int r;
-
- assert(s);
- assert(fd >= 0);
-
- if (s->n_fd_store >= s->n_fd_store_max)
- return 0;
-
- LIST_FOREACH(fd_store, fs, s->fd_store) {
- r = -EINVAL;
- if (r < 0)
- return r;
- if (r > 0) {
- /* Already included */
- safe_close(fd);
- return 1;
- }
- }
-
- fs = new0(ServiceFDStore, 1);
- if (!fs)
- return -ENOMEM;
-
- fs->fd = fd;
- fs->service = s;
-
- r = sd_event_add_io(UNIT(s)->manager->event, &fs->event_source, fd, 0, on_fd_store_io, fs);
- if (r < 0) {
- free(fs);
- return r;
- }
-
- LIST_PREPEND(fd_store, s->fd_store, fs);
- s->n_fd_store++;
-
- return 1;
-}
-
-static int service_add_fd_store_set(Service *s, FDSet *fds) {
- int r;
-
- assert(s);
-
- if (fdset_size(fds) <= 0)
- return 0;
-
- while (s->n_fd_store < s->n_fd_store_max) {
- _cleanup_close_ int fd = -1;
-
- fd = fdset_steal_first(fds);
- if (fd < 0)
- break;
-
- r = service_add_fd_store(s, fd);
- if (r < 0)
- return log_unit_error_errno(UNIT(s)->id, r, "%s: Couldn't add fd to fd store: %m", UNIT(s)->id);
-
- if (r > 0) {
- log_unit_debug(UNIT(s)->id, "%s: added fd to fd store.", UNIT(s)->id);
- fd = -1;
- }
- }
-
- if (fdset_size(fds) > 0)
- log_unit_warning(UNIT(s)->id, "%s: tried to store more fds than FDStoreMax=%u allows, closing remaining.", UNIT(s)->id, s->n_fd_store_max);
-
- return 0;
-}
-
-static int service_arm_timer(Service *s, usec_t usec) {
- int r;
-
- assert(s);
-
- if (s->timer_event_source) {
- r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + usec);
- if (r < 0)
- return r;
-
- return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
- }
-
- return sd_event_add_time(
- UNIT(s)->manager->event,
- &s->timer_event_source,
- CLOCK_MONOTONIC,
- now(CLOCK_MONOTONIC) + usec, 0,
- service_dispatch_timer, s);
-}
-
-static int service_verify(Service *s) {
- assert(s);
-
- if (UNIT(s)->load_state != UNIT_LOADED)
- return 0;
-
- if (!s->exec_command[SERVICE_EXEC_START] && !s->exec_command[SERVICE_EXEC_STOP]) {
- log_unit_error(UNIT(s)->id, "%s lacks both ExecStart= and ExecStop= setting. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
-
- if (s->type != SERVICE_ONESHOT && !s->exec_command[SERVICE_EXEC_START]) {
- log_unit_error(UNIT(s)->id, "%s has no ExecStart= setting, which is only allowed for Type=oneshot services. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
-
- if (!s->remain_after_exit && !s->exec_command[SERVICE_EXEC_START]) {
- log_unit_error(UNIT(s)->id, "%s has no ExecStart= setting, which is only allowed for RemainAfterExit=yes services. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
-
- if (s->type != SERVICE_ONESHOT && s->exec_command[SERVICE_EXEC_START]->command_next) {
- log_unit_error(UNIT(s)->id, "%s has more than one ExecStart= setting, which is only allowed for Type=oneshot services. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
-
- if (s->type == SERVICE_ONESHOT && s->restart != SERVICE_RESTART_NO) {
- log_unit_error(UNIT(s)->id, "%s has Restart= setting other than no, which isn't allowed for Type=oneshot services. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
-
- if (s->type == SERVICE_ONESHOT && !exit_status_set_is_empty(&s->restart_force_status)) {
- log_unit_error(UNIT(s)->id, "%s has RestartForceStatus= set, which isn't allowed for Type=oneshot services. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
-
- if (s->type == SERVICE_DBUS && !s->bus_name) {
- log_unit_error(UNIT(s)->id, "%s is of type D-Bus but no D-Bus service name has been specified. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
-
- if (s->bus_name && s->type != SERVICE_DBUS)
- log_unit_warning(UNIT(s)->id, "%s has a D-Bus service name specified, but is not of type dbus. Ignoring.", UNIT(s)->id);
-
- if (s->exec_context.pam_name && !(s->kill_context.kill_mode == KILL_CONTROL_GROUP || s->kill_context.kill_mode == KILL_MIXED)) {
- log_unit_error(UNIT(s)->id, "%s has PAM enabled. Kill mode must be set to 'control-group' or 'mixed'. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int service_add_default_dependencies(Service *s) {
- int r;
-
- assert(s);
-
- /* Add a number of automatic dependencies useful for the
- * majority of services. */
-
- /* First, pull in base system */
- r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true);
- if (r < 0)
- return r;
-
- /* Second, activate normal shutdown */
- return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
-}
-
-static void service_fix_output(Service *s) {
- assert(s);
-
- /* If nothing has been explicitly configured, patch default
- * output in. If input is socket/tty we avoid this however,
- * since in that case we want output to default to the same
- * place as we read input from. */
-
- if (s->exec_context.std_error == EXEC_OUTPUT_INHERIT &&
- s->exec_context.std_output == EXEC_OUTPUT_INHERIT &&
- s->exec_context.std_input == EXEC_INPUT_NULL)
- s->exec_context.std_error = UNIT(s)->manager->default_std_error;
-
- if (s->exec_context.std_output == EXEC_OUTPUT_INHERIT &&
- s->exec_context.std_input == EXEC_INPUT_NULL)
- s->exec_context.std_output = UNIT(s)->manager->default_std_output;
-}
-
-static int service_add_extras(Service *s) {
- int r;
-
- assert(s);
-
- if (s->type == _SERVICE_TYPE_INVALID) {
- /* Figure out a type automatically */
- if (s->bus_name)
- s->type = SERVICE_DBUS;
- else if (s->exec_command[SERVICE_EXEC_START])
- s->type = SERVICE_SIMPLE;
- else
- s->type = SERVICE_ONESHOT;
- }
-
- /* Oneshot services have disabled start timeout by default */
- if (s->type == SERVICE_ONESHOT && !s->start_timeout_defined)
- s->timeout_start_usec = 0;
-
- service_fix_output(s);
-
- r = unit_patch_contexts(UNIT(s));
- if (r < 0)
- return r;
-
- r = unit_add_exec_dependencies(UNIT(s), &s->exec_context);
- if (r < 0)
- return r;
-
- r = unit_add_default_slice(UNIT(s), &s->cgroup_context);
- 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)
- s->notify_access = NOTIFY_MAIN;
-
- if (s->bus_name) {
-#ifdef ENABLE_KDBUS
- const char *n;
-
- n = strjoina(s->bus_name, ".busname");
- r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, n, NULL, true);
- if (r < 0)
- return r;
-#endif
-
- r = unit_watch_bus_name(UNIT(s), s->bus_name);
- if (r < 0)
- return r;
- }
-
- if (UNIT(s)->default_dependencies) {
- r = service_add_default_dependencies(s);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-static int service_load(Unit *u) {
- Service *s = SERVICE(u);
- int r;
-
- assert(s);
-
- /* Load a .service file */
- r = unit_load_fragment(u);
- if (r < 0)
- return r;
-
- /* Still nothing found? Then let's give up */
- if (u->load_state == UNIT_STUB)
- return -ENOENT;
-
- /* This is a new unit? Then let's add in some extras */
- if (u->load_state == UNIT_LOADED) {
-
- /* We were able to load something, then let's add in
- * the dropin directories. */
- r = unit_load_dropin(u);
- if (r < 0)
- return r;
-
- /* This is a new unit? Then let's add in some
- * extras */
- r = service_add_extras(s);
- if (r < 0)
- return r;
- }
-
- return service_verify(s);
-}
-
-static void service_dump(Unit *u, FILE *f, const char *prefix) {
- ServiceExecCommand c;
- Service *s = SERVICE(u);
- const char *prefix2;
-
- assert(s);
-
- prefix = strempty(prefix);
- prefix2 = strjoina(prefix, "\t");
-
- fprintf(f,
- "%sService State: %s\n"
- "%sResult: %s\n"
- "%sReload Result: %s\n"
- "%sPermissionsStartOnly: %s\n"
- "%sRootDirectoryStartOnly: %s\n"
- "%sRemainAfterExit: %s\n"
- "%sGuessMainPID: %s\n"
- "%sType: %s\n"
- "%sRestart: %s\n"
- "%sNotifyAccess: %s\n"
- "%sNotifyState: %s\n",
- prefix, service_state_to_string(s->state),
- prefix, service_result_to_string(s->result),
- prefix, service_result_to_string(s->reload_result),
- prefix, yes_no(s->permissions_start_only),
- prefix, yes_no(s->root_directory_start_only),
- prefix, yes_no(s->remain_after_exit),
- prefix, yes_no(s->guess_main_pid),
- prefix, service_type_to_string(s->type),
- prefix, service_restart_to_string(s->restart),
- prefix, notify_access_to_string(s->notify_access),
- prefix, notify_state_to_string(s->notify_state));
-
- if (s->control_pid > 0)
- fprintf(f,
- "%sControl PID: "PID_FMT"\n",
- prefix, s->control_pid);
-
- if (s->main_pid > 0)
- fprintf(f,
- "%sMain PID: "PID_FMT"\n"
- "%sMain PID Known: %s\n"
- "%sMain PID Alien: %s\n",
- prefix, s->main_pid,
- prefix, yes_no(s->main_pid_known),
- prefix, yes_no(s->main_pid_alien));
-
- if (s->pid_file)
- fprintf(f,
- "%sPIDFile: %s\n",
- prefix, s->pid_file);
-
- if (s->bus_name)
- fprintf(f,
- "%sBusName: %s\n"
- "%sBus Name Good: %s\n",
- prefix, s->bus_name,
- prefix, yes_no(s->bus_name_good));
-
- kill_context_dump(&s->kill_context, f, prefix);
- exec_context_dump(&s->exec_context, f, prefix);
-
- for (c = 0; c < _SERVICE_EXEC_COMMAND_MAX; c++) {
-
- if (!s->exec_command[c])
- continue;
-
- fprintf(f, "%s-> %s:\n",
- prefix, service_exec_command_to_string(c));
-
- exec_command_dump_list(s->exec_command[c], f, prefix2);
- }
-
- if (s->status_text)
- fprintf(f, "%sStatus Text: %s\n",
- prefix, s->status_text);
-
- if (s->n_fd_store_max > 0) {
- fprintf(f,
- "%sFile Descriptor Store Max: %u\n"
- "%sFile Descriptor Store Current: %u\n",
- prefix, s->n_fd_store_max,
- prefix, s->n_fd_store);
- }
-}
-
-static int service_load_pid_file(Service *s, bool may_warn) {
- _cleanup_free_ char *k = NULL;
- int r;
- pid_t pid;
-
- assert(s);
-
- if (!s->pid_file)
- return -ENOENT;
-
- r = read_one_line_file(s->pid_file, &k);
- if (r < 0) {
- if (may_warn)
- log_unit_info(UNIT(s)->id, "PID file %s not readable (yet?) after %s.", s->pid_file, service_state_to_string(s->state));
- return r;
- }
-
- r = parse_pid(k, &pid);
- if (r < 0) {
- if (may_warn)
- log_unit_info_errno(UNIT(s)->id, r, "Failed to read PID from file %s: %m", s->pid_file);
- return r;
- }
-
- if (!pid_is_alive(pid)) {
- if (may_warn)
- log_unit_info(UNIT(s)->id, "PID "PID_FMT" read from file %s does not exist or is a zombie.", pid, s->pid_file);
- return -ESRCH;
- }
-
- if (s->main_pid_known) {
- if (pid == s->main_pid)
- return 0;
-
- log_unit_debug(UNIT(s)->id, "Main PID changing: "PID_FMT" -> "PID_FMT, s->main_pid, pid);
-
- service_unwatch_main_pid(s);
- s->main_pid_known = false;
- } else
- log_unit_debug(UNIT(s)->id, "Main PID loaded: "PID_FMT, pid);
-
- r = service_set_main_pid(s, pid);
- if (r < 0)
- return r;
-
- r = unit_watch_pid(UNIT(s), pid);
- if (r < 0) {
- /* FIXME: we need to do something here */
- log_unit_warning(UNIT(s)->id, "Failed to watch PID "PID_FMT" from service %s", pid, UNIT(s)->id);
- return r;
- }
-
- return 0;
-}
-
-static int service_search_main_pid(Service *s) {
- pid_t pid;
- int r;
-
- assert(s);
-
- /* If we know it anyway, don't ever fallback to unreliable
- * heuristics */
- if (s->main_pid_known)
- return 0;
-
- if (!s->guess_main_pid)
- return 0;
-
- assert(s->main_pid <= 0);
-
- pid = unit_search_main_pid(UNIT(s));
- if (pid <= 0)
- return -ENOENT;
-
- log_unit_debug(UNIT(s)->id, "Main PID guessed: "PID_FMT, pid);
- r = service_set_main_pid(s, pid);
- if (r < 0)
- return r;
-
- r = unit_watch_pid(UNIT(s), pid);
- if (r < 0) {
- /* FIXME: we need to do something here */
- log_unit_warning(UNIT(s)->id, "Failed to watch PID "PID_FMT" from service %s", pid, UNIT(s)->id);
- return r;
- }
-
- return 0;
-}
-
-static void service_set_state(Service *s, ServiceState state) {
- ServiceState old_state;
- const UnitActiveState *table;
-
- assert(s);
-
- table = s->type == SERVICE_IDLE ? state_translation_table_idle : state_translation_table;
-
- old_state = s->state;
- s->state = state;
-
- service_unwatch_pid_file(s);
-
- if (!IN_SET(state,
- SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
- SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL,
- SERVICE_STOP_SIGABRT, SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
- SERVICE_AUTO_RESTART))
- s->timer_event_source = sd_event_source_unref(s->timer_event_source);
-
- if (!IN_SET(state,
- SERVICE_START, SERVICE_START_POST,
- SERVICE_RUNNING, SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL,
- SERVICE_STOP_SIGABRT, SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
- service_unwatch_main_pid(s);
- s->main_command = NULL;
- }
-
- if (!IN_SET(state,
- SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
- SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL,
- SERVICE_STOP_SIGABRT, SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
- service_unwatch_control_pid(s);
- s->control_command = NULL;
- s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
- }
-
- if (IN_SET(state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART))
- unit_unwatch_all_pids(UNIT(s));
-
- if (!IN_SET(state,
- SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
- SERVICE_RUNNING, SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
- SERVICE_STOP_SIGABRT, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL) &&
- !(state == SERVICE_DEAD && UNIT(s)->job)) {
- service_close_socket_fd(s);
- service_connection_unref(s);
- }
-
- if (!IN_SET(state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
- service_stop_watchdog(s);
-
- /* For the inactive states unit_notify() will trim the cgroup,
- * but for exit we have to do that ourselves... */
- if (state == SERVICE_EXITED && UNIT(s)->manager->n_reloading <= 0)
- unit_destroy_cgroup_if_empty(UNIT(s));
-
- /* For remain_after_exit services, let's see if we can "release" the
- * hold on the console, since unit_notify() only does that in case of
- * change of state */
- if (state == SERVICE_EXITED &&
- s->remain_after_exit &&
- UNIT(s)->manager->n_on_console > 0) {
-
- ExecContext *ec;
-
- ec = unit_get_exec_context(UNIT(s));
- if (ec && exec_context_may_touch_console(ec)) {
- Manager *m = UNIT(s)->manager;
-
- m->n_on_console --;
- if (m->n_on_console == 0)
- /* unset no_console_output flag, since the console is free */
- m->no_console_output = false;
- }
- }
-
- if (old_state != state)
- log_unit_debug(UNIT(s)->id, "%s changed %s -> %s", UNIT(s)->id, 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);
- s->reload_result = SERVICE_SUCCESS;
-}
-
-static int service_coldplug(Unit *u, Hashmap *deferred_work) {
- Service *s = SERVICE(u);
- int r;
-
- assert(s);
- assert(s->state == SERVICE_DEAD);
-
- if (s->deserialized_state != s->state) {
-
- if (IN_SET(s->deserialized_state,
- SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
- SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL,
- SERVICE_STOP_SIGABRT, SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
-
- usec_t k;
-
- k = IN_SET(s->deserialized_state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD) ? s->timeout_start_usec : s->timeout_stop_usec;
-
- /* For the start/stop timeouts 0 means off */
- if (k > 0) {
- r = service_arm_timer(s, k);
- if (r < 0)
- return r;
- }
- }
-
- if (s->deserialized_state == SERVICE_AUTO_RESTART) {
-
- /* The restart timeouts 0 means immediately */
- r = service_arm_timer(s, s->restart_usec);
- if (r < 0)
- return r;
- }
-
- if (pid_is_unwaited(s->main_pid) &&
- ((s->deserialized_state == SERVICE_START && IN_SET(s->type, SERVICE_FORKING, SERVICE_DBUS, SERVICE_ONESHOT, SERVICE_NOTIFY)) ||
- IN_SET(s->deserialized_state,
- SERVICE_START, SERVICE_START_POST,
- SERVICE_RUNNING, SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL,
- SERVICE_STOP_SIGABRT, SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) {
- r = unit_watch_pid(UNIT(s), s->main_pid);
- if (r < 0)
- return r;
- }
-
- if (pid_is_unwaited(s->control_pid) &&
- IN_SET(s->deserialized_state,
- SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
- SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL,
- SERVICE_STOP_SIGABRT, SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
- r = unit_watch_pid(UNIT(s), s->control_pid);
- if (r < 0)
- 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);
-
- service_set_state(s, s->deserialized_state);
- }
-
- return 0;
-}
-
-static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
- _cleanup_free_ int *rfds = NULL;
- unsigned rn_fds = 0;
- Iterator i;
- int r;
- Unit *u;
-
- assert(s);
- assert(fds);
- assert(n_fds);
-
- if (s->socket_fd >= 0)
- return 0;
-
- SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) {
- int *cfds;
- unsigned cn_fds;
- Socket *sock;
-
- if (u->type != UNIT_SOCKET)
- continue;
-
- sock = SOCKET(u);
-
- r = socket_collect_fds(sock, &cfds, &cn_fds);
- if (r < 0)
- return r;
-
- if (cn_fds <= 0) {
- free(cfds);
- continue;
- }
-
- if (!rfds) {
- rfds = cfds;
- rn_fds = cn_fds;
- } else {
- int *t;
-
- t = realloc(rfds, (rn_fds + cn_fds) * sizeof(int));
- if (!t) {
- free(cfds);
- return -ENOMEM;
- }
-
- memcpy(t + rn_fds, cfds, cn_fds * sizeof(int));
- rfds = t;
- rn_fds += cn_fds;
-
- free(cfds);
-
- }
- }
-
- if (s->n_fd_store > 0) {
- ServiceFDStore *fs;
- int *t;
-
- t = realloc(rfds, (rn_fds + s->n_fd_store) * sizeof(int));
- if (!t)
- return -ENOMEM;
-
- rfds = t;
- LIST_FOREACH(fd_store, fs, s->fd_store)
- rfds[rn_fds++] = fs->fd;
- }
-
- *fds = rfds;
- *n_fds = rn_fds;
-
- rfds = NULL;
- return 0;
-}
-
-static int service_spawn(
- Service *s,
- ExecCommand *c,
- usec_t timeout,
- bool pass_fds,
- bool apply_permissions,
- bool apply_chroot,
- bool apply_tty_stdin,
- bool is_control,
- pid_t *_pid) {
-
- pid_t pid;
- int r;
- int *fds = NULL;
- _cleanup_free_ int *fdsbuf = NULL;
- unsigned n_fds = 0, n_env = 0;
- _cleanup_free_ char *bus_endpoint_path = NULL;
- _cleanup_strv_free_ char
- **argv = NULL, **final_env = NULL, **our_env = NULL;
- const char *path;
- ExecParameters exec_params = {
- .apply_permissions = apply_permissions,
- .apply_chroot = apply_chroot,
- .apply_tty_stdin = apply_tty_stdin,
- .bus_endpoint_fd = -1,
- .selinux_context_net = s->socket_fd_selinux_context_net
- };
-
- assert(s);
- assert(c);
- assert(_pid);
-
- (void) unit_realize_cgroup(UNIT(s));
- if (s->reset_cpu_usage) {
- (void) unit_reset_cpu_usage(UNIT(s));
- s->reset_cpu_usage = false;
- }
-
- r = unit_setup_exec_runtime(UNIT(s));
- if (r < 0)
- goto fail;
-
- if (pass_fds ||
- s->exec_context.std_input == EXEC_INPUT_SOCKET ||
- s->exec_context.std_output == EXEC_OUTPUT_SOCKET ||
- s->exec_context.std_error == EXEC_OUTPUT_SOCKET) {
-
- if (s->socket_fd >= 0) {
- fds = &s->socket_fd;
- n_fds = 1;
- } else {
- r = service_collect_fds(s, &fdsbuf, &n_fds);
- if (r < 0)
- goto fail;
-
- fds = fdsbuf;
- }
- }
-
- if (timeout > 0) {
- r = service_arm_timer(s, timeout);
- if (r < 0)
- goto fail;
- } else
- s->timer_event_source = sd_event_source_unref(s->timer_event_source);
-
- r = unit_full_printf_strv(UNIT(s), c->argv, &argv);
- if (r < 0)
- goto fail;
-
- our_env = new0(char*, 6);
- if (!our_env) {
- r = -ENOMEM;
- goto fail;
- }
-
- if (is_control ? s->notify_access == NOTIFY_ALL : s->notify_access != NOTIFY_NONE)
- if (asprintf(our_env + n_env++, "NOTIFY_SOCKET=%s", UNIT(s)->manager->notify_socket) < 0) {
- r = -ENOMEM;
- goto fail;
- }
-
- if (s->main_pid > 0)
- if (asprintf(our_env + n_env++, "MAINPID="PID_FMT, s->main_pid) < 0) {
- r = -ENOMEM;
- goto fail;
- }
-
- if (UNIT(s)->manager->running_as != SYSTEMD_SYSTEM)
- if (asprintf(our_env + n_env++, "MANAGERPID="PID_FMT, getpid()) < 0) {
- r = -ENOMEM;
- goto fail;
- }
-
- if (UNIT_DEREF(s->accept_socket)) {
- union sockaddr_union sa;
- socklen_t salen = sizeof(sa);
-
- r = getpeername(s->socket_fd, &sa.sa, &salen);
- if (r < 0) {
- r = -errno;
- goto fail;
- }
-
- if (IN_SET(sa.sa.sa_family, AF_INET, AF_INET6)) {
- _cleanup_free_ char *addr = NULL;
- char *t;
- int port;
-
- r = sockaddr_pretty(&sa.sa, salen, true, false, &addr);
- if (r < 0)
- goto fail;
-
- t = strappend("REMOTE_ADDR=", addr);
- if (!t) {
- r = -ENOMEM;
- goto fail;
- }
- our_env[n_env++] = t;
-
- port = sockaddr_port(&sa.sa);
- if (port < 0) {
- r = port;
- goto fail;
- }
-
- if (asprintf(&t, "REMOTE_PORT=%u", port) < 0) {
- r = -ENOMEM;
- goto fail;
- }
- our_env[n_env++] = t;
- }
- }
-
- final_env = strv_env_merge(2, UNIT(s)->manager->environment, our_env, NULL);
- if (!final_env) {
- r = -ENOMEM;
- goto fail;
- }
-
- if (is_control && UNIT(s)->cgroup_path) {
- path = strjoina(UNIT(s)->cgroup_path, "/control");
- cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
- } else
- path = UNIT(s)->cgroup_path;
-
-#ifdef ENABLE_KDBUS
- if (s->exec_context.bus_endpoint) {
- r = bus_kernel_create_endpoint(UNIT(s)->manager->running_as == SYSTEMD_SYSTEM ? "system" : "user",
- UNIT(s)->id, &bus_endpoint_path);
- if (r < 0)
- goto fail;
-
- /* Pass the fd to the exec_params so that the child process can upload the policy.
- * Keep a reference to the fd in the service, so the endpoint is kept alive as long
- * as the service is running. */
- exec_params.bus_endpoint_fd = s->bus_endpoint_fd = r;
- }
-#endif
-
- exec_params.argv = argv;
- exec_params.fds = fds;
- exec_params.n_fds = n_fds;
- exec_params.environment = final_env;
- exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn;
- exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
- exec_params.cgroup_path = path;
- exec_params.cgroup_delegate = s->cgroup_context.delegate;
- exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager);
- exec_params.unit_id = UNIT(s)->id;
- exec_params.watchdog_usec = s->watchdog_usec;
- exec_params.bus_endpoint_path = bus_endpoint_path;
- if (s->type == SERVICE_IDLE)
- exec_params.idle_pipe = UNIT(s)->manager->idle_pipe;
-
- r = exec_spawn(c,
- &s->exec_context,
- &exec_params,
- s->exec_runtime,
- &pid);
- if (r < 0)
- goto fail;
-
- r = unit_watch_pid(UNIT(s), pid);
- if (r < 0)
- /* FIXME: we need to do something here */
- goto fail;
-
- *_pid = pid;
-
- return 0;
-
-fail:
- if (timeout)
- s->timer_event_source = sd_event_source_unref(s->timer_event_source);
-
- return r;
-}
-
-static int main_pid_good(Service *s) {
- assert(s);
-
- /* Returns 0 if the pid is dead, 1 if it is good, -1 if we
- * don't know */
-
- /* If we know the pid file, then lets just check if it is
- * still valid */
- if (s->main_pid_known) {
-
- /* If it's an alien child let's check if it is still
- * alive ... */
- if (s->main_pid_alien && s->main_pid > 0)
- return pid_is_alive(s->main_pid);
-
- /* .. otherwise assume we'll get a SIGCHLD for it,
- * which we really should wait for to collect exit
- * status and code */
- return s->main_pid > 0;
- }
-
- /* We don't know the pid */
- return -EAGAIN;
-}
-
-_pure_ static int control_pid_good(Service *s) {
- assert(s);
-
- return s->control_pid > 0;
-}
-
-static int cgroup_good(Service *s) {
- int r;
-
- assert(s);
-
- if (!UNIT(s)->cgroup_path)
- return 0;
-
- r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, UNIT(s)->cgroup_path, true);
- if (r < 0)
- return r;
-
- return !r;
-}
-
-static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) {
- int r;
- assert(s);
-
- if (f != SERVICE_SUCCESS)
- s->result = f;
-
- service_set_state(s, s->result != SERVICE_SUCCESS ? SERVICE_FAILED : SERVICE_DEAD);
-
- if (s->result != SERVICE_SUCCESS) {
- log_unit_warning(UNIT(s)->id, "%s failed.", UNIT(s)->id);
- failure_action(UNIT(s)->manager, s->failure_action, s->reboot_arg);
- }
-
- if (allow_restart &&
- !s->forbid_restart &&
- (s->restart == SERVICE_RESTART_ALWAYS ||
- (s->restart == SERVICE_RESTART_ON_SUCCESS && s->result == SERVICE_SUCCESS) ||
- (s->restart == SERVICE_RESTART_ON_FAILURE && s->result != SERVICE_SUCCESS) ||
- (s->restart == SERVICE_RESTART_ON_ABNORMAL && !IN_SET(s->result, SERVICE_SUCCESS, SERVICE_FAILURE_EXIT_CODE)) ||
- (s->restart == SERVICE_RESTART_ON_WATCHDOG && s->result == SERVICE_FAILURE_WATCHDOG) ||
- (s->restart == SERVICE_RESTART_ON_ABORT && IN_SET(s->result, SERVICE_FAILURE_SIGNAL, SERVICE_FAILURE_CORE_DUMP)) ||
- (s->main_exec_status.code == CLD_EXITED && set_contains(s->restart_force_status.status, INT_TO_PTR(s->main_exec_status.status))) ||
- (IN_SET(s->main_exec_status.code, CLD_KILLED, CLD_DUMPED) && set_contains(s->restart_force_status.signal, INT_TO_PTR(s->main_exec_status.status)))) &&
- (s->main_exec_status.code != CLD_EXITED || !set_contains(s->restart_prevent_status.status, INT_TO_PTR(s->main_exec_status.status))) &&
- (!IN_SET(s->main_exec_status.code, CLD_KILLED, CLD_DUMPED) || !set_contains(s->restart_prevent_status.signal, INT_TO_PTR(s->main_exec_status.status)))) {
-
- r = service_arm_timer(s, s->restart_usec);
- if (r < 0)
- goto fail;
-
- service_set_state(s, SERVICE_AUTO_RESTART);
- }
-
- s->forbid_restart = false;
-
- /* We want fresh tmpdirs in case service is started again immediately */
- exec_runtime_destroy(s->exec_runtime);
- s->exec_runtime = exec_runtime_unref(s->exec_runtime);
-
- /* Also, remove the runtime directory in */
- exec_context_destroy_runtime_directory(&s->exec_context, manager_get_runtime_prefix(UNIT(s)->manager));
-
- /* Try to delete the pid file. At this point it will be
- * out-of-date, and some software might be confused by it, so
- * let's remove it. */
- if (s->pid_file)
- unlink_noerrno(s->pid_file);
-
- return;
-
-fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run install restart timer: %m", UNIT(s)->id);
- service_enter_dead(s, SERVICE_FAILURE_RESOURCES, false);
-}
-
-static void service_enter_stop_post(Service *s, ServiceResult f) {
- int r;
- assert(s);
-
- if (f != SERVICE_SUCCESS)
- s->result = f;
-
- service_unwatch_control_pid(s);
- unit_watch_all_pids(UNIT(s));
-
- s->control_command = s->exec_command[SERVICE_EXEC_STOP_POST];
- if (s->control_command) {
- s->control_command_id = SERVICE_EXEC_STOP_POST;
-
- r = service_spawn(s,
- s->control_command,
- s->timeout_stop_usec,
- false,
- !s->permissions_start_only,
- !s->root_directory_start_only,
- true,
- true,
- &s->control_pid);
- if (r < 0)
- goto fail;
-
- service_set_state(s, SERVICE_STOP_POST);
- } else
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_SUCCESS);
-
- return;
-
-fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'stop-post' task: %m", UNIT(s)->id);
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
-}
-
-static void service_enter_signal(Service *s, ServiceState state, ServiceResult f) {
- int r;
-
- assert(s);
-
- if (f != SERVICE_SUCCESS)
- s->result = f;
-
- unit_watch_all_pids(UNIT(s));
-
- r = unit_kill_context(
- UNIT(s),
- &s->kill_context,
- (state != SERVICE_STOP_SIGTERM && state != SERVICE_FINAL_SIGTERM && state != SERVICE_STOP_SIGABRT) ?
- KILL_KILL : (state == SERVICE_STOP_SIGABRT ? KILL_ABORT : KILL_TERMINATE),
- s->main_pid,
- s->control_pid,
- s->main_pid_alien);
-
- if (r < 0)
- goto fail;
-
- if (r > 0) {
- if (s->timeout_stop_usec > 0) {
- r = service_arm_timer(s, s->timeout_stop_usec);
- if (r < 0)
- goto fail;
- }
-
- service_set_state(s, state);
- } else if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGABRT)
- service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_SUCCESS);
- else if (state == SERVICE_STOP_SIGKILL)
- service_enter_stop_post(s, SERVICE_SUCCESS);
- else if (state == SERVICE_FINAL_SIGTERM)
- service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_SUCCESS);
- else
- service_enter_dead(s, SERVICE_SUCCESS, true);
-
- return;
-
-fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to kill processes: %m", UNIT(s)->id);
-
- if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGKILL ||
- state == SERVICE_STOP_SIGABRT)
- service_enter_stop_post(s, SERVICE_FAILURE_RESOURCES);
- else
- service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
-}
-
-static void service_enter_stop_by_notify(Service *s) {
- assert(s);
-
- unit_watch_all_pids(UNIT(s));
-
- if (s->timeout_stop_usec > 0)
- service_arm_timer(s, s->timeout_stop_usec);
-
- /* The service told us it's stopping, so it's as if we SIGTERM'd it. */
- service_set_state(s, SERVICE_STOP_SIGTERM);
-}
-
-static void service_enter_stop(Service *s, ServiceResult f) {
- int r;
-
- assert(s);
-
- if (f != SERVICE_SUCCESS)
- s->result = f;
-
- service_unwatch_control_pid(s);
- unit_watch_all_pids(UNIT(s));
-
- s->control_command = s->exec_command[SERVICE_EXEC_STOP];
- if (s->control_command) {
- s->control_command_id = SERVICE_EXEC_STOP;
-
- r = service_spawn(s,
- s->control_command,
- s->timeout_stop_usec,
- false,
- !s->permissions_start_only,
- !s->root_directory_start_only,
- false,
- true,
- &s->control_pid);
- if (r < 0)
- goto fail;
-
- service_set_state(s, SERVICE_STOP);
- } else
- service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_SUCCESS);
-
- return;
-
-fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'stop' task: %m", UNIT(s)->id);
- service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
-}
-
-static void service_enter_running(Service *s, ServiceResult f) {
- int main_pid_ok, cgroup_ok;
- assert(s);
-
- if (f != SERVICE_SUCCESS)
- s->result = f;
-
- main_pid_ok = main_pid_good(s);
- cgroup_ok = cgroup_good(s);
-
- if ((main_pid_ok > 0 || (main_pid_ok < 0 && cgroup_ok != 0)) &&
- (s->bus_name_good || s->type != SERVICE_DBUS)) {
-
- /* 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)
- service_enter_stop_by_notify(s);
- else
- service_set_state(s, SERVICE_RUNNING);
-
- } else if (s->remain_after_exit)
- service_set_state(s, SERVICE_EXITED);
- else
- service_enter_stop(s, SERVICE_SUCCESS);
-}
-
-static void service_enter_start_post(Service *s) {
- int r;
- assert(s);
-
- service_unwatch_control_pid(s);
- service_reset_watchdog(s);
-
- s->control_command = s->exec_command[SERVICE_EXEC_START_POST];
- if (s->control_command) {
- s->control_command_id = SERVICE_EXEC_START_POST;
-
- r = service_spawn(s,
- s->control_command,
- s->timeout_start_usec,
- false,
- !s->permissions_start_only,
- !s->root_directory_start_only,
- false,
- true,
- &s->control_pid);
- if (r < 0)
- goto fail;
-
- service_set_state(s, SERVICE_START_POST);
- } else
- service_enter_running(s, SERVICE_SUCCESS);
-
- return;
-
-fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'start-post' task: %m", UNIT(s)->id);
- service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
-}
-
-static void service_kill_control_processes(Service *s) {
- char *p;
-
- if (!UNIT(s)->cgroup_path)
- return;
-
- p = strjoina(UNIT(s)->cgroup_path, "/control");
- cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, p, SIGKILL, true, true, true, NULL);
-}
-
-static void service_enter_start(Service *s) {
- ExecCommand *c;
- pid_t pid;
- int r;
-
- assert(s);
-
- service_unwatch_control_pid(s);
- service_unwatch_main_pid(s);
-
- /* We want to ensure that nobody leaks processes from
- * START_PRE here, so let's go on a killing spree, People
- * should not spawn long running processes from START_PRE. */
- service_kill_control_processes(s);
-
- if (s->type == SERVICE_FORKING) {
- s->control_command_id = SERVICE_EXEC_START;
- c = s->control_command = s->exec_command[SERVICE_EXEC_START];
-
- s->main_command = NULL;
- } else {
- s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
- s->control_command = NULL;
-
- c = s->main_command = s->exec_command[SERVICE_EXEC_START];
- }
-
- if (!c) {
- assert(s->type == SERVICE_ONESHOT);
- service_enter_start_post(s);
- return;
- }
-
- r = service_spawn(s,
- c,
- IN_SET(s->type, SERVICE_FORKING, SERVICE_DBUS, SERVICE_NOTIFY, SERVICE_ONESHOT) ? s->timeout_start_usec : 0,
- true,
- true,
- true,
- true,
- false,
- &pid);
- if (r < 0)
- goto fail;
-
- if (s->type == SERVICE_SIMPLE || s->type == SERVICE_IDLE) {
- /* For simple services we immediately start
- * the START_POST binaries. */
-
- service_set_main_pid(s, pid);
- service_enter_start_post(s);
-
- } else if (s->type == SERVICE_FORKING) {
-
- /* For forking services we wait until the start
- * process exited. */
-
- s->control_pid = pid;
- service_set_state(s, SERVICE_START);
-
- } else if (s->type == SERVICE_ONESHOT ||
- s->type == SERVICE_DBUS ||
- s->type == SERVICE_NOTIFY) {
-
- /* For oneshot services we wait until the start
- * process exited, too, but it is our main process. */
-
- /* For D-Bus services we know the main pid right away,
- * but wait for the bus name to appear on the
- * bus. Notify services are similar. */
-
- service_set_main_pid(s, pid);
- service_set_state(s, SERVICE_START);
- } else
- assert_not_reached("Unknown service type");
-
- return;
-
-fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'start' task: %m", UNIT(s)->id);
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
-}
-
-static void service_enter_start_pre(Service *s) {
- int r;
-
- assert(s);
-
- service_unwatch_control_pid(s);
-
- s->control_command = s->exec_command[SERVICE_EXEC_START_PRE];
- if (s->control_command) {
- /* Before we start anything, let's clear up what might
- * be left from previous runs. */
- service_kill_control_processes(s);
-
- s->control_command_id = SERVICE_EXEC_START_PRE;
-
- r = service_spawn(s,
- s->control_command,
- s->timeout_start_usec,
- false,
- !s->permissions_start_only,
- !s->root_directory_start_only,
- true,
- true,
- &s->control_pid);
- if (r < 0)
- goto fail;
-
- service_set_state(s, SERVICE_START_PRE);
- } else
- service_enter_start(s);
-
- return;
-
-fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'start-pre' task: %m", UNIT(s)->id);
- service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
-}
-
-static void service_enter_restart(Service *s) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- int r;
-
- assert(s);
-
- if (UNIT(s)->job && UNIT(s)->job->type == JOB_STOP) {
- /* Don't restart things if we are going down anyway */
- log_unit_info(UNIT(s)->id, "Stop job pending for unit, delaying automatic restart.");
-
- r = service_arm_timer(s, s->restart_usec);
- if (r < 0)
- goto fail;
-
- return;
- }
-
- /* Any units that are bound to this service must also be
- * restarted. We use JOB_RESTART (instead of the more obvious
- * JOB_START) here so that those dependency jobs will be added
- * as well. */
- r = manager_add_job(UNIT(s)->manager, JOB_RESTART, UNIT(s), JOB_FAIL, false, &error, NULL);
- if (r < 0)
- goto fail;
-
- /* Note that we stay in the SERVICE_AUTO_RESTART state here,
- * it will be canceled as part of the service_stop() call that
- * is executed as part of JOB_RESTART. */
-
- log_unit_debug(UNIT(s)->id, "%s scheduled restart job.", UNIT(s)->id);
- return;
-
-fail:
- log_unit_warning(UNIT(s)->id, "%s failed to schedule restart job: %s", UNIT(s)->id, bus_error_message(&error, -r));
- service_enter_dead(s, SERVICE_FAILURE_RESOURCES, false);
-}
-
-static void service_enter_reload_by_notify(Service *s) {
- assert(s);
-
- if (s->timeout_start_usec > 0)
- service_arm_timer(s, s->timeout_start_usec);
-
- service_set_state(s, SERVICE_RELOAD);
-}
-
-static void service_enter_reload(Service *s) {
- int r;
-
- assert(s);
-
- service_unwatch_control_pid(s);
-
- s->control_command = s->exec_command[SERVICE_EXEC_RELOAD];
- if (s->control_command) {
- s->control_command_id = SERVICE_EXEC_RELOAD;
-
- r = service_spawn(s,
- s->control_command,
- s->timeout_start_usec,
- false,
- !s->permissions_start_only,
- !s->root_directory_start_only,
- false,
- true,
- &s->control_pid);
- if (r < 0)
- goto fail;
-
- service_set_state(s, SERVICE_RELOAD);
- } else
- service_enter_running(s, SERVICE_SUCCESS);
-
- return;
-
-fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'reload' task: %m", UNIT(s)->id);
- s->reload_result = SERVICE_FAILURE_RESOURCES;
- service_enter_running(s, SERVICE_SUCCESS);
-}
-
-static void service_run_next_control(Service *s) {
- int r;
-
- assert(s);
- assert(s->control_command);
- assert(s->control_command->command_next);
-
- assert(s->control_command_id != SERVICE_EXEC_START);
-
- s->control_command = s->control_command->command_next;
- service_unwatch_control_pid(s);
-
- r = service_spawn(s,
- s->control_command,
- IN_SET(s->state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD) ? s->timeout_start_usec : s->timeout_stop_usec,
- false,
- !s->permissions_start_only,
- !s->root_directory_start_only,
- s->control_command_id == SERVICE_EXEC_START_PRE ||
- s->control_command_id == SERVICE_EXEC_STOP_POST,
- true,
- &s->control_pid);
- if (r < 0)
- goto fail;
-
- return;
-
-fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run next control task: %m", UNIT(s)->id);
-
- if (s->state == SERVICE_START_PRE)
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
- else if (s->state == SERVICE_STOP)
- service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
- else if (s->state == SERVICE_STOP_POST)
- service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
- else if (s->state == SERVICE_RELOAD) {
- s->reload_result = SERVICE_FAILURE_RESOURCES;
- service_enter_running(s, SERVICE_SUCCESS);
- } else
- service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
-}
-
-static void service_run_next_main(Service *s) {
- pid_t pid;
- int r;
-
- assert(s);
- assert(s->main_command);
- assert(s->main_command->command_next);
- assert(s->type == SERVICE_ONESHOT);
-
- s->main_command = s->main_command->command_next;
- service_unwatch_main_pid(s);
-
- r = service_spawn(s,
- s->main_command,
- s->timeout_start_usec,
- true,
- true,
- true,
- true,
- false,
- &pid);
- if (r < 0)
- goto fail;
-
- service_set_main_pid(s, pid);
-
- return;
-
-fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run next main task: %m", UNIT(s)->id);
- service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
-}
-
-static int service_start_limit_test(Service *s) {
- assert(s);
-
- if (ratelimit_test(&s->start_limit))
- return 0;
-
- log_unit_warning(UNIT(s)->id, "start request repeated too quickly for %s", UNIT(s)->id);
-
- return failure_action(UNIT(s)->manager, s->start_limit_action, s->reboot_arg);
-}
-
-static int service_start(Unit *u) {
- Service *s = SERVICE(u);
- int r;
-
- assert(s);
-
- /* We cannot fulfill this request right now, try again later
- * please! */
- if (s->state == SERVICE_STOP ||
- s->state == SERVICE_STOP_SIGABRT ||
- s->state == SERVICE_STOP_SIGTERM ||
- s->state == SERVICE_STOP_SIGKILL ||
- s->state == SERVICE_STOP_POST ||
- s->state == SERVICE_FINAL_SIGTERM ||
- s->state == SERVICE_FINAL_SIGKILL)
- return -EAGAIN;
-
- /* Already on it! */
- if (s->state == SERVICE_START_PRE ||
- s->state == SERVICE_START ||
- s->state == SERVICE_START_POST)
- return 0;
-
- /* A service that will be restarted must be stopped first to
- * trigger BindsTo and/or OnFailure dependencies. If a user
- * does not want to wait for the holdoff time to elapse, the
- * service should be manually restarted, not started. We
- * simply return EAGAIN here, so that any start jobs stay
- * queued, and assume that the auto restart timer will
- * eventually trigger the restart. */
- if (s->state == SERVICE_AUTO_RESTART)
- return -EAGAIN;
-
- assert(s->state == SERVICE_DEAD || s->state == SERVICE_FAILED);
-
- /* Make sure we don't enter a busy loop of some kind. */
- r = service_start_limit_test(s);
- if (r < 0) {
- service_enter_dead(s, SERVICE_FAILURE_START_LIMIT, false);
- return r;
- }
-
- s->result = SERVICE_SUCCESS;
- s->reload_result = SERVICE_SUCCESS;
- s->main_pid_known = false;
- s->main_pid_alien = false;
- s->forbid_restart = false;
- s->reset_cpu_usage = true;
-
- free(s->status_text);
- s->status_text = NULL;
- s->status_errno = 0;
-
- s->notify_state = NOTIFY_UNKNOWN;
-
- service_enter_start_pre(s);
- return 1;
-}
-
-static int service_stop(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
-
- /* Don't create restart jobs from here. */
- s->forbid_restart = true;
-
- /* Already on it */
- if (s->state == SERVICE_STOP ||
- s->state == SERVICE_STOP_SIGABRT ||
- s->state == SERVICE_STOP_SIGTERM ||
- s->state == SERVICE_STOP_SIGKILL ||
- s->state == SERVICE_STOP_POST ||
- s->state == SERVICE_FINAL_SIGTERM ||
- s->state == SERVICE_FINAL_SIGKILL)
- return 0;
-
- /* A restart will be scheduled or is in progress. */
- if (s->state == SERVICE_AUTO_RESTART) {
- service_set_state(s, SERVICE_DEAD);
- return 0;
- }
-
- /* If there's already something running we go directly into
- * kill mode. */
- if (s->state == SERVICE_START_PRE ||
- s->state == SERVICE_START ||
- s->state == SERVICE_START_POST ||
- s->state == SERVICE_RELOAD) {
- service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_SUCCESS);
- return 0;
- }
-
- assert(s->state == SERVICE_RUNNING ||
- s->state == SERVICE_EXITED);
-
- service_enter_stop(s, SERVICE_SUCCESS);
- return 1;
-}
-
-static int service_reload(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
-
- assert(s->state == SERVICE_RUNNING || s->state == SERVICE_EXITED);
-
- service_enter_reload(s);
- return 0;
-}
-
-_pure_ static bool service_can_reload(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
-
- return !!s->exec_command[SERVICE_EXEC_RELOAD];
-}
-
-static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
- Service *s = SERVICE(u);
- ServiceFDStore *fs;
-
- assert(u);
- assert(f);
- assert(fds);
-
- unit_serialize_item(u, f, "state", service_state_to_string(s->state));
- unit_serialize_item(u, f, "result", service_result_to_string(s->result));
- unit_serialize_item(u, f, "reload-result", service_result_to_string(s->reload_result));
-
- if (s->control_pid > 0)
- unit_serialize_item_format(u, f, "control-pid", PID_FMT,
- s->control_pid);
-
- if (s->main_pid_known && s->main_pid > 0)
- unit_serialize_item_format(u, f, "main-pid", PID_FMT, s->main_pid);
-
- unit_serialize_item(u, f, "main-pid-known", yes_no(s->main_pid_known));
-
- if (s->status_text)
- unit_serialize_item(u, f, "status-text", s->status_text);
-
- /* FIXME: There's a minor uncleanliness here: if there are
- * multiple commands attached here, we will start from the
- * first one again */
- if (s->control_command_id >= 0)
- unit_serialize_item(u, f, "control-command",
- service_exec_command_to_string(s->control_command_id));
-
- if (s->socket_fd >= 0) {
- int copy;
-
- copy = fdset_put_dup(fds, s->socket_fd);
- if (copy < 0)
- return copy;
-
- unit_serialize_item_format(u, f, "socket-fd", "%i", copy);
- }
-
- if (s->bus_endpoint_fd >= 0) {
- int copy;
-
- copy = fdset_put_dup(fds, s->bus_endpoint_fd);
- if (copy < 0)
- return copy;
-
- unit_serialize_item_format(u, f, "endpoint-fd", "%i", copy);
- }
-
- LIST_FOREACH(fd_store, fs, s->fd_store) {
- int copy;
-
- copy = fdset_put_dup(fds, fs->fd);
- if (copy < 0)
- return copy;
-
- unit_serialize_item_format(u, f, "fd-store-fd", "%i", copy);
- }
-
- if (s->main_exec_status.pid > 0) {
- unit_serialize_item_format(u, f, "main-exec-status-pid", PID_FMT,
- s->main_exec_status.pid);
- dual_timestamp_serialize(f, "main-exec-status-start",
- &s->main_exec_status.start_timestamp);
- dual_timestamp_serialize(f, "main-exec-status-exit",
- &s->main_exec_status.exit_timestamp);
-
- if (dual_timestamp_is_set(&s->main_exec_status.exit_timestamp)) {
- unit_serialize_item_format(u, f, "main-exec-status-code", "%i",
- s->main_exec_status.code);
- unit_serialize_item_format(u, f, "main-exec-status-status", "%i",
- s->main_exec_status.status);
- }
- }
- if (dual_timestamp_is_set(&s->watchdog_timestamp))
- dual_timestamp_serialize(f, "watchdog-timestamp", &s->watchdog_timestamp);
-
- if (s->forbid_restart)
- unit_serialize_item(u, f, "forbid-restart", yes_no(s->forbid_restart));
-
- return 0;
-}
-
-static int service_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Service *s = SERVICE(u);
- int r;
-
- assert(u);
- assert(key);
- assert(value);
- assert(fds);
-
- if (streq(key, "state")) {
- ServiceState state;
-
- state = service_state_from_string(value);
- if (state < 0)
- log_unit_debug(u->id, "Failed to parse state value %s", value);
- else
- s->deserialized_state = state;
- } else if (streq(key, "result")) {
- ServiceResult f;
-
- f = service_result_from_string(value);
- if (f < 0)
- log_unit_debug(u->id, "Failed to parse result value %s", value);
- else if (f != SERVICE_SUCCESS)
- s->result = f;
-
- } else if (streq(key, "reload-result")) {
- ServiceResult f;
-
- f = service_result_from_string(value);
- if (f < 0)
- log_unit_debug(u->id, "Failed to parse reload result value %s", value);
- else if (f != SERVICE_SUCCESS)
- s->reload_result = f;
-
- } else if (streq(key, "control-pid")) {
- pid_t pid;
-
- if (parse_pid(value, &pid) < 0)
- log_unit_debug(u->id, "Failed to parse control-pid value %s", value);
- else
- s->control_pid = pid;
- } else if (streq(key, "main-pid")) {
- pid_t pid;
-
- if (parse_pid(value, &pid) < 0)
- log_unit_debug(u->id, "Failed to parse main-pid value %s", value);
- else {
- service_set_main_pid(s, pid);
- unit_watch_pid(UNIT(s), pid);
- }
- } else if (streq(key, "main-pid-known")) {
- int b;
-
- b = parse_boolean(value);
- if (b < 0)
- log_unit_debug(u->id, "Failed to parse main-pid-known value %s", value);
- else
- s->main_pid_known = b;
- } else if (streq(key, "status-text")) {
- char *t;
-
- t = strdup(value);
- if (!t)
- log_oom();
- else {
- free(s->status_text);
- s->status_text = t;
- }
-
- } else if (streq(key, "control-command")) {
- ServiceExecCommand id;
-
- id = service_exec_command_from_string(value);
- if (id < 0)
- log_unit_debug(u->id, "Failed to parse exec-command value %s", value);
- else {
- s->control_command_id = id;
- s->control_command = s->exec_command[id];
- }
- } else if (streq(key, "socket-fd")) {
- int fd;
-
- if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u->id, "Failed to parse socket-fd value %s", value);
- else {
- asynchronous_close(s->socket_fd);
- s->socket_fd = fdset_remove(fds, fd);
- }
- } else if (streq(key, "endpoint-fd")) {
- int fd;
-
- if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u->id, "Failed to parse endpoint-fd value %s", value);
- else {
- safe_close(s->bus_endpoint_fd);
- s->bus_endpoint_fd = fdset_remove(fds, fd);
- }
- } else if (streq(key, "fd-store-fd")) {
- int fd;
-
- if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u->id, "Failed to parse fd-store-fd value %s", value);
- else {
- r = service_add_fd_store(s, fd);
- if (r < 0)
- log_unit_error_errno(u->id, r, "Failed to add fd to store: %m");
- else if (r > 0)
- fdset_remove(fds, fd);
- }
-
- } else if (streq(key, "main-exec-status-pid")) {
- pid_t pid;
-
- if (parse_pid(value, &pid) < 0)
- log_unit_debug(u->id, "Failed to parse main-exec-status-pid value %s", value);
- else
- s->main_exec_status.pid = pid;
- } else if (streq(key, "main-exec-status-code")) {
- int i;
-
- if (safe_atoi(value, &i) < 0)
- log_unit_debug(u->id, "Failed to parse main-exec-status-code value %s", value);
- else
- s->main_exec_status.code = i;
- } else if (streq(key, "main-exec-status-status")) {
- int i;
-
- if (safe_atoi(value, &i) < 0)
- log_unit_debug(u->id, "Failed to parse main-exec-status-status value %s", value);
- else
- s->main_exec_status.status = i;
- } else if (streq(key, "main-exec-status-start"))
- dual_timestamp_deserialize(value, &s->main_exec_status.start_timestamp);
- else if (streq(key, "main-exec-status-exit"))
- dual_timestamp_deserialize(value, &s->main_exec_status.exit_timestamp);
- else if (streq(key, "watchdog-timestamp"))
- dual_timestamp_deserialize(value, &s->watchdog_timestamp);
- else if (streq(key, "forbid-restart")) {
- int b;
-
- b = parse_boolean(value);
- if (b < 0)
- log_unit_debug(u->id, "Failed to parse forbid-restart value %s", value);
- else
- s->forbid_restart = b;
- } else
- log_unit_debug(u->id, "Unknown serialization key '%s'", key);
-
- return 0;
-}
-
-_pure_ static UnitActiveState service_active_state(Unit *u) {
- const UnitActiveState *table;
-
- assert(u);
-
- table = SERVICE(u)->type == SERVICE_IDLE ? state_translation_table_idle : state_translation_table;
-
- return table[SERVICE(u)->state];
-}
-
-static const char *service_sub_state_to_string(Unit *u) {
- assert(u);
-
- return service_state_to_string(SERVICE(u)->state);
-}
-
-static bool service_check_gc(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
-
- /* Never clean up services that still have a process around,
- * even if the service is formally dead. */
- if (cgroup_good(s) > 0 ||
- main_pid_good(s) > 0 ||
- control_pid_good(s) > 0)
- return true;
-
- return false;
-}
-
-_pure_ static bool service_check_snapshot(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
-
- return s->socket_fd < 0;
-}
-
-static int service_retry_pid_file(Service *s) {
- int r;
-
- assert(s->pid_file);
- assert(s->state == SERVICE_START || s->state == SERVICE_START_POST);
-
- r = service_load_pid_file(s, false);
- if (r < 0)
- return r;
-
- service_unwatch_pid_file(s);
-
- service_enter_running(s, SERVICE_SUCCESS);
- return 0;
-}
-
-static int service_watch_pid_file(Service *s) {
- int r;
-
- log_unit_debug(UNIT(s)->id, "Setting watch for %s's PID file %s", UNIT(s)->id, s->pid_file_pathspec->path);
-
- r = path_spec_watch(s->pid_file_pathspec, service_dispatch_io);
- if (r < 0)
- goto fail;
-
- /* the pidfile might have appeared just before we set the watch */
- log_unit_debug(UNIT(s)->id, "Trying to read %s's PID file %s in case it changed", UNIT(s)->id, s->pid_file_pathspec->path);
- service_retry_pid_file(s);
-
- return 0;
-fail:
- log_unit_error_errno(UNIT(s)->id, r, "Failed to set a watch for %s's PID file %s: %m", UNIT(s)->id, s->pid_file_pathspec->path);
- service_unwatch_pid_file(s);
- return r;
-}
-
-static int service_demand_pid_file(Service *s) {
- PathSpec *ps;
-
- assert(s->pid_file);
- assert(!s->pid_file_pathspec);
-
- ps = new0(PathSpec, 1);
- if (!ps)
- return -ENOMEM;
-
- ps->unit = UNIT(s);
- ps->path = strdup(s->pid_file);
- if (!ps->path) {
- free(ps);
- return -ENOMEM;
- }
-
- path_kill_slashes(ps->path);
-
- /* PATH_CHANGED would not be enough. There are daemons (sendmail) that
- * keep their PID file open all the time. */
- ps->type = PATH_MODIFIED;
- ps->inotify_fd = -1;
-
- s->pid_file_pathspec = ps;
-
- return service_watch_pid_file(s);
-}
-
-static int service_dispatch_io(sd_event_source *source, int fd, uint32_t events, void *userdata) {
- PathSpec *p = userdata;
- Service *s;
-
- assert(p);
-
- s = SERVICE(p->unit);
-
- assert(s);
- assert(fd >= 0);
- assert(s->state == SERVICE_START || s->state == SERVICE_START_POST);
- assert(s->pid_file_pathspec);
- assert(path_spec_owns_inotify_fd(s->pid_file_pathspec, fd));
-
- log_unit_debug(UNIT(s)->id, "inotify event for %s", UNIT(s)->id);
-
- if (path_spec_fd_event(p, events) < 0)
- goto fail;
-
- if (service_retry_pid_file(s) == 0)
- return 0;
-
- if (service_watch_pid_file(s) < 0)
- goto fail;
-
- return 0;
-
-fail:
- service_unwatch_pid_file(s);
- service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
- return 0;
-}
-
-static void service_notify_cgroup_empty_event(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(u);
-
- log_unit_debug(u->id, "%s: cgroup is empty", u->id);
-
- switch (s->state) {
-
- /* Waiting for SIGCHLD is usually more interesting,
- * because it includes return codes/signals. Which is
- * why we ignore the cgroup events for most cases,
- * except when we don't know pid which to expect the
- * SIGCHLD for. */
-
- case SERVICE_START:
- case SERVICE_START_POST:
- /* If we were hoping for the daemon to write its PID file,
- * we can give up now. */
- if (s->pid_file_pathspec) {
- log_unit_warning(u->id, "%s never wrote its PID file. Failing.", UNIT(s)->id);
-
- service_unwatch_pid_file(s);
- if (s->state == SERVICE_START)
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
- else
- service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
- }
- break;
-
- case SERVICE_RUNNING:
- /* service_enter_running() will figure out what to do */
- service_enter_running(s, SERVICE_SUCCESS);
- break;
-
- case SERVICE_STOP_SIGABRT:
- case SERVICE_STOP_SIGTERM:
- case SERVICE_STOP_SIGKILL:
-
- if (main_pid_good(s) <= 0 && !control_pid_good(s))
- service_enter_stop_post(s, SERVICE_SUCCESS);
-
- break;
-
- case SERVICE_STOP_POST:
- case SERVICE_FINAL_SIGTERM:
- case SERVICE_FINAL_SIGKILL:
- if (main_pid_good(s) <= 0 && !control_pid_good(s))
- service_enter_dead(s, SERVICE_SUCCESS, true);
-
- break;
-
- default:
- ;
- }
-}
-
-static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
- Service *s = SERVICE(u);
- ServiceResult f;
-
- assert(s);
- assert(pid >= 0);
-
- if (UNIT(s)->fragment_path ? is_clean_exit(code, status, &s->success_status) :
- is_clean_exit_lsb(code, status, &s->success_status))
- f = SERVICE_SUCCESS;
- else if (code == CLD_EXITED)
- f = SERVICE_FAILURE_EXIT_CODE;
- else if (code == CLD_KILLED)
- f = SERVICE_FAILURE_SIGNAL;
- else if (code == CLD_DUMPED)
- f = SERVICE_FAILURE_CORE_DUMP;
- else
- assert_not_reached("Unknown code");
-
- if (s->main_pid == pid) {
- /* Forking services may occasionally move to a new PID.
- * As long as they update the PID file before exiting the old
- * PID, they're fine. */
- if (service_load_pid_file(s, false) == 0)
- return;
-
- s->main_pid = 0;
- exec_status_exit(&s->main_exec_status, &s->exec_context, pid, code, status);
-
- if (s->main_command) {
- /* If this is not a forking service than the
- * main process got started and hence we copy
- * the exit status so that it is recorded both
- * as main and as control process exit
- * status */
-
- s->main_command->exec_status = s->main_exec_status;
-
- if (s->main_command->ignore)
- f = SERVICE_SUCCESS;
- } else if (s->exec_command[SERVICE_EXEC_START]) {
-
- /* If this is a forked process, then we should
- * ignore the return value if this was
- * configured for the starter process */
-
- if (s->exec_command[SERVICE_EXEC_START]->ignore)
- f = SERVICE_SUCCESS;
- }
-
- log_unit_struct(u->id,
- f == SERVICE_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
- LOG_MESSAGE("%s: main process exited, code=%s, status=%i/%s",
- u->id, sigchld_code_to_string(code), status,
- strna(code == CLD_EXITED
- ? exit_status_to_string(status, EXIT_STATUS_FULL)
- : signal_to_string(status))),
- "EXIT_CODE=%s", sigchld_code_to_string(code),
- "EXIT_STATUS=%i", status,
- NULL);
-
- if (f != SERVICE_SUCCESS)
- s->result = f;
-
- if (s->main_command &&
- s->main_command->command_next &&
- f == SERVICE_SUCCESS) {
-
- /* There is another command to *
- * execute, so let's do that. */
-
- log_unit_debug(u->id, "%s running next main command for state %s", u->id, service_state_to_string(s->state));
- service_run_next_main(s);
-
- } else {
-
- /* The service exited, so the service is officially
- * gone. */
- s->main_command = NULL;
-
- switch (s->state) {
-
- case SERVICE_START_POST:
- case SERVICE_RELOAD:
- case SERVICE_STOP:
- /* Need to wait until the operation is
- * done */
- break;
-
- case SERVICE_START:
- if (s->type == SERVICE_ONESHOT) {
- /* This was our main goal, so let's go on */
- if (f == SERVICE_SUCCESS)
- service_enter_start_post(s);
- else
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
- break;
- }
-
- /* Fall through */
-
- case SERVICE_RUNNING:
- service_enter_running(s, f);
- break;
-
- case SERVICE_STOP_SIGABRT:
- case SERVICE_STOP_SIGTERM:
- case SERVICE_STOP_SIGKILL:
-
- if (!control_pid_good(s))
- service_enter_stop_post(s, f);
-
- /* If there is still a control process, wait for that first */
- break;
-
- case SERVICE_STOP_POST:
- case SERVICE_FINAL_SIGTERM:
- case SERVICE_FINAL_SIGKILL:
-
- if (!control_pid_good(s))
- service_enter_dead(s, f, true);
- break;
-
- default:
- assert_not_reached("Uh, main process died at wrong time.");
- }
- }
-
- } else if (s->control_pid == pid) {
- s->control_pid = 0;
-
- if (s->control_command) {
- exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status);
-
- if (s->control_command->ignore)
- f = SERVICE_SUCCESS;
- }
-
- log_unit_full(u->id,
- f == SERVICE_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
- "%s: control process exited, code=%s status=%i",
- u->id, sigchld_code_to_string(code), status);
-
- if (f != SERVICE_SUCCESS)
- s->result = f;
-
- /* Immediately get rid of the cgroup, so that the
- * kernel doesn't delay the cgroup empty messages for
- * the service cgroup any longer than necessary */
- service_kill_control_processes(s);
-
- if (s->control_command &&
- s->control_command->command_next &&
- f == SERVICE_SUCCESS) {
-
- /* There is another command to *
- * execute, so let's do that. */
-
- log_unit_debug(u->id, "%s running next control command for state %s", u->id, service_state_to_string(s->state));
- service_run_next_control(s);
-
- } else {
- /* No further commands for this step, so let's
- * figure out what to do next */
-
- s->control_command = NULL;
- s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
-
- log_unit_debug(u->id, "%s got final SIGCHLD for state %s", u->id, service_state_to_string(s->state));
-
- switch (s->state) {
-
- case SERVICE_START_PRE:
- if (f == SERVICE_SUCCESS)
- service_enter_start(s);
- else
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
- break;
-
- case SERVICE_START:
- if (s->type != SERVICE_FORKING)
- /* Maybe spurious event due to a reload that changed the type? */
- break;
-
- if (f != SERVICE_SUCCESS) {
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
- break;
- }
-
- if (s->pid_file) {
- bool has_start_post;
- int r;
-
- /* Let's try to load the pid file here if we can.
- * 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];
- r = service_load_pid_file(s, !has_start_post);
- if (!has_start_post && r < 0) {
- r = service_demand_pid_file(s);
- if (r < 0 || !cgroup_good(s))
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
- break;
- }
- } else
- service_search_main_pid(s);
-
- service_enter_start_post(s);
- break;
-
- case SERVICE_START_POST:
- if (f != SERVICE_SUCCESS) {
- service_enter_stop(s, f);
- break;
- }
-
- if (s->pid_file) {
- int r;
-
- r = service_load_pid_file(s, true);
- if (r < 0) {
- r = service_demand_pid_file(s);
- if (r < 0 || !cgroup_good(s))
- service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
- break;
- }
- } else
- service_search_main_pid(s);
-
- service_enter_running(s, SERVICE_SUCCESS);
- break;
-
- case SERVICE_RELOAD:
- if (f == SERVICE_SUCCESS) {
- service_load_pid_file(s, true);
- service_search_main_pid(s);
- }
-
- s->reload_result = f;
- service_enter_running(s, SERVICE_SUCCESS);
- break;
-
- case SERVICE_STOP:
- service_enter_signal(s, SERVICE_STOP_SIGTERM, f);
- break;
-
- case SERVICE_STOP_SIGABRT:
- case SERVICE_STOP_SIGTERM:
- case SERVICE_STOP_SIGKILL:
- if (main_pid_good(s) <= 0)
- service_enter_stop_post(s, f);
-
- /* If there is still a service
- * process around, wait until
- * that one quit, too */
- break;
-
- case SERVICE_STOP_POST:
- case SERVICE_FINAL_SIGTERM:
- case SERVICE_FINAL_SIGKILL:
- if (main_pid_good(s) <= 0)
- service_enter_dead(s, f, true);
- break;
-
- default:
- assert_not_reached("Uh, control process died at wrong time.");
- }
- }
- }
-
- /* Notify clients about changed exit status */
- unit_add_to_dbus_queue(u);
-
- /* We got one SIGCHLD for the service, let's watch all
- * processes that are now running of the service, and watch
- * that. Among the PIDs we then watch will be children
- * reassigned to us, which hopefully allows us to identify
- * when all children are gone */
- 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 finish this off */
- if (set_isempty(u->pids))
- service_notify_cgroup_empty_event(u);
-}
-
-static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
- Service *s = SERVICE(userdata);
-
- assert(s);
- assert(source == s->timer_event_source);
-
- switch (s->state) {
-
- case SERVICE_START_PRE:
- case SERVICE_START:
- log_unit_warning(UNIT(s)->id, "%s %s operation timed out. Terminating.", UNIT(s)->id, s->state == SERVICE_START ? "start" : "start-pre");
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT);
- break;
-
- case SERVICE_START_POST:
- log_unit_warning(UNIT(s)->id, "%s start-post operation timed out. Stopping.", UNIT(s)->id);
- service_enter_stop(s, SERVICE_FAILURE_TIMEOUT);
- break;
-
- case SERVICE_RELOAD:
- log_unit_warning(UNIT(s)->id, "%s reload operation timed out. Stopping.", UNIT(s)->id);
- s->reload_result = SERVICE_FAILURE_TIMEOUT;
- service_enter_running(s, SERVICE_SUCCESS);
- break;
-
- case SERVICE_STOP:
- log_unit_warning(UNIT(s)->id, "%s stopping timed out. Terminating.", UNIT(s)->id);
- service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
- break;
-
- case SERVICE_STOP_SIGABRT:
- log_unit_warning(UNIT(s)->id,
- "%s stop-sigabrt timed out. Terminating.", UNIT(s)->id);
- service_enter_signal(s, SERVICE_STOP_SIGTERM, s->result);
- break;
-
- case SERVICE_STOP_SIGTERM:
- if (s->kill_context.send_sigkill) {
- log_unit_warning(UNIT(s)->id, "%s stop-sigterm timed out. Killing.", UNIT(s)->id);
- service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT);
- } else {
- log_unit_warning(UNIT(s)->id, "%s stop-sigterm timed out. Skipping SIGKILL.", UNIT(s)->id);
- service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT);
- }
-
- break;
-
- case SERVICE_STOP_SIGKILL:
- /* Uh, we sent a SIGKILL and it is still not gone?
- * Must be something we cannot kill, so let's just be
- * weirded out and continue */
-
- log_unit_warning(UNIT(s)->id, "%s still around after SIGKILL. Ignoring.", UNIT(s)->id);
- service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT);
- break;
-
- case SERVICE_STOP_POST:
- log_unit_warning(UNIT(s)->id, "%s stop-post timed out. Terminating.", UNIT(s)->id);
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT);
- break;
-
- case SERVICE_FINAL_SIGTERM:
- if (s->kill_context.send_sigkill) {
- log_unit_warning(UNIT(s)->id, "%s stop-final-sigterm timed out. Killing.", UNIT(s)->id);
- service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_FAILURE_TIMEOUT);
- } else {
- log_unit_warning(UNIT(s)->id, "%s stop-final-sigterm timed out. Skipping SIGKILL. Entering failed mode.", UNIT(s)->id);
- service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, false);
- }
-
- break;
-
- case SERVICE_FINAL_SIGKILL:
- log_unit_warning(UNIT(s)->id, "%s still around after final SIGKILL. Entering failed mode.", UNIT(s)->id);
- service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, true);
- break;
-
- case SERVICE_AUTO_RESTART:
- log_unit_info(UNIT(s)->id,
- s->restart_usec > 0 ?
- "%s holdoff time over, scheduling restart." :
- "%s has no holdoff time, scheduling restart.",
- UNIT(s)->id);
- service_enter_restart(s);
- break;
-
- default:
- assert_not_reached("Timeout at wrong time.");
- }
-
- return 0;
-}
-
-static int service_dispatch_watchdog(sd_event_source *source, usec_t usec, void *userdata) {
- Service *s = SERVICE(userdata);
- char t[FORMAT_TIMESPAN_MAX];
-
- assert(s);
- assert(source == s->watchdog_event_source);
-
- log_unit_error(UNIT(s)->id, "%s watchdog timeout (limit %s)!", UNIT(s)->id,
- format_timespan(t, sizeof(t), s->watchdog_usec, 1));
-
- service_enter_signal(s, SERVICE_STOP_SIGABRT, SERVICE_FAILURE_WATCHDOG);
-
- return 0;
-}
-
-static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds) {
- Service *s = SERVICE(u);
- _cleanup_free_ char *cc = NULL;
- bool notify_dbus = false;
- const char *e;
-
- assert(u);
-
- cc = strv_join(tags, ", ");
- log_unit_debug(u->id, "%s: Got notification message from PID "PID_FMT" (%s)",
- u->id, pid, isempty(cc) ? "n/a" : cc);
-
- if (s->notify_access == NOTIFY_NONE) {
- log_unit_warning(u->id, "%s: Got notification message from PID "PID_FMT", but reception is disabled.", u->id, pid);
- return;
- }
-
- if (s->notify_access == NOTIFY_MAIN && pid != s->main_pid) {
- if (s->main_pid != 0)
- log_unit_warning(u->id, "%s: Got notification message from PID "PID_FMT", but reception only permitted for main PID "PID_FMT, u->id, pid, s->main_pid);
- else
- log_unit_debug(u->id, "%s: Got notification message from PID "PID_FMT", but reception only permitted for main PID which is currently not known", u->id, pid);
- return;
- }
-
- /* Interpret MAINPID= */
- e = strv_find_startswith(tags, "MAINPID=");
- if (e && IN_SET(s->state, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD)) {
- if (parse_pid(e, &pid) < 0)
- log_unit_warning(u->id, "Failed to parse MAINPID= field in notification message: %s", e);
- else {
- log_unit_debug(u->id, "%s: got MAINPID=%s", u->id, e);
-
- service_set_main_pid(s, pid);
- unit_watch_pid(UNIT(s), pid);
- notify_dbus = true;
- }
- }
-
- /* Interpret RELOADING= */
- if (strv_find(tags, "RELOADING=1")) {
-
- log_unit_debug(u->id, "%s: got RELOADING=1", u->id);
- s->notify_state = NOTIFY_RELOADING;
-
- if (s->state == SERVICE_RUNNING)
- service_enter_reload_by_notify(s);
-
- notify_dbus = true;
- }
-
- /* Interpret READY= */
- if (strv_find(tags, "READY=1")) {
-
- log_unit_debug(u->id, "%s: got READY=1", u->id);
- s->notify_state = NOTIFY_READY;
-
- /* Type=notify services inform us about completed
- * initialization with READY=1 */
- if (s->type == SERVICE_NOTIFY && s->state == SERVICE_START)
- service_enter_start_post(s);
-
- /* Sending READY=1 while we are reloading informs us
- * that the reloading is complete */
- if (s->state == SERVICE_RELOAD && s->control_pid == 0)
- service_enter_running(s, SERVICE_SUCCESS);
-
- notify_dbus = true;
- }
-
- /* Interpret STOPPING= */
- if (strv_find(tags, "STOPPING=1")) {
-
- log_unit_debug(u->id, "%s: got STOPPING=1", u->id);
- s->notify_state = NOTIFY_STOPPING;
-
- if (s->state == SERVICE_RUNNING)
- service_enter_stop_by_notify(s);
-
- notify_dbus = true;
- }
-
- /* Interpret STATUS= */
- e = strv_find_startswith(tags, "STATUS=");
- if (e) {
- _cleanup_free_ char *t = NULL;
-
- if (!isempty(e)) {
- if (!utf8_is_valid(e))
- log_unit_warning(u->id, "Status message in notification is not UTF-8 clean.");
- else {
- log_unit_debug(u->id, "%s: got STATUS=%s", u->id, e);
-
- t = strdup(e);
- if (!t)
- log_oom();
- }
- }
-
- if (!streq_ptr(s->status_text, t)) {
-
- free(s->status_text);
- s->status_text = t;
- t = NULL;
-
- notify_dbus = true;
- }
- }
-
- /* Interpret ERRNO= */
- e = strv_find_startswith(tags, "ERRNO=");
- if (e) {
- int status_errno;
-
- if (safe_atoi(e, &status_errno) < 0 || status_errno < 0)
- log_unit_warning(u->id, "Failed to parse ERRNO= field in notification message: %s", e);
- else {
- log_unit_debug(u->id, "%s: got ERRNO=%s", u->id, e);
-
- if (s->status_errno != status_errno) {
- s->status_errno = status_errno;
- notify_dbus = true;
- }
- }
- }
-
- /* Interpret WATCHDOG= */
- if (strv_find(tags, "WATCHDOG=1")) {
- log_unit_debug(u->id, "%s: got WATCHDOG=1", u->id);
- service_reset_watchdog(s);
- }
-
- /* Add the passed fds to the fd store */
- if (strv_find(tags, "FDSTORE=1")) {
- log_unit_debug(u->id, "%s: got FDSTORE=1", u->id);
- service_add_fd_store_set(s, fds);
- }
-
- /* Notify clients about changed status or main pid */
- if (notify_dbus)
- unit_add_to_dbus_queue(u);
-}
-
-static int service_get_timeout(Unit *u, uint64_t *timeout) {
- Service *s = SERVICE(u);
- int r;
-
- if (!s->timer_event_source)
- return 0;
-
- r = sd_event_source_get_time(s->timer_event_source, timeout);
- if (r < 0)
- return r;
-
- return 1;
-}
-
-static void service_bus_name_owner_change(
- Unit *u,
- const char *name,
- const char *old_owner,
- const char *new_owner) {
-
- Service *s = SERVICE(u);
- int r;
-
- assert(s);
- assert(name);
-
- assert(streq(s->bus_name, name));
- assert(old_owner || new_owner);
-
- if (old_owner && new_owner)
- log_unit_debug(u->id, "%s's D-Bus name %s changed owner from %s to %s", u->id, name, old_owner, new_owner);
- else if (old_owner)
- log_unit_debug(u->id, "%s's D-Bus name %s no longer registered by %s", u->id, name, old_owner);
- else
- log_unit_debug(u->id, "%s's D-Bus name %s now registered by %s", u->id, name, new_owner);
-
- s->bus_name_good = !!new_owner;
-
- if (s->type == SERVICE_DBUS) {
-
- /* service_enter_running() will figure out what to
- * do */
- if (s->state == SERVICE_RUNNING)
- service_enter_running(s, SERVICE_SUCCESS);
- else if (s->state == SERVICE_START && new_owner)
- service_enter_start_post(s);
-
- } else if (new_owner &&
- s->main_pid <= 0 &&
- (s->state == SERVICE_START ||
- s->state == SERVICE_START_POST ||
- s->state == SERVICE_RUNNING ||
- s->state == SERVICE_RELOAD)) {
-
- _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
- pid_t pid;
-
- /* Try to acquire PID from bus service */
-
- r = sd_bus_get_name_creds(u->manager->api_bus, name, SD_BUS_CREDS_PID, &creds);
- if (r >= 0)
- r = sd_bus_creds_get_pid(creds, &pid);
- if (r >= 0) {
- log_unit_debug(u->id, "%s's D-Bus name %s is now owned by process %u", u->id, name, (unsigned) pid);
-
- service_set_main_pid(s, pid);
- unit_watch_pid(UNIT(s), pid);
- }
- }
-}
-
-int service_set_socket_fd(Service *s, int fd, Socket *sock, bool selinux_context_net) {
- _cleanup_free_ char *peer = NULL;
- int r;
-
- assert(s);
- assert(fd >= 0);
-
- /* This is called by the socket code when instantiating a new
- * service for a stream socket and the socket needs to be
- * configured. */
-
- if (UNIT(s)->load_state != UNIT_LOADED)
- return -EINVAL;
-
- if (s->socket_fd >= 0)
- return -EBUSY;
-
- if (s->state != SERVICE_DEAD)
- return -EAGAIN;
-
- if (getpeername_pretty(fd, &peer) >= 0) {
-
- if (UNIT(s)->description) {
- _cleanup_free_ char *a;
-
- a = strjoin(UNIT(s)->description, " (", peer, ")", NULL);
- if (!a)
- return -ENOMEM;
-
- r = unit_set_description(UNIT(s), a);
- } else
- r = unit_set_description(UNIT(s), peer);
-
- if (r < 0)
- return r;
- }
-
- s->socket_fd = fd;
- s->socket_fd_selinux_context_net = selinux_context_net;
-
- unit_ref_set(&s->accept_socket, UNIT(sock));
-
- return unit_add_two_dependencies(UNIT(sock), UNIT_BEFORE, UNIT_TRIGGERS, UNIT(s), false);
-}
-
-static void service_reset_failed(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
-
- if (s->state == SERVICE_FAILED)
- service_set_state(s, SERVICE_DEAD);
-
- s->result = SERVICE_SUCCESS;
- s->reload_result = SERVICE_SUCCESS;
-
- RATELIMIT_RESET(s->start_limit);
-}
-
-static int service_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
- Service *s = SERVICE(u);
-
- return unit_kill_common(u, who, signo, s->main_pid, s->control_pid, error);
-}
-
-static const char* const service_state_table[_SERVICE_STATE_MAX] = {
- [SERVICE_DEAD] = "dead",
- [SERVICE_START_PRE] = "start-pre",
- [SERVICE_START] = "start",
- [SERVICE_START_POST] = "start-post",
- [SERVICE_RUNNING] = "running",
- [SERVICE_EXITED] = "exited",
- [SERVICE_RELOAD] = "reload",
- [SERVICE_STOP] = "stop",
- [SERVICE_STOP_SIGABRT] = "stop-sigabrt",
- [SERVICE_STOP_SIGTERM] = "stop-sigterm",
- [SERVICE_STOP_SIGKILL] = "stop-sigkill",
- [SERVICE_STOP_POST] = "stop-post",
- [SERVICE_FINAL_SIGTERM] = "final-sigterm",
- [SERVICE_FINAL_SIGKILL] = "final-sigkill",
- [SERVICE_FAILED] = "failed",
- [SERVICE_AUTO_RESTART] = "auto-restart",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState);
-
-static const char* const service_restart_table[_SERVICE_RESTART_MAX] = {
- [SERVICE_RESTART_NO] = "no",
- [SERVICE_RESTART_ON_SUCCESS] = "on-success",
- [SERVICE_RESTART_ON_FAILURE] = "on-failure",
- [SERVICE_RESTART_ON_ABNORMAL] = "on-abnormal",
- [SERVICE_RESTART_ON_WATCHDOG] = "on-watchdog",
- [SERVICE_RESTART_ON_ABORT] = "on-abort",
- [SERVICE_RESTART_ALWAYS] = "always",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(service_restart, ServiceRestart);
-
-static const char* const service_type_table[_SERVICE_TYPE_MAX] = {
- [SERVICE_SIMPLE] = "simple",
- [SERVICE_FORKING] = "forking",
- [SERVICE_ONESHOT] = "oneshot",
- [SERVICE_DBUS] = "dbus",
- [SERVICE_NOTIFY] = "notify",
- [SERVICE_IDLE] = "idle"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(service_type, ServiceType);
-
-static const char* const service_exec_command_table[_SERVICE_EXEC_COMMAND_MAX] = {
- [SERVICE_EXEC_START_PRE] = "ExecStartPre",
- [SERVICE_EXEC_START] = "ExecStart",
- [SERVICE_EXEC_START_POST] = "ExecStartPost",
- [SERVICE_EXEC_RELOAD] = "ExecReload",
- [SERVICE_EXEC_STOP] = "ExecStop",
- [SERVICE_EXEC_STOP_POST] = "ExecStopPost",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(service_exec_command, ServiceExecCommand);
-
-static const char* const notify_access_table[_NOTIFY_ACCESS_MAX] = {
- [NOTIFY_NONE] = "none",
- [NOTIFY_MAIN] = "main",
- [NOTIFY_ALL] = "all"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(notify_access, NotifyAccess);
-
-static const char* const notify_state_table[_NOTIFY_STATE_MAX] = {
- [NOTIFY_UNKNOWN] = "unknown",
- [NOTIFY_READY] = "ready",
- [NOTIFY_RELOADING] = "reloading",
- [NOTIFY_STOPPING] = "stopping",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(notify_state, NotifyState);
-
-static const char* const service_result_table[_SERVICE_RESULT_MAX] = {
- [SERVICE_SUCCESS] = "success",
- [SERVICE_FAILURE_RESOURCES] = "resources",
- [SERVICE_FAILURE_TIMEOUT] = "timeout",
- [SERVICE_FAILURE_EXIT_CODE] = "exit-code",
- [SERVICE_FAILURE_SIGNAL] = "signal",
- [SERVICE_FAILURE_CORE_DUMP] = "core-dump",
- [SERVICE_FAILURE_WATCHDOG] = "watchdog",
- [SERVICE_FAILURE_START_LIMIT] = "start-limit"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult);
-
-const UnitVTable service_vtable = {
- .object_size = sizeof(Service),
- .exec_context_offset = offsetof(Service, exec_context),
- .cgroup_context_offset = offsetof(Service, cgroup_context),
- .kill_context_offset = offsetof(Service, kill_context),
- .exec_runtime_offset = offsetof(Service, exec_runtime),
-
- .sections =
- "Unit\0"
- "Service\0"
- "Install\0",
- .private_section = "Service",
-
- .init = service_init,
- .done = service_done,
- .load = service_load,
- .release_resources = service_release_resources,
-
- .coldplug = service_coldplug,
-
- .dump = service_dump,
-
- .start = service_start,
- .stop = service_stop,
- .reload = service_reload,
-
- .can_reload = service_can_reload,
-
- .kill = service_kill,
-
- .serialize = service_serialize,
- .deserialize_item = service_deserialize_item,
-
- .active_state = service_active_state,
- .sub_state_to_string = service_sub_state_to_string,
-
- .check_gc = service_check_gc,
- .check_snapshot = service_check_snapshot,
-
- .sigchld_event = service_sigchld_event,
-
- .reset_failed = service_reset_failed,
-
- .notify_cgroup_empty = service_notify_cgroup_empty_event,
- .notify_message = service_notify_message,
-
- .bus_name_owner_change = service_bus_name_owner_change,
-
- .bus_interface = "org.freedesktop.systemd1.Service",
- .bus_vtable = bus_service_vtable,
- .bus_set_property = bus_service_set_property,
- .bus_commit_properties = bus_service_commit_properties,
-
- .get_timeout = service_get_timeout,
- .can_transient = true,
-
- .status_message_formats = {
- .starting_stopping = {
- [0] = "Starting %s...",
- [1] = "Stopping %s...",
- },
- .finished_start_job = {
- [JOB_DONE] = "Started %s.",
- [JOB_FAILED] = "Failed to start %s.",
- [JOB_DEPENDENCY] = "Dependency failed for %s.",
- [JOB_TIMEOUT] = "Timed out starting %s.",
- },
- .finished_stop_job = {
- [JOB_DONE] = "Stopped %s.",
- [JOB_FAILED] = "Stopped (with error) %s.",
- [JOB_TIMEOUT] = "Timed out stopping %s.",
- },
- },
-};
diff --git a/src/core/service.h b/src/core/service.h
deleted file mode 100644
index 23124e8ea..000000000
--- a/src/core/service.h
+++ /dev/null
@@ -1,242 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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;
-
-#include "path.h"
-#include "ratelimit.h"
-#include "kill.h"
-#include "exit-status.h"
-
-typedef enum ServiceState {
- SERVICE_DEAD,
- SERVICE_START_PRE,
- SERVICE_START,
- SERVICE_START_POST,
- SERVICE_RUNNING,
- SERVICE_EXITED, /* Nothing is running anymore, but RemainAfterExit is true hence this is OK */
- SERVICE_RELOAD,
- SERVICE_STOP, /* No STOP_PRE state, instead just register multiple STOP executables */
- SERVICE_STOP_SIGABRT, /* Watchdog timeout */
- SERVICE_STOP_SIGTERM,
- SERVICE_STOP_SIGKILL,
- SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, /* In case the STOP_POST executable hangs, we shoot that down, too */
- SERVICE_FINAL_SIGKILL,
- SERVICE_FAILED,
- SERVICE_AUTO_RESTART,
- _SERVICE_STATE_MAX,
- _SERVICE_STATE_INVALID = -1
-} ServiceState;
-
-typedef enum ServiceRestart {
- SERVICE_RESTART_NO,
- SERVICE_RESTART_ON_SUCCESS,
- SERVICE_RESTART_ON_FAILURE,
- SERVICE_RESTART_ON_ABNORMAL,
- SERVICE_RESTART_ON_WATCHDOG,
- SERVICE_RESTART_ON_ABORT,
- SERVICE_RESTART_ALWAYS,
- _SERVICE_RESTART_MAX,
- _SERVICE_RESTART_INVALID = -1
-} ServiceRestart;
-
-typedef enum ServiceType {
- SERVICE_SIMPLE, /* we fork and go on right-away (i.e. modern socket activated daemons) */
- SERVICE_FORKING, /* forks by itself (i.e. traditional daemons) */
- SERVICE_ONESHOT, /* we fork and wait until the program finishes (i.e. programs like fsck which run and need to finish before we continue) */
- SERVICE_DBUS, /* we fork and wait until a specific D-Bus name appears on the bus */
- SERVICE_NOTIFY, /* we fork and wait until a daemon sends us a ready message with sd_notify() */
- SERVICE_IDLE, /* much like simple, but delay exec() until all jobs are dispatched. */
- _SERVICE_TYPE_MAX,
- _SERVICE_TYPE_INVALID = -1
-} ServiceType;
-
-typedef enum ServiceExecCommand {
- SERVICE_EXEC_START_PRE,
- SERVICE_EXEC_START,
- SERVICE_EXEC_START_POST,
- SERVICE_EXEC_RELOAD,
- SERVICE_EXEC_STOP,
- SERVICE_EXEC_STOP_POST,
- _SERVICE_EXEC_COMMAND_MAX,
- _SERVICE_EXEC_COMMAND_INVALID = -1
-} ServiceExecCommand;
-
-typedef enum NotifyAccess {
- NOTIFY_NONE,
- NOTIFY_ALL,
- NOTIFY_MAIN,
- _NOTIFY_ACCESS_MAX,
- _NOTIFY_ACCESS_INVALID = -1
-} NotifyAccess;
-
-typedef enum NotifyState {
- NOTIFY_UNKNOWN,
- NOTIFY_READY,
- NOTIFY_RELOADING,
- NOTIFY_STOPPING,
- _NOTIFY_STATE_MAX,
- _NOTIFY_STATE_INVALID = -1
-} NotifyState;
-
-typedef enum ServiceResult {
- SERVICE_SUCCESS,
- SERVICE_FAILURE_RESOURCES,
- SERVICE_FAILURE_TIMEOUT,
- SERVICE_FAILURE_EXIT_CODE,
- SERVICE_FAILURE_SIGNAL,
- SERVICE_FAILURE_CORE_DUMP,
- SERVICE_FAILURE_WATCHDOG,
- SERVICE_FAILURE_START_LIMIT,
- _SERVICE_RESULT_MAX,
- _SERVICE_RESULT_INVALID = -1
-} ServiceResult;
-
-struct ServiceFDStore {
- Service *service;
-
- int fd;
- sd_event_source *event_source;
-
- LIST_FIELDS(ServiceFDStore, fd_store);
-};
-
-struct Service {
- Unit meta;
-
- ServiceType type;
- ServiceRestart restart;
- ExitStatusSet restart_prevent_status;
- ExitStatusSet restart_force_status;
- ExitStatusSet success_status;
-
- /* If set we'll read the main daemon PID from this file */
- char *pid_file;
-
- usec_t restart_usec;
- usec_t timeout_start_usec;
- usec_t timeout_stop_usec;
-
- dual_timestamp watchdog_timestamp;
- usec_t watchdog_usec;
- sd_event_source *watchdog_event_source;
-
- ExecCommand* exec_command[_SERVICE_EXEC_COMMAND_MAX];
-
- ExecContext exec_context;
- KillContext kill_context;
- CGroupContext cgroup_context;
-
- ServiceState state, deserialized_state;
-
- /* The exit status of the real main process */
- ExecStatus main_exec_status;
-
- /* The currently executed control process */
- ExecCommand *control_command;
-
- /* The currently executed main process, which may be NULL if
- * the main process got started via forking mode and not by
- * us */
- ExecCommand *main_command;
-
- /* The ID of the control command currently being executed */
- ServiceExecCommand control_command_id;
-
- /* Runtime data of the execution context */
- ExecRuntime *exec_runtime;
-
- pid_t main_pid, control_pid;
- int socket_fd;
- bool socket_fd_selinux_context_net;
-
- int bus_endpoint_fd;
-
- bool permissions_start_only;
- bool root_directory_start_only;
- bool remain_after_exit;
- bool guess_main_pid;
-
- /* If we shut down, remember why */
- ServiceResult result;
- ServiceResult reload_result;
-
- bool main_pid_known:1;
- bool main_pid_alien:1;
- bool bus_name_good:1;
- bool forbid_restart:1;
- bool start_timeout_defined:1;
-
- bool reset_cpu_usage:1;
-
- char *bus_name;
-
- char *status_text;
- int status_errno;
-
- RateLimit start_limit;
- FailureAction start_limit_action;
- FailureAction failure_action;
- char *reboot_arg;
-
- UnitRef accept_socket;
-
- sd_event_source *timer_event_source;
- PathSpec *pid_file_pathspec;
-
- NotifyAccess notify_access;
- NotifyState notify_state;
-
- ServiceFDStore *fd_store;
- unsigned n_fd_store;
- unsigned n_fd_store_max;
-};
-
-extern const UnitVTable service_vtable;
-
-struct Socket;
-
-int service_set_socket_fd(Service *s, int fd, struct Socket *socket, bool selinux_context_net);
-
-const char* service_state_to_string(ServiceState i) _const_;
-ServiceState service_state_from_string(const char *s) _pure_;
-
-const char* service_restart_to_string(ServiceRestart i) _const_;
-ServiceRestart service_restart_from_string(const char *s) _pure_;
-
-const char* service_type_to_string(ServiceType i) _const_;
-ServiceType service_type_from_string(const char *s) _pure_;
-
-const char* service_exec_command_to_string(ServiceExecCommand i) _const_;
-ServiceExecCommand service_exec_command_from_string(const char *s) _pure_;
-
-const char* notify_access_to_string(NotifyAccess i) _const_;
-NotifyAccess notify_access_from_string(const char *s) _pure_;
-
-const char* notify_state_to_string(NotifyState i) _const_;
-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_;
diff --git a/src/core/show-status.c b/src/core/show-status.c
deleted file mode 100644
index 02b1be73e..000000000
--- a/src/core/show-status.c
+++ /dev/null
@@ -1,42 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 "show-status.h"
-#include "util.h"
-
-int parse_show_status(const char *v, ShowStatus *ret) {
- int r;
-
- assert(v);
- assert(ret);
-
- if (streq(v, "auto")) {
- *ret = SHOW_STATUS_AUTO;
- return 0;
- }
-
- r = parse_boolean(v);
- if (r < 0)
- return r;
-
- *ret = r ? SHOW_STATUS_YES : SHOW_STATUS_NO;
- return 0;
-}
diff --git a/src/core/show-status.h b/src/core/show-status.h
deleted file mode 100644
index a2b215374..000000000
--- a/src/core/show-status.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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/>.
-***/
-
-/* Manager status */
-
-typedef enum ShowStatus {
- _SHOW_STATUS_UNSET = -2,
- SHOW_STATUS_AUTO = -1,
- SHOW_STATUS_NO = 0,
- SHOW_STATUS_YES = 1,
- SHOW_STATUS_TEMPORARY = 2,
-} ShowStatus;
-
-int parse_show_status(const char *v, ShowStatus *ret);
diff --git a/src/core/shutdown.c b/src/core/shutdown.c
deleted file mode 100644
index 70a461e38..000000000
--- a/src/core/shutdown.c
+++ /dev/null
@@ -1,412 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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/>.
-***/
-
-#include <sys/mman.h>
-#include <sys/reboot.h>
-#include <linux/reboot.h>
-#include <sys/stat.h>
-#include <sys/mount.h>
-#include <errno.h>
-#include <unistd.h>
-#include <signal.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <getopt.h>
-
-#include "missing.h"
-#include "log.h"
-#include "fileio.h"
-#include "umount.h"
-#include "util.h"
-#include "virt.h"
-#include "watchdog.h"
-#include "killall.h"
-#include "cgroup-util.h"
-#include "def.h"
-#include "switch-root.h"
-
-#define FINALIZE_ATTEMPTS 50
-
-static char* arg_verb;
-
-static int parse_argv(int argc, char *argv[]) {
- enum {
- ARG_LOG_LEVEL = 0x100,
- ARG_LOG_TARGET,
- ARG_LOG_COLOR,
- ARG_LOG_LOCATION,
- };
-
- static const struct option options[] = {
- { "log-level", required_argument, NULL, ARG_LOG_LEVEL },
- { "log-target", required_argument, NULL, ARG_LOG_TARGET },
- { "log-color", optional_argument, NULL, ARG_LOG_COLOR },
- { "log-location", optional_argument, NULL, ARG_LOG_LOCATION },
- {}
- };
-
- int c, r;
-
- assert(argc >= 1);
- assert(argv);
-
- /* "-" prevents getopt from permuting argv[] and moving the verb away
- * from argv[1]. Our interface to initrd promises it'll be there. */
- while ((c = getopt_long(argc, argv, "-", options, NULL)) >= 0)
- switch (c) {
-
- case ARG_LOG_LEVEL:
- r = log_set_max_level_from_string(optarg);
- if (r < 0)
- log_error("Failed to parse log level %s, ignoring.", optarg);
-
- break;
-
- case ARG_LOG_TARGET:
- r = log_set_target_from_string(optarg);
- if (r < 0)
- log_error("Failed to parse log target %s, ignoring", optarg);
-
- break;
-
- case ARG_LOG_COLOR:
-
- if (optarg) {
- r = log_show_color_from_string(optarg);
- if (r < 0)
- log_error("Failed to parse log color setting %s, ignoring", optarg);
- } else
- log_show_color(true);
-
- break;
-
- case ARG_LOG_LOCATION:
- if (optarg) {
- r = log_show_location_from_string(optarg);
- if (r < 0)
- log_error("Failed to parse log location setting %s, ignoring", optarg);
- } else
- log_show_location(true);
-
- break;
-
- case '\001':
- if (!arg_verb)
- arg_verb = optarg;
- else
- log_error("Excess arguments, ignoring");
- break;
-
- case '?':
- return -EINVAL;
-
- default:
- assert_not_reached("Unhandled option code.");
- }
-
- if (!arg_verb) {
- log_error("Verb argument missing.");
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int switch_root_initramfs(void) {
- if (mount("/run/initramfs", "/run/initramfs", NULL, MS_BIND, NULL) < 0)
- return log_error_errno(errno, "Failed to mount bind /run/initramfs on /run/initramfs: %m");
-
- if (mount(NULL, "/run/initramfs", NULL, MS_PRIVATE, NULL) < 0)
- return log_error_errno(errno, "Failed to make /run/initramfs private mount: %m");
-
- /* switch_root with MS_BIND, because there might still be processes lurking around, which have open file descriptors.
- * /run/initramfs/shutdown will take care of these.
- * Also do not detach the old root, because /run/initramfs/shutdown needs to access it.
- */
- return switch_root("/run/initramfs", "/oldroot", false, MS_BIND);
-}
-
-
-int main(int argc, char *argv[]) {
- bool need_umount, need_swapoff, need_loop_detach, need_dm_detach;
- bool in_container, use_watchdog = false;
- _cleanup_free_ char *cgroup = NULL;
- char *arguments[3];
- unsigned retries;
- int cmd, r;
- static const char* const dirs[] = {SYSTEM_SHUTDOWN_PATH, NULL};
-
- log_parse_environment();
- r = parse_argv(argc, argv);
- if (r < 0)
- goto error;
-
- /* journald will die if not gone yet. The log target defaults
- * to console, but may have been changed by command line options. */
-
- log_close_console(); /* force reopen of /dev/console */
- log_open();
-
- umask(0022);
-
- if (getpid() != 1) {
- log_error("Not executed by init (PID 1).");
- r = -EPERM;
- goto error;
- }
-
- if (streq(arg_verb, "reboot"))
- cmd = RB_AUTOBOOT;
- else if (streq(arg_verb, "poweroff"))
- cmd = RB_POWER_OFF;
- else if (streq(arg_verb, "halt"))
- cmd = RB_HALT_SYSTEM;
- else if (streq(arg_verb, "kexec"))
- cmd = LINUX_REBOOT_CMD_KEXEC;
- else {
- r = -EINVAL;
- log_error("Unknown action '%s'.", arg_verb);
- goto error;
- }
-
- cg_get_root_path(&cgroup);
-
- use_watchdog = !!getenv("WATCHDOG_USEC");
-
- /* lock us into memory */
- mlockall(MCL_CURRENT|MCL_FUTURE);
-
- log_info("Sending SIGTERM to remaining processes...");
- broadcast_signal(SIGTERM, true, true);
-
- log_info("Sending SIGKILL to remaining processes...");
- broadcast_signal(SIGKILL, true, false);
-
- in_container = detect_container(NULL) > 0;
-
- need_umount = !in_container;
- need_swapoff = !in_container;
- need_loop_detach = !in_container;
- need_dm_detach = !in_container;
-
- /* Unmount all mountpoints, swaps, and loopback devices */
- for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) {
- bool changed = false;
-
- if (use_watchdog)
- watchdog_ping();
-
- /* Let's trim the cgroup tree on each iteration so
- that we leave an empty cgroup tree around, so that
- container managers get a nice notify event when we
- are down */
- if (cgroup)
- cg_trim(SYSTEMD_CGROUP_CONTROLLER, cgroup, false);
-
- if (need_umount) {
- log_info("Unmounting file systems.");
- r = umount_all(&changed);
- if (r == 0) {
- need_umount = false;
- log_info("All filesystems unmounted.");
- } else if (r > 0)
- log_info("Not all file systems unmounted, %d left.", r);
- else
- log_error_errno(r, "Failed to unmount file systems: %m");
- }
-
- if (need_swapoff) {
- log_info("Deactivating swaps.");
- r = swapoff_all(&changed);
- if (r == 0) {
- need_swapoff = false;
- log_info("All swaps deactivated.");
- } else if (r > 0)
- log_info("Not all swaps deactivated, %d left.", r);
- else
- log_error_errno(r, "Failed to deactivate swaps: %m");
- }
-
- if (need_loop_detach) {
- log_info("Detaching loop devices.");
- r = loopback_detach_all(&changed);
- if (r == 0) {
- need_loop_detach = false;
- log_info("All loop devices detached.");
- } else if (r > 0)
- log_info("Not all loop devices detached, %d left.", r);
- else
- log_error_errno(r, "Failed to detach loop devices: %m");
- }
-
- if (need_dm_detach) {
- log_info("Detaching DM devices.");
- r = dm_detach_all(&changed);
- if (r == 0) {
- need_dm_detach = false;
- log_info("All DM devices detached.");
- } else if (r > 0)
- log_info("Not all DM devices detached, %d left.", r);
- else
- log_error_errno(r, "Failed to detach DM devices: %m");
- }
-
- if (!need_umount && !need_swapoff && !need_loop_detach && !need_dm_detach) {
- if (retries > 0)
- log_info("All filesystems, swaps, loop devices, DM devices detached.");
- /* Yay, done */
- goto initrd_jump;
- }
-
- /* If in this iteration we didn't manage to
- * unmount/deactivate anything, we simply give up */
- if (!changed) {
- log_info("Cannot finalize remaining%s%s%s%s continuing.",
- need_umount ? " file systems," : "",
- need_swapoff ? " swap devices," : "",
- need_loop_detach ? " loop devices," : "",
- need_dm_detach ? " DM devices," : "");
- goto initrd_jump;
- }
-
- log_debug("After %u retries, couldn't finalize remaining %s%s%s%s trying again.",
- retries + 1,
- 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:
-
- arguments[0] = NULL;
- arguments[1] = arg_verb;
- arguments[2] = NULL;
- execute_directories(dirs, DEFAULT_TIMEOUT_USEC, arguments);
-
- if (!in_container && !in_initrd() &&
- access("/run/initramfs/shutdown", X_OK) == 0) {
- r = switch_root_initramfs();
- if (r >= 0) {
- argv[0] = (char*) "/shutdown";
-
- setsid();
- make_console_stdio();
-
- log_info("Successfully changed into root pivot.\n"
- "Returning to initrd...");
-
- execv("/shutdown", argv);
- log_error_errno(errno, "Failed to execute shutdown binary: %m");
- } else
- log_error_errno(r, "Failed to switch root to \"/run/initramfs\": %m");
-
- }
-
- if (need_umount || need_swapoff || need_loop_detach || need_dm_detach)
- log_error("Failed to finalize %s%s%s%s ignoring",
- need_umount ? " file systems," : "",
- need_swapoff ? " swap devices," : "",
- need_loop_detach ? " loop devices," : "",
- need_dm_detach ? " DM devices," : "");
-
- /* The kernel will automaticall flush ATA disks and suchlike
- * on reboot(), but the file systems need to be synce'd
- * explicitly in advance. So let's do this here, but not
- * needlessly slow down containers. */
- if (!in_container)
- sync();
-
- switch (cmd) {
-
- case LINUX_REBOOT_CMD_KEXEC:
-
- if (!in_container) {
- /* We cheat and exec kexec to avoid doing all its work */
- pid_t pid;
-
- log_info("Rebooting with kexec.");
-
- pid = fork();
- if (pid < 0)
- log_error_errno(errno, "Failed to fork: %m");
- else if (pid == 0) {
-
- const char * const args[] = {
- KEXEC, "-e", NULL
- };
-
- /* Child */
-
- execv(args[0], (char * const *) args);
- _exit(EXIT_FAILURE);
- } else
- wait_for_terminate_and_warn("kexec", pid, true);
- }
-
- cmd = RB_AUTOBOOT;
- /* Fall through */
-
- case RB_AUTOBOOT:
-
- if (!in_container) {
- _cleanup_free_ char *param = NULL;
-
- if (read_one_line_file(REBOOT_PARAM_FILE, &param) >= 0) {
- log_info("Rebooting with argument '%s'.", param);
- syscall(SYS_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, param);
- }
- }
-
- log_info("Rebooting.");
- break;
-
- case RB_POWER_OFF:
- log_info("Powering off.");
- break;
-
- case RB_HALT_SYSTEM:
- log_info("Halting system.");
- break;
-
- default:
- assert_not_reached("Unknown magic");
- }
-
- reboot(cmd);
- if (errno == EPERM && in_container) {
- /* If we are in a container, and we lacked
- * CAP_SYS_BOOT just exit, this will kill our
- * container for good. */
- log_info("Exiting container.");
- exit(0);
- }
-
- log_error_errno(errno, "Failed to invoke reboot(): %m");
- r = -errno;
-
- error:
- log_emergency_errno(r, "Critical error while doing system shutdown: %m");
-
- freeze();
-}
diff --git a/src/core/slice.c b/src/core/slice.c
deleted file mode 100644
index 0285c49ae..000000000
--- a/src/core/slice.c
+++ /dev/null
@@ -1,305 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 "unit.h"
-#include "slice.h"
-#include "log.h"
-#include "dbus-slice.h"
-#include "special.h"
-#include "unit-name.h"
-
-static const UnitActiveState state_translation_table[_SLICE_STATE_MAX] = {
- [SLICE_DEAD] = UNIT_INACTIVE,
- [SLICE_ACTIVE] = UNIT_ACTIVE
-};
-
-static void slice_set_state(Slice *t, SliceState state) {
- SliceState old_state;
- assert(t);
-
- old_state = t->state;
- t->state = state;
-
- if (state != old_state)
- log_debug("%s changed %s -> %s",
- UNIT(t)->id,
- 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);
-}
-
-static int slice_add_parent_slice(Slice *s) {
- char *a, *dash;
- Unit *parent;
- int r;
-
- assert(s);
-
- if (UNIT_ISSET(UNIT(s)->slice))
- return 0;
-
- if (unit_has_name(UNIT(s), SPECIAL_ROOT_SLICE))
- return 0;
-
- a = strdupa(UNIT(s)->id);
- dash = strrchr(a, '-');
- if (dash)
- strcpy(dash, ".slice");
- else
- a = (char*) SPECIAL_ROOT_SLICE;
-
- r = manager_load_unit(UNIT(s)->manager, a, NULL, NULL, &parent);
- if (r < 0)
- return r;
-
- unit_ref_set(&UNIT(s)->slice, parent);
- return 0;
-}
-
-static int slice_add_default_dependencies(Slice *s) {
- int r;
-
- assert(s);
-
- /* Make sure slices are unloaded on shutdown */
- r = unit_add_two_dependencies_by_name(
- UNIT(s),
- UNIT_BEFORE, UNIT_CONFLICTS,
- SPECIAL_SHUTDOWN_TARGET, NULL, true);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-static int slice_verify(Slice *s) {
- assert(s);
-
- if (UNIT(s)->load_state != UNIT_LOADED)
- return 0;
-
- if (UNIT_DEREF(UNIT(s)->slice)) {
- char *a, *dash;
-
- a = strdupa(UNIT(s)->id);
- dash = strrchr(a, '-');
- if (dash)
- strcpy(dash, ".slice");
- else
- a = (char*) SPECIAL_ROOT_SLICE;
-
- if (!unit_has_name(UNIT_DEREF(UNIT(s)->slice), a)) {
- log_unit_error(UNIT(s)->id,
- "%s located outside its parent slice. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
-static int slice_load(Unit *u) {
- Slice *s = SLICE(u);
- int r;
-
- assert(s);
-
- r = unit_load_fragment_and_dropin_optional(u);
- if (r < 0)
- return r;
-
- /* This is a new unit? Then let's add in some extras */
- if (u->load_state == UNIT_LOADED) {
-
- r = unit_patch_contexts(u);
- if (r < 0)
- return r;
-
- r = slice_add_parent_slice(s);
- if (r < 0)
- return r;
-
- if (u->default_dependencies) {
- r = slice_add_default_dependencies(s);
- if (r < 0)
- return r;
- }
- }
-
- return slice_verify(s);
-}
-
-static int slice_coldplug(Unit *u, Hashmap *deferred_work) {
- Slice *t = SLICE(u);
-
- assert(t);
- assert(t->state == SLICE_DEAD);
-
- if (t->deserialized_state != t->state)
- slice_set_state(t, t->deserialized_state);
-
- return 0;
-}
-
-static void slice_dump(Unit *u, FILE *f, const char *prefix) {
- Slice *t = SLICE(u);
-
- assert(t);
- assert(f);
-
- fprintf(f,
- "%sSlice State: %s\n",
- prefix, slice_state_to_string(t->state));
-
- cgroup_context_dump(&t->cgroup_context, f, prefix);
-}
-
-static int slice_start(Unit *u) {
- Slice *t = SLICE(u);
-
- assert(t);
- assert(t->state == SLICE_DEAD);
-
- (void) unit_realize_cgroup(u);
- (void) unit_reset_cpu_usage(u);
-
- slice_set_state(t, SLICE_ACTIVE);
- return 1;
-}
-
-static int slice_stop(Unit *u) {
- Slice *t = SLICE(u);
-
- assert(t);
- assert(t->state == SLICE_ACTIVE);
-
- /* We do not need to destroy the cgroup explicitly,
- * unit_notify() will do that for us anyway. */
-
- slice_set_state(t, SLICE_DEAD);
- return 1;
-}
-
-static int slice_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
- return unit_kill_common(u, who, signo, -1, -1, error);
-}
-
-static int slice_serialize(Unit *u, FILE *f, FDSet *fds) {
- Slice *s = SLICE(u);
-
- assert(s);
- assert(f);
- assert(fds);
-
- unit_serialize_item(u, f, "state", slice_state_to_string(s->state));
- return 0;
-}
-
-static int slice_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Slice *s = SLICE(u);
-
- assert(u);
- assert(key);
- assert(value);
- assert(fds);
-
- if (streq(key, "state")) {
- SliceState state;
-
- state = slice_state_from_string(value);
- if (state < 0)
- log_debug("Failed to parse state value %s", value);
- else
- s->deserialized_state = state;
-
- } else
- log_debug("Unknown serialization key '%s'", key);
-
- return 0;
-}
-
-_pure_ static UnitActiveState slice_active_state(Unit *u) {
- assert(u);
-
- return state_translation_table[SLICE(u)->state];
-}
-
-_pure_ static const char *slice_sub_state_to_string(Unit *u) {
- assert(u);
-
- return slice_state_to_string(SLICE(u)->state);
-}
-
-static const char* const slice_state_table[_SLICE_STATE_MAX] = {
- [SLICE_DEAD] = "dead",
- [SLICE_ACTIVE] = "active"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(slice_state, SliceState);
-
-const UnitVTable slice_vtable = {
- .object_size = sizeof(Slice),
- .cgroup_context_offset = offsetof(Slice, cgroup_context),
-
- .sections =
- "Unit\0"
- "Slice\0"
- "Install\0",
- .private_section = "Slice",
-
- .no_alias = true,
- .no_instances = true,
-
- .load = slice_load,
-
- .coldplug = slice_coldplug,
-
- .dump = slice_dump,
-
- .start = slice_start,
- .stop = slice_stop,
-
- .kill = slice_kill,
-
- .serialize = slice_serialize,
- .deserialize_item = slice_deserialize_item,
-
- .active_state = slice_active_state,
- .sub_state_to_string = slice_sub_state_to_string,
-
- .bus_interface = "org.freedesktop.systemd1.Slice",
- .bus_vtable = bus_slice_vtable,
- .bus_set_property = bus_slice_set_property,
- .bus_commit_properties = bus_slice_commit_properties,
-
- .status_message_formats = {
- .finished_start_job = {
- [JOB_DONE] = "Created slice %s.",
- [JOB_DEPENDENCY] = "Dependency failed for %s.",
- },
- .finished_stop_job = {
- [JOB_DONE] = "Removed slice %s.",
- },
- },
-};
diff --git a/src/core/slice.h b/src/core/slice.h
deleted file mode 100644
index ac648e56f..000000000
--- a/src/core/slice.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 Slice Slice;
-
-
-typedef enum SliceState {
- SLICE_DEAD,
- SLICE_ACTIVE,
- _SLICE_STATE_MAX,
- _SLICE_STATE_INVALID = -1
-} SliceState;
-
-struct Slice {
- Unit meta;
-
- SliceState state, deserialized_state;
-
- CGroupContext cgroup_context;
-};
-
-extern const UnitVTable slice_vtable;
-
-const char* slice_state_to_string(SliceState i) _const_;
-SliceState slice_state_from_string(const char *s) _pure_;
diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c
deleted file mode 100644
index ff2a02004..000000000
--- a/src/core/smack-setup.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright (C) 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 <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <dirent.h>
-
-#include "macro.h"
-#include "smack-setup.h"
-#include "util.h"
-#include "fileio.h"
-#include "log.h"
-
-#define SMACK_CONFIG "/etc/smack/accesses.d/"
-#define CIPSO_CONFIG "/etc/smack/cipso.d/"
-
-#ifdef HAVE_SMACK
-
-static int write_rules(const char* dstpath, const char* srcdir) {
- _cleanup_fclose_ FILE *dst = NULL;
- _cleanup_closedir_ DIR *dir = NULL;
- struct dirent *entry;
- char buf[NAME_MAX];
- int dfd = -1;
- int r = 0;
-
- dst = fopen(dstpath, "we");
- if (!dst) {
- if (errno != ENOENT)
- log_warning_errno(errno, "Failed to open %s: %m", dstpath);
- return -errno; /* negative error */
- }
-
- /* write rules to dst from every file in the directory */
- dir = opendir(srcdir);
- if (!dir) {
- if (errno != ENOENT)
- log_warning_errno(errno, "Failed to opendir %s: %m", srcdir);
- return errno; /* positive on purpose */
- }
-
- dfd = dirfd(dir);
- assert(dfd >= 0);
-
- FOREACH_DIRENT(entry, dir, return 0) {
- int fd;
- _cleanup_fclose_ FILE *policy = NULL;
-
- fd = openat(dfd, entry->d_name, O_RDONLY|O_CLOEXEC);
- if (fd < 0) {
- if (r == 0)
- r = -errno;
- log_warning_errno(errno, "Failed to open %s: %m", entry->d_name);
- continue;
- }
-
- policy = fdopen(fd, "re");
- if (!policy) {
- if (r == 0)
- r = -errno;
- safe_close(fd);
- log_error_errno(errno, "Failed to open %s: %m", entry->d_name);
- continue;
- }
-
- /* load2 write rules in the kernel require a line buffered stream */
- FOREACH_LINE(buf, policy,
- log_error_errno(errno, "Failed to read line from %s: %m",
- entry->d_name)) {
- if (!fputs(buf, dst)) {
- if (r == 0)
- r = -EINVAL;
- log_error("Failed to write line to %s", dstpath);
- break;
- }
- if (fflush(dst)) {
- if (r == 0)
- r = -errno;
- log_error_errno(errno, "Failed to flush writes to %s: %m", dstpath);
- break;
- }
- }
- }
-
- return r;
-}
-
-#endif
-
-int mac_smack_setup(bool *loaded_policy) {
-
-#ifdef HAVE_SMACK
-
- int r;
-
- assert(loaded_policy);
-
- r = write_rules("/sys/fs/smackfs/load2", SMACK_CONFIG);
- switch(r) {
- case -ENOENT:
- log_debug("Smack is not enabled in the kernel.");
- return 0;
- case ENOENT:
- log_debug("Smack access rules directory " SMACK_CONFIG " not found");
- return 0;
- case 0:
- log_info("Successfully loaded Smack policies.");
- break;
- default:
- log_warning("Failed to load Smack access rules: %s, ignoring.",
- strerror(abs(r)));
- return 0;
- }
-
-#ifdef SMACK_RUN_LABEL
- r = write_string_file("/proc/self/attr/current", SMACK_RUN_LABEL);
- if (r)
- log_warning("Failed to set SMACK label \"%s\" on self: %s",
- SMACK_RUN_LABEL, strerror(-r));
-#endif
-
- r = write_rules("/sys/fs/smackfs/cipso2", CIPSO_CONFIG);
- switch(r) {
- case -ENOENT:
- log_debug("Smack/CIPSO is not enabled in the kernel.");
- return 0;
- case ENOENT:
- log_debug("Smack/CIPSO access rules directory " CIPSO_CONFIG " not found");
- return 0;
- case 0:
- log_info("Successfully loaded Smack/CIPSO policies.");
- break;
- default:
- log_warning("Failed to load Smack/CIPSO access rules: %s, ignoring.",
- strerror(abs(r)));
- return 0;
- }
-
- *loaded_policy = true;
-
-#endif
-
- return 0;
-}
diff --git a/src/core/smack-setup.h b/src/core/smack-setup.h
deleted file mode 100644
index 1cab7718f..000000000
--- a/src/core/smack-setup.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright (C) 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/snapshot.c b/src/core/snapshot.c
deleted file mode 100644
index b1d844877..000000000
--- a/src/core/snapshot.c
+++ /dev/null
@@ -1,312 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 "unit.h"
-#include "snapshot.h"
-#include "unit-name.h"
-#include "dbus-snapshot.h"
-#include "bus-common-errors.h"
-
-static const UnitActiveState state_translation_table[_SNAPSHOT_STATE_MAX] = {
- [SNAPSHOT_DEAD] = UNIT_INACTIVE,
- [SNAPSHOT_ACTIVE] = UNIT_ACTIVE
-};
-
-static void snapshot_init(Unit *u) {
- Snapshot *s = SNAPSHOT(u);
-
- assert(s);
- assert(UNIT(s)->load_state == UNIT_STUB);
-
- UNIT(s)->ignore_on_isolate = true;
- UNIT(s)->ignore_on_snapshot = true;
- UNIT(s)->allow_isolate = true;
-}
-
-static void snapshot_set_state(Snapshot *s, SnapshotState state) {
- SnapshotState old_state;
- assert(s);
-
- old_state = s->state;
- s->state = state;
-
- if (state != old_state)
- log_unit_debug(UNIT(s)->id,
- "%s changed %s -> %s",
- UNIT(s)->id,
- snapshot_state_to_string(old_state),
- snapshot_state_to_string(state));
-
- unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
-}
-
-static int snapshot_load(Unit *u) {
- Snapshot *s = SNAPSHOT(u);
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
-
- /* Make sure that only snapshots created via snapshot_create()
- * can be loaded */
- if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
- return -ENOENT;
-
- u->load_state = UNIT_LOADED;
- return 0;
-}
-
-static int snapshot_coldplug(Unit *u, Hashmap *deferred_work) {
- Snapshot *s = SNAPSHOT(u);
-
- assert(s);
- assert(s->state == SNAPSHOT_DEAD);
-
- if (s->deserialized_state != s->state)
- snapshot_set_state(s, s->deserialized_state);
-
- return 0;
-}
-
-static void snapshot_dump(Unit *u, FILE *f, const char *prefix) {
- Snapshot *s = SNAPSHOT(u);
-
- assert(s);
- assert(f);
-
- fprintf(f,
- "%sSnapshot State: %s\n"
- "%sClean Up: %s\n",
- prefix, snapshot_state_to_string(s->state),
- prefix, yes_no(s->cleanup));
-}
-
-static int snapshot_start(Unit *u) {
- Snapshot *s = SNAPSHOT(u);
-
- assert(s);
- assert(s->state == SNAPSHOT_DEAD);
-
- snapshot_set_state(s, SNAPSHOT_ACTIVE);
-
- if (s->cleanup)
- unit_add_to_cleanup_queue(u);
-
- return 1;
-}
-
-static int snapshot_stop(Unit *u) {
- Snapshot *s = SNAPSHOT(u);
-
- assert(s);
- assert(s->state == SNAPSHOT_ACTIVE);
-
- snapshot_set_state(s, SNAPSHOT_DEAD);
- return 1;
-}
-
-static int snapshot_serialize(Unit *u, FILE *f, FDSet *fds) {
- Snapshot *s = SNAPSHOT(u);
- Unit *other;
- Iterator i;
-
- assert(s);
- assert(f);
- assert(fds);
-
- unit_serialize_item(u, f, "state", snapshot_state_to_string(s->state));
- unit_serialize_item(u, f, "cleanup", yes_no(s->cleanup));
- SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
- unit_serialize_item(u, f, "wants", other->id);
-
- return 0;
-}
-
-static int snapshot_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Snapshot *s = SNAPSHOT(u);
- int r;
-
- assert(u);
- assert(key);
- assert(value);
- assert(fds);
-
- if (streq(key, "state")) {
- SnapshotState state;
-
- state = snapshot_state_from_string(value);
- if (state < 0)
- log_unit_debug(u->id, "Failed to parse state value %s", value);
- else
- s->deserialized_state = state;
-
- } else if (streq(key, "cleanup")) {
-
- r = parse_boolean(value);
- if (r < 0)
- log_unit_debug(u->id, "Failed to parse cleanup value %s", value);
- else
- s->cleanup = r;
-
- } else if (streq(key, "wants")) {
-
- r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, value, NULL, true);
- if (r < 0)
- return r;
- } else
- log_unit_debug(u->id, "Unknown serialization key '%s'", key);
-
- return 0;
-}
-
-_pure_ static UnitActiveState snapshot_active_state(Unit *u) {
- assert(u);
-
- return state_translation_table[SNAPSHOT(u)->state];
-}
-
-_pure_ static const char *snapshot_sub_state_to_string(Unit *u) {
- assert(u);
-
- return snapshot_state_to_string(SNAPSHOT(u)->state);
-}
-
-int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e, Snapshot **_s) {
- _cleanup_free_ char *n = NULL;
- Unit *other, *u = NULL;
- Iterator i;
- int r;
- const char *k;
-
- assert(m);
- assert(_s);
-
- if (name) {
- if (!unit_name_is_valid(name, TEMPLATE_INVALID))
- return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name);
-
- if (unit_name_to_type(name) != UNIT_SNAPSHOT)
- return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s lacks snapshot suffix.", name);
-
- if (manager_get_unit(m, name))
- return sd_bus_error_setf(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", name);
-
- } else {
-
- for (;;) {
- if (asprintf(&n, "snapshot-%u.snapshot", ++ m->n_snapshots) < 0)
- return -ENOMEM;
-
- if (!manager_get_unit(m, n)) {
- name = n;
- break;
- }
-
- free(n);
- n = NULL;
- }
- }
-
- r = manager_load_unit_prepare(m, name, NULL, e, &u);
- if (r < 0)
- goto fail;
-
- u->transient = true;
- manager_dispatch_load_queue(m);
- assert(u->load_state == UNIT_LOADED);
-
- HASHMAP_FOREACH_KEY(other, k, m->units, i) {
-
- if (other->ignore_on_snapshot ||
- other->transient)
- continue;
-
- if (k != other->id)
- continue;
-
- if (UNIT_VTABLE(other)->check_snapshot)
- if (!UNIT_VTABLE(other)->check_snapshot(other))
- continue;
-
- if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
- continue;
-
- r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, other, true);
- if (r < 0)
- goto fail;
- }
-
- SNAPSHOT(u)->cleanup = cleanup;
- *_s = SNAPSHOT(u);
-
- log_unit_info(u->id, "Created snapshot %s.", u->id);
-
- return 0;
-
-fail:
- if (u)
- unit_add_to_cleanup_queue(u);
-
- return r;
-}
-
-void snapshot_remove(Snapshot *s) {
- assert(s);
-
- log_unit_info(UNIT(s)->id, "Removing snapshot %s.", UNIT(s)->id);
-
- unit_add_to_cleanup_queue(UNIT(s));
-}
-
-static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = {
- [SNAPSHOT_DEAD] = "dead",
- [SNAPSHOT_ACTIVE] = "active"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState);
-
-const UnitVTable snapshot_vtable = {
- .object_size = sizeof(Snapshot),
-
- .no_alias = true,
- .no_instances = true,
- .no_gc = true,
-
- .init = snapshot_init,
- .load = snapshot_load,
-
- .coldplug = snapshot_coldplug,
-
- .dump = snapshot_dump,
-
- .start = snapshot_start,
- .stop = snapshot_stop,
-
- .serialize = snapshot_serialize,
- .deserialize_item = snapshot_deserialize_item,
-
- .active_state = snapshot_active_state,
- .sub_state_to_string = snapshot_sub_state_to_string,
-
- .bus_interface = "org.freedesktop.systemd1.Snapshot",
- .bus_vtable = bus_snapshot_vtable
-};
diff --git a/src/core/snapshot.h b/src/core/snapshot.h
deleted file mode 100644
index f2451b119..000000000
--- a/src/core/snapshot.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 Snapshot Snapshot;
-
-
-typedef enum SnapshotState {
- SNAPSHOT_DEAD,
- SNAPSHOT_ACTIVE,
- _SNAPSHOT_STATE_MAX,
- _SNAPSHOT_STATE_INVALID = -1
-} SnapshotState;
-
-struct Snapshot {
- Unit meta;
-
- SnapshotState state, deserialized_state;
-
- bool cleanup;
-};
-
-extern const UnitVTable snapshot_vtable;
-
-int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e, Snapshot **s);
-void snapshot_remove(Snapshot *s);
-
-const char* snapshot_state_to_string(SnapshotState i) _const_;
-SnapshotState snapshot_state_from_string(const char *s) _pure_;
diff --git a/src/core/socket.c b/src/core/socket.c
deleted file mode 100644
index f67370b4c..000000000
--- a/src/core/socket.c
+++ /dev/null
@@ -1,2740 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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/stat.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/epoll.h>
-#include <signal.h>
-#include <arpa/inet.h>
-#include <netinet/tcp.h>
-#include <mqueue.h>
-
-#include "sd-event.h"
-#include "log.h"
-#include "strv.h"
-#include "mkdir.h"
-#include "path-util.h"
-#include "unit-name.h"
-#include "unit-printf.h"
-#include "missing.h"
-#include "special.h"
-#include "label.h"
-#include "exit-status.h"
-#include "def.h"
-#include "smack-util.h"
-#include "bus-util.h"
-#include "bus-error.h"
-#include "selinux-util.h"
-#include "dbus-socket.h"
-#include "unit.h"
-#include "socket.h"
-
-static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = {
- [SOCKET_DEAD] = UNIT_INACTIVE,
- [SOCKET_START_PRE] = UNIT_ACTIVATING,
- [SOCKET_START_CHOWN] = UNIT_ACTIVATING,
- [SOCKET_START_POST] = UNIT_ACTIVATING,
- [SOCKET_LISTENING] = UNIT_ACTIVE,
- [SOCKET_RUNNING] = UNIT_ACTIVE,
- [SOCKET_STOP_PRE] = UNIT_DEACTIVATING,
- [SOCKET_STOP_PRE_SIGTERM] = UNIT_DEACTIVATING,
- [SOCKET_STOP_PRE_SIGKILL] = UNIT_DEACTIVATING,
- [SOCKET_STOP_POST] = UNIT_DEACTIVATING,
- [SOCKET_FINAL_SIGTERM] = UNIT_DEACTIVATING,
- [SOCKET_FINAL_SIGKILL] = UNIT_DEACTIVATING,
- [SOCKET_FAILED] = UNIT_FAILED
-};
-
-static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
-static int socket_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
-
-static void socket_init(Unit *u) {
- Socket *s = SOCKET(u);
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
-
- s->backlog = SOMAXCONN;
- s->timeout_usec = u->manager->default_timeout_start_usec;
- s->directory_mode = 0755;
- s->socket_mode = 0666;
-
- s->max_connections = 64;
-
- s->priority = -1;
- s->ip_tos = -1;
- s->ip_ttl = -1;
- s->mark = -1;
-
- s->exec_context.std_output = u->manager->default_std_output;
- s->exec_context.std_error = u->manager->default_std_error;
-
- s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID;
-}
-
-static void socket_unwatch_control_pid(Socket *s) {
- assert(s);
-
- if (s->control_pid <= 0)
- return;
-
- unit_unwatch_pid(UNIT(s), s->control_pid);
- s->control_pid = 0;
-}
-
-void socket_free_ports(Socket *s) {
- SocketPort *p;
-
- assert(s);
-
- while ((p = s->ports)) {
- LIST_REMOVE(port, s->ports, p);
-
- sd_event_source_unref(p->event_source);
-
- safe_close(p->fd);
- free(p->path);
- free(p);
- }
-}
-
-static void socket_done(Unit *u) {
- Socket *s = SOCKET(u);
-
- assert(s);
-
- socket_free_ports(s);
-
- s->exec_runtime = exec_runtime_unref(s->exec_runtime);
- exec_command_free_array(s->exec_command, _SOCKET_EXEC_COMMAND_MAX);
- s->control_command = NULL;
-
- socket_unwatch_control_pid(s);
-
- unit_ref_unset(&s->service);
-
- free(s->tcp_congestion);
- s->tcp_congestion = NULL;
-
- free(s->bind_to_device);
- s->bind_to_device = NULL;
-
- free(s->smack);
- free(s->smack_ip_in);
- free(s->smack_ip_out);
-
- strv_free(s->symlinks);
-
- free(s->user);
- free(s->group);
-
- s->timer_event_source = sd_event_source_unref(s->timer_event_source);
-}
-
-static int socket_arm_timer(Socket *s) {
- int r;
-
- assert(s);
-
- if (s->timeout_usec <= 0) {
- s->timer_event_source = sd_event_source_unref(s->timer_event_source);
- return 0;
- }
-
- if (s->timer_event_source) {
- r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_usec);
- if (r < 0)
- return r;
-
- return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
- }
-
- return sd_event_add_time(
- UNIT(s)->manager->event,
- &s->timer_event_source,
- CLOCK_MONOTONIC,
- now(CLOCK_MONOTONIC) + s->timeout_usec, 0,
- socket_dispatch_timer, s);
-}
-
-int socket_instantiate_service(Socket *s) {
- _cleanup_free_ char *prefix = NULL, *name = NULL;
- int r;
- Unit *u;
-
- assert(s);
-
- /* This fills in s->service if it isn't filled in yet. For
- * Accept=yes sockets we create the next connection service
- * here. For Accept=no this is mostly a NOP since the service
- * is figured out at load time anyway. */
-
- if (UNIT_DEREF(s->service) || !s->accept)
- return 0;
-
- prefix = unit_name_to_prefix(UNIT(s)->id);
- if (!prefix)
- return -ENOMEM;
-
- if (asprintf(&name, "%s@%u.service", prefix, s->n_accepted) < 0)
- return -ENOMEM;
-
- r = manager_load_unit(UNIT(s)->manager, name, NULL, NULL, &u);
- if (r < 0)
- return r;
-
- u->no_gc = true;
- unit_ref_set(&s->service, u);
-
- return unit_add_two_dependencies(UNIT(s), UNIT_BEFORE, UNIT_TRIGGERS, u, false);
-}
-
-static bool have_non_accept_socket(Socket *s) {
- SocketPort *p;
-
- assert(s);
-
- if (!s->accept)
- return true;
-
- LIST_FOREACH(port, p, s->ports) {
-
- if (p->type != SOCKET_SOCKET)
- return true;
-
- if (!socket_address_can_accept(&p->address))
- return true;
- }
-
- return false;
-}
-
-static int socket_add_mount_links(Socket *s) {
- SocketPort *p;
- int r;
-
- assert(s);
-
- LIST_FOREACH(port, p, s->ports) {
- const char *path = NULL;
-
- if (p->type == SOCKET_SOCKET)
- path = socket_address_get_path(&p->address);
- else if (p->type == SOCKET_FIFO || p->type == SOCKET_SPECIAL)
- path = p->path;
-
- if (!path)
- continue;
-
- r = unit_require_mounts_for(UNIT(s), path);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-static int socket_add_device_link(Socket *s) {
- char *t;
-
- assert(s);
-
- if (!s->bind_to_device || streq(s->bind_to_device, "lo"))
- return 0;
-
- t = strjoina("/sys/subsystem/net/devices/", s->bind_to_device);
- return unit_add_node_link(UNIT(s), t, false);
-}
-
-static int socket_add_default_dependencies(Socket *s) {
- int r;
- assert(s);
-
- r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SOCKETS_TARGET, NULL, true);
- if (r < 0)
- return r;
-
- if (UNIT(s)->manager->running_as == SYSTEMD_SYSTEM) {
- r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
- if (r < 0)
- return r;
- }
-
- return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
-}
-
-_pure_ static bool socket_has_exec(Socket *s) {
- unsigned i;
- assert(s);
-
- for (i = 0; i < _SOCKET_EXEC_COMMAND_MAX; i++)
- if (s->exec_command[i])
- return true;
-
- return false;
-}
-
-static int socket_add_extras(Socket *s) {
- Unit *u = UNIT(s);
- int r;
-
- assert(s);
-
- if (have_non_accept_socket(s)) {
-
- if (!UNIT_DEREF(s->service)) {
- Unit *x;
-
- r = unit_load_related_unit(u, ".service", &x);
- if (r < 0)
- return r;
-
- unit_ref_set(&s->service, x);
- }
-
- r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(s->service), true);
- if (r < 0)
- return r;
- }
-
- r = socket_add_mount_links(s);
- if (r < 0)
- return r;
-
- r = socket_add_device_link(s);
- if (r < 0)
- return r;
-
- r = unit_patch_contexts(u);
- if (r < 0)
- return r;
-
- if (socket_has_exec(s)) {
- r = unit_add_exec_dependencies(u, &s->exec_context);
- if (r < 0)
- return r;
-
- r = unit_add_default_slice(u, &s->cgroup_context);
- if (r < 0)
- return r;
- }
-
- if (u->default_dependencies) {
- r = socket_add_default_dependencies(s);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-static const char *socket_find_symlink_target(Socket *s) {
- const char *found = NULL;
- SocketPort *p;
-
- LIST_FOREACH(port, p, s->ports) {
- const char *f = NULL;
-
- switch (p->type) {
-
- case SOCKET_FIFO:
- f = p->path;
- break;
-
- case SOCKET_SOCKET:
- if (p->address.sockaddr.un.sun_path[0] != 0)
- f = p->address.sockaddr.un.sun_path;
- break;
-
- default:
- break;
- }
-
- if (f) {
- if (found)
- return NULL;
-
- found = f;
- }
- }
-
- return found;
-}
-
-static int socket_verify(Socket *s) {
- assert(s);
-
- if (UNIT(s)->load_state != UNIT_LOADED)
- return 0;
-
- if (!s->ports) {
- log_unit_error(UNIT(s)->id, "%s lacks Listen setting. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
-
- if (s->accept && have_non_accept_socket(s)) {
- log_unit_error(UNIT(s)->id, "%s configured for accepting sockets, but sockets are non-accepting. Refusing.",
- UNIT(s)->id);
- return -EINVAL;
- }
-
- if (s->accept && s->max_connections <= 0) {
- log_unit_error(UNIT(s)->id, "%s's MaxConnection setting too small. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
-
- if (s->accept && UNIT_DEREF(s->service)) {
- log_unit_error(UNIT(s)->id, "Explicit service configuration for accepting sockets not supported on %s. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
-
- if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) {
- log_unit_error(UNIT(s)->id, "%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
-
- if (!strv_isempty(s->symlinks) && !socket_find_symlink_target(s)) {
- log_unit_error(UNIT(s)->id, "%s has symlinks set but none or more than one node in the file system. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int socket_load(Unit *u) {
- Socket *s = SOCKET(u);
- int r;
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
-
- r = unit_load_fragment_and_dropin(u);
- if (r < 0)
- return r;
-
- if (u->load_state == UNIT_LOADED) {
- /* This is a new unit? Then let's add in some extras */
- r = socket_add_extras(s);
- if (r < 0)
- return r;
- }
-
- return socket_verify(s);
-}
-
-_const_ static const char* listen_lookup(int family, int type) {
-
- if (family == AF_NETLINK)
- return "ListenNetlink";
-
- if (type == SOCK_STREAM)
- return "ListenStream";
- else if (type == SOCK_DGRAM)
- return "ListenDatagram";
- else if (type == SOCK_SEQPACKET)
- return "ListenSequentialPacket";
-
- assert_not_reached("Unknown socket type");
- return NULL;
-}
-
-static void socket_dump(Unit *u, FILE *f, const char *prefix) {
- char time_string[FORMAT_TIMESPAN_MAX];
- SocketExecCommand c;
- Socket *s = SOCKET(u);
- SocketPort *p;
- const char *prefix2;
-
- assert(s);
- assert(f);
-
- prefix = strempty(prefix);
- prefix2 = strjoina(prefix, "\t");
-
- fprintf(f,
- "%sSocket State: %s\n"
- "%sResult: %s\n"
- "%sBindIPv6Only: %s\n"
- "%sBacklog: %u\n"
- "%sSocketMode: %04o\n"
- "%sDirectoryMode: %04o\n"
- "%sKeepAlive: %s\n"
- "%sNoDelay: %s\n"
- "%sFreeBind: %s\n"
- "%sTransparent: %s\n"
- "%sBroadcast: %s\n"
- "%sPassCredentials: %s\n"
- "%sPassSecurity: %s\n"
- "%sTCPCongestion: %s\n"
- "%sRemoveOnStop: %s\n"
- "%sSELinuxContextFromNet: %s\n",
- prefix, socket_state_to_string(s->state),
- prefix, socket_result_to_string(s->result),
- prefix, socket_address_bind_ipv6_only_to_string(s->bind_ipv6_only),
- prefix, s->backlog,
- prefix, s->socket_mode,
- prefix, s->directory_mode,
- prefix, yes_no(s->keep_alive),
- prefix, yes_no(s->no_delay),
- prefix, yes_no(s->free_bind),
- prefix, yes_no(s->transparent),
- prefix, yes_no(s->broadcast),
- prefix, yes_no(s->pass_cred),
- prefix, yes_no(s->pass_sec),
- prefix, strna(s->tcp_congestion),
- prefix, yes_no(s->remove_on_stop),
- prefix, yes_no(s->selinux_context_from_net));
-
- if (s->control_pid > 0)
- fprintf(f,
- "%sControl PID: "PID_FMT"\n",
- prefix, s->control_pid);
-
- if (s->bind_to_device)
- fprintf(f,
- "%sBindToDevice: %s\n",
- prefix, s->bind_to_device);
-
- if (s->accept)
- fprintf(f,
- "%sAccepted: %u\n"
- "%sNConnections: %u\n"
- "%sMaxConnections: %u\n",
- prefix, s->n_accepted,
- prefix, s->n_connections,
- prefix, s->max_connections);
-
- if (s->priority >= 0)
- fprintf(f,
- "%sPriority: %i\n",
- prefix, s->priority);
-
- if (s->receive_buffer > 0)
- fprintf(f,
- "%sReceiveBuffer: %zu\n",
- prefix, s->receive_buffer);
-
- if (s->send_buffer > 0)
- fprintf(f,
- "%sSendBuffer: %zu\n",
- prefix, s->send_buffer);
-
- if (s->ip_tos >= 0)
- fprintf(f,
- "%sIPTOS: %i\n",
- prefix, s->ip_tos);
-
- if (s->ip_ttl >= 0)
- fprintf(f,
- "%sIPTTL: %i\n",
- prefix, s->ip_ttl);
-
- if (s->pipe_size > 0)
- fprintf(f,
- "%sPipeSize: %zu\n",
- prefix, s->pipe_size);
-
- if (s->mark >= 0)
- fprintf(f,
- "%sMark: %i\n",
- prefix, s->mark);
-
- if (s->mq_maxmsg > 0)
- fprintf(f,
- "%sMessageQueueMaxMessages: %li\n",
- prefix, s->mq_maxmsg);
-
- if (s->mq_msgsize > 0)
- fprintf(f,
- "%sMessageQueueMessageSize: %li\n",
- prefix, s->mq_msgsize);
-
- if (s->reuse_port)
- fprintf(f,
- "%sReusePort: %s\n",
- prefix, yes_no(s->reuse_port));
-
- if (s->smack)
- fprintf(f,
- "%sSmackLabel: %s\n",
- prefix, s->smack);
-
- if (s->smack_ip_in)
- fprintf(f,
- "%sSmackLabelIPIn: %s\n",
- prefix, s->smack_ip_in);
-
- if (s->smack_ip_out)
- fprintf(f,
- "%sSmackLabelIPOut: %s\n",
- prefix, s->smack_ip_out);
-
- if (!isempty(s->user) || !isempty(s->group))
- fprintf(f,
- "%sOwnerUser: %s\n"
- "%sOwnerGroup: %s\n",
- prefix, strna(s->user),
- prefix, strna(s->group));
-
- if (s->keep_alive_time > 0)
- fprintf(f,
- "%sKeepAliveTimeSec: %s\n",
- prefix, format_timespan(time_string, FORMAT_TIMESPAN_MAX, s->keep_alive_time, USEC_PER_SEC));
-
- if (s->keep_alive_interval)
- 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)
- fprintf(f,
- "%sKeepAliveProbes: %u\n",
- prefix, s->keep_alive_cnt);
-
- if (s->defer_accept)
- 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) {
- const char *t;
- int r;
- char *k = NULL;
-
- if ((r = socket_address_print(&p->address, &k)) < 0)
- t = strerror(-r);
- else
- 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)
- fprintf(f, "%sListenSpecial: %s\n", prefix, p->path);
- else if (p->type == SOCKET_MQUEUE)
- fprintf(f, "%sListenMessageQueue: %s\n", prefix, p->path);
- else
- fprintf(f, "%sListenFIFO: %s\n", prefix, p->path);
- }
-
- exec_context_dump(&s->exec_context, f, prefix);
- kill_context_dump(&s->kill_context, f, prefix);
-
- for (c = 0; c < _SOCKET_EXEC_COMMAND_MAX; c++) {
- if (!s->exec_command[c])
- continue;
-
- fprintf(f, "%s-> %s:\n",
- prefix, socket_exec_command_to_string(c));
-
- exec_command_dump_list(s->exec_command[c], f, prefix2);
- }
-}
-
-static int instance_from_socket(int fd, unsigned nr, char **instance) {
- socklen_t l;
- char *r;
- union sockaddr_union local, remote;
-
- assert(fd >= 0);
- assert(instance);
-
- l = sizeof(local);
- if (getsockname(fd, &local.sa, &l) < 0)
- return -errno;
-
- l = sizeof(remote);
- if (getpeername(fd, &remote.sa, &l) < 0)
- return -errno;
-
- switch (local.sa.sa_family) {
-
- case AF_INET: {
- uint32_t
- a = ntohl(local.in.sin_addr.s_addr),
- b = ntohl(remote.in.sin_addr.s_addr);
-
- if (asprintf(&r,
- "%u-%u.%u.%u.%u:%u-%u.%u.%u.%u:%u",
- nr,
- a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
- ntohs(local.in.sin_port),
- b >> 24, (b >> 16) & 0xFF, (b >> 8) & 0xFF, b & 0xFF,
- ntohs(remote.in.sin_port)) < 0)
- return -ENOMEM;
-
- break;
- }
-
- case AF_INET6: {
- static const unsigned char ipv4_prefix[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF
- };
-
- if (memcmp(&local.in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0 &&
- memcmp(&remote.in6.sin6_addr, ipv4_prefix, sizeof(ipv4_prefix)) == 0) {
- const uint8_t
- *a = local.in6.sin6_addr.s6_addr+12,
- *b = remote.in6.sin6_addr.s6_addr+12;
-
- if (asprintf(&r,
- "%u-%u.%u.%u.%u:%u-%u.%u.%u.%u:%u",
- nr,
- a[0], a[1], a[2], a[3],
- ntohs(local.in6.sin6_port),
- b[0], b[1], b[2], b[3],
- ntohs(remote.in6.sin6_port)) < 0)
- return -ENOMEM;
- } else {
- char a[INET6_ADDRSTRLEN], b[INET6_ADDRSTRLEN];
-
- if (asprintf(&r,
- "%u-%s:%u-%s:%u",
- nr,
- inet_ntop(AF_INET6, &local.in6.sin6_addr, a, sizeof(a)),
- ntohs(local.in6.sin6_port),
- inet_ntop(AF_INET6, &remote.in6.sin6_addr, b, sizeof(b)),
- ntohs(remote.in6.sin6_port)) < 0)
- return -ENOMEM;
- }
-
- break;
- }
-
- case AF_UNIX: {
- struct ucred ucred;
- int k;
-
- k = getpeercred(fd, &ucred);
- if (k >= 0) {
- if (asprintf(&r,
- "%u-"PID_FMT"-"UID_FMT,
- nr, ucred.pid, ucred.uid) < 0)
- return -ENOMEM;
- } else if (k == -ENODATA) {
- /* This handles the case where somebody is
- * connecting from another pid/uid namespace
- * (e.g. from outside of our container). */
- if (asprintf(&r,
- "%u-unknown",
- nr) < 0)
- return -ENOMEM;
- } else
- return k;
-
- break;
- }
-
- default:
- assert_not_reached("Unhandled socket type.");
- }
-
- *instance = r;
- return 0;
-}
-
-static void socket_close_fds(Socket *s) {
- SocketPort *p;
- char **i;
-
- assert(s);
-
- LIST_FOREACH(port, p, s->ports) {
-
- p->event_source = sd_event_source_unref(p->event_source);
-
- if (p->fd < 0)
- continue;
-
- p->fd = safe_close(p->fd);
-
- /* One little note: we should normally not delete any
- * sockets in the file system here! After all some
- * other process we spawned might still have a
- * reference of this fd and wants to continue to use
- * it. Therefore we delete sockets in the file system
- * before we create a new one, not after we stopped
- * using one! */
-
- if (s->remove_on_stop) {
- switch (p->type) {
-
- case SOCKET_FIFO:
- unlink(p->path);
- break;
-
- case SOCKET_MQUEUE:
- mq_unlink(p->path);
- break;
-
- case SOCKET_SOCKET:
- socket_address_unlink(&p->address);
- break;
-
- default:
- break;
- }
- }
- }
-
- if (s->remove_on_stop)
- STRV_FOREACH(i, s->symlinks)
- unlink(*i);
-}
-
-static void socket_apply_socket_options(Socket *s, int fd) {
- int r;
-
- assert(s);
- assert(fd >= 0);
-
- if (s->keep_alive) {
- int b = s->keep_alive;
- if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &b, sizeof(b)) < 0)
- log_unit_warning(UNIT(s)->id, "SO_KEEPALIVE failed: %m");
- }
-
- if (s->keep_alive_time) {
- int value = s->keep_alive_time / USEC_PER_SEC;
- if (setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &value, sizeof(value)) < 0)
- log_unit_warning(UNIT(s)->id, "TCP_KEEPIDLE failed: %m");
- }
-
- if (s->keep_alive_interval) {
- int value = s->keep_alive_interval / USEC_PER_SEC;
- if (setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &value, sizeof(value)) < 0)
- log_unit_warning(UNIT(s)->id, "TCP_KEEPINTVL failed: %m");
- }
-
- if (s->keep_alive_cnt) {
- int value = s->keep_alive_cnt;
- if (setsockopt(fd, SOL_SOCKET, TCP_KEEPCNT, &value, sizeof(value)) < 0)
- log_unit_warning(UNIT(s)->id, "TCP_KEEPCNT failed: %m");
- }
-
- if (s->defer_accept) {
- int value = s->defer_accept / USEC_PER_SEC;
- if (setsockopt(fd, SOL_TCP, TCP_DEFER_ACCEPT, &value, sizeof(value)) < 0)
- log_unit_warning(UNIT(s)->id, "TCP_DEFER_ACCEPT failed: %m");
- }
-
- if (s->no_delay) {
- int b = s->no_delay;
- if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &b, sizeof(b)) < 0)
- log_unit_warning(UNIT(s)->id, "TCP_NODELAY failed: %m");
- }
-
- if (s->broadcast) {
- int one = 1;
- if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)) < 0)
- log_unit_warning(UNIT(s)->id, "SO_BROADCAST failed: %m");
- }
-
- if (s->pass_cred) {
- int one = 1;
- if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0)
- log_unit_warning(UNIT(s)->id, "SO_PASSCRED failed: %m");
- }
-
- if (s->pass_sec) {
- int one = 1;
- if (setsockopt(fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one)) < 0)
- log_unit_warning(UNIT(s)->id, "SO_PASSSEC failed: %m");
- }
-
- if (s->priority >= 0)
- if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &s->priority, sizeof(s->priority)) < 0)
- log_unit_warning(UNIT(s)->id, "SO_PRIORITY failed: %m");
-
- if (s->receive_buffer > 0) {
- 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(UNIT(s)->id, "SO_RCVBUF failed: %m");
- }
-
- if (s->send_buffer > 0) {
- int value = (int) s->send_buffer;
- if (setsockopt(fd, SOL_SOCKET, SO_SNDBUFFORCE, &value, sizeof(value)) < 0)
- if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)) < 0)
- log_unit_warning(UNIT(s)->id, "SO_SNDBUF failed: %m");
- }
-
- if (s->mark >= 0)
- if (setsockopt(fd, SOL_SOCKET, SO_MARK, &s->mark, sizeof(s->mark)) < 0)
- log_unit_warning(UNIT(s)->id, "SO_MARK failed: %m");
-
- if (s->ip_tos >= 0)
- if (setsockopt(fd, IPPROTO_IP, IP_TOS, &s->ip_tos, sizeof(s->ip_tos)) < 0)
- log_unit_warning(UNIT(s)->id, "IP_TOS failed: %m");
-
- if (s->ip_ttl >= 0) {
- int x;
-
- r = setsockopt(fd, IPPROTO_IP, IP_TTL, &s->ip_ttl, sizeof(s->ip_ttl));
-
- if (socket_ipv6_is_supported())
- x = setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &s->ip_ttl, sizeof(s->ip_ttl));
- else {
- x = -1;
- errno = EAFNOSUPPORT;
- }
-
- if (r < 0 && x < 0)
- log_unit_warning(UNIT(s)->id,
- "IP_TTL/IPV6_UNICAST_HOPS failed: %m");
- }
-
- if (s->tcp_congestion)
- if (setsockopt(fd, SOL_TCP, TCP_CONGESTION, s->tcp_congestion, strlen(s->tcp_congestion)+1) < 0)
- log_unit_warning(UNIT(s)->id, "TCP_CONGESTION failed: %m");
-
- if (s->reuse_port) {
- int b = s->reuse_port;
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &b, sizeof(b)) < 0)
- log_unit_warning(UNIT(s)->id, "SO_REUSEPORT failed: %m");
- }
-
- if (s->smack_ip_in) {
- r = mac_smack_apply_ip_in_fd(fd, s->smack_ip_in);
- if (r < 0)
- log_unit_error_errno(UNIT(s)->id, r, "mac_smack_apply_ip_in_fd: %m");
- }
-
- if (s->smack_ip_out) {
- r = mac_smack_apply_ip_out_fd(fd, s->smack_ip_out);
- if (r < 0)
- log_unit_error_errno(UNIT(s)->id, r, "mac_smack_apply_ip_out_fd: %m");
- }
-}
-
-static void socket_apply_fifo_options(Socket *s, int fd) {
- int r;
-
- assert(s);
- assert(fd >= 0);
-
- if (s->pipe_size > 0)
- if (fcntl(fd, F_SETPIPE_SZ, s->pipe_size) < 0)
- log_unit_warning(UNIT(s)->id, "F_SETPIPE_SZ: %m");
-
- if (s->smack) {
- r = mac_smack_apply_fd(fd, s->smack);
- if (r < 0)
- log_unit_error_errno(UNIT(s)->id, r, "mac_smack_apply_fd: %m");
- }
-}
-
-static int fifo_address_create(
- const char *path,
- mode_t directory_mode,
- mode_t socket_mode,
- int *_fd) {
-
- int fd = -1, r = 0;
- struct stat st;
- mode_t old_mask;
-
- assert(path);
- assert(_fd);
-
- mkdir_parents_label(path, directory_mode);
-
- r = mac_selinux_create_file_prepare(path, S_IFIFO);
- if (r < 0)
- goto fail;
-
- /* Enforce the right access mode for the fifo */
- old_mask = umask(~ socket_mode);
-
- /* Include the original umask in our mask */
- umask(~socket_mode | old_mask);
-
- r = mkfifo(path, socket_mode);
- umask(old_mask);
-
- if (r < 0 && errno != EEXIST) {
- r = -errno;
- goto fail;
- }
-
- if ((fd = open(path, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW)) < 0) {
- r = -errno;
- goto fail;
- }
-
- mac_selinux_create_file_clear();
-
- if (fstat(fd, &st) < 0) {
- r = -errno;
- goto fail;
- }
-
- if (!S_ISFIFO(st.st_mode) ||
- (st.st_mode & 0777) != (socket_mode & ~old_mask) ||
- st.st_uid != getuid() ||
- st.st_gid != getgid()) {
-
- r = -EEXIST;
- goto fail;
- }
-
- *_fd = fd;
- return 0;
-
-fail:
- mac_selinux_create_file_clear();
- safe_close(fd);
-
- return r;
-}
-
-static int special_address_create(
- const char *path,
- int *_fd) {
-
- int fd = -1, r = 0;
- struct stat st;
-
- assert(path);
- assert(_fd);
-
- fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW);
- if (fd < 0) {
- r = -errno;
- goto fail;
- }
-
- if (fstat(fd, &st) < 0) {
- r = -errno;
- goto fail;
- }
-
- /* Check whether this is a /proc, /sys or /dev file or char device */
- if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) {
- r = -EEXIST;
- goto fail;
- }
-
- *_fd = fd;
- return 0;
-
-fail:
- safe_close(fd);
-
- return r;
-}
-
-static int mq_address_create(
- const char *path,
- mode_t mq_mode,
- long maxmsg,
- long msgsize,
- int *_fd) {
-
- int fd = -1, r = 0;
- struct stat st;
- mode_t old_mask;
- struct mq_attr _attr, *attr = NULL;
-
- assert(path);
- assert(_fd);
-
- if (maxmsg > 0 && msgsize > 0) {
- zero(_attr);
- _attr.mq_flags = O_NONBLOCK;
- _attr.mq_maxmsg = maxmsg;
- _attr.mq_msgsize = msgsize;
- attr = &_attr;
- }
-
- /* Enforce the right access mode for the mq */
- old_mask = umask(~ mq_mode);
-
- /* Include the original umask in our mask */
- umask(~mq_mode | old_mask);
- fd = mq_open(path, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_CREAT, mq_mode, attr);
- umask(old_mask);
-
- if (fd < 0) {
- r = -errno;
- goto fail;
- }
-
- if (fstat(fd, &st) < 0) {
- r = -errno;
- goto fail;
- }
-
- if ((st.st_mode & 0777) != (mq_mode & ~old_mask) ||
- st.st_uid != getuid() ||
- st.st_gid != getgid()) {
-
- r = -EEXIST;
- goto fail;
- }
-
- *_fd = fd;
- return 0;
-
-fail:
- safe_close(fd);
- return r;
-}
-
-static int socket_symlink(Socket *s) {
- const char *p;
- char **i;
-
- assert(s);
-
- p = socket_find_symlink_target(s);
- if (!p)
- return 0;
-
- STRV_FOREACH(i, s->symlinks)
- symlink_label(p, *i);
-
- return 0;
-}
-
-static int socket_open_fds(Socket *s) {
- SocketPort *p;
- int r;
- char *label = NULL;
- bool know_label = false;
-
- assert(s);
-
- LIST_FOREACH(port, p, s->ports) {
-
- if (p->fd >= 0)
- continue;
-
- if (p->type == SOCKET_SOCKET) {
-
- if (!know_label) {
- /* Figure out label, if we don't it know
- * yet. We do it once, for the first
- * socket where we need this and
- * remember it for the rest. */
-
- if (s->selinux_context_from_net) {
- /* Get it from the network label */
-
- r = mac_selinux_get_our_label(&label);
- if (r < 0 && r != -EOPNOTSUPP)
- goto rollback;
-
- } else {
- /* Get it from the executable we are about to start */
-
- r = socket_instantiate_service(s);
- if (r < 0)
- goto rollback;
-
- if (UNIT_ISSET(s->service) &&
- SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]) {
- r = mac_selinux_get_create_label_from_exe(SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]->path, &label);
- if (r < 0 && r != -EPERM && r != -EOPNOTSUPP)
- goto rollback;
- }
- }
-
- know_label = true;
- }
-
- r = socket_address_listen(
- &p->address,
- SOCK_CLOEXEC|SOCK_NONBLOCK,
- s->backlog,
- s->bind_ipv6_only,
- s->bind_to_device,
- s->free_bind,
- s->transparent,
- s->directory_mode,
- s->socket_mode,
- label);
- if (r < 0)
- goto rollback;
-
- p->fd = r;
- socket_apply_socket_options(s, p->fd);
- socket_symlink(s);
-
- } else if (p->type == SOCKET_SPECIAL) {
-
- r = special_address_create(
- p->path,
- &p->fd);
- if (r < 0)
- goto rollback;
-
- } else if (p->type == SOCKET_FIFO) {
-
- r = fifo_address_create(
- p->path,
- s->directory_mode,
- s->socket_mode,
- &p->fd);
- if (r < 0)
- goto rollback;
-
- socket_apply_fifo_options(s, p->fd);
- socket_symlink(s);
-
- } else if (p->type == SOCKET_MQUEUE) {
-
- r = mq_address_create(
- p->path,
- s->socket_mode,
- s->mq_maxmsg,
- s->mq_msgsize,
- &p->fd);
- if (r < 0)
- goto rollback;
- } else
- assert_not_reached("Unknown port type");
- }
-
- mac_selinux_free(label);
- return 0;
-
-rollback:
- socket_close_fds(s);
- mac_selinux_free(label);
-
- return r;
-}
-
-static void socket_unwatch_fds(Socket *s) {
- SocketPort *p;
- int r;
-
- assert(s);
-
- LIST_FOREACH(port, p, s->ports) {
- if (p->fd < 0)
- continue;
-
- if (!p->event_source)
- continue;
-
- r = sd_event_source_set_enabled(p->event_source, SD_EVENT_OFF);
- if (r < 0)
- log_unit_debug(UNIT(s)->id, "Failed to disable event source.");
- }
-}
-
-static int socket_watch_fds(Socket *s) {
- SocketPort *p;
- int r;
-
- assert(s);
-
- LIST_FOREACH(port, p, s->ports) {
- if (p->fd < 0)
- continue;
-
- if (p->event_source)
- r = sd_event_source_set_enabled(p->event_source, SD_EVENT_ON);
- else
- r = sd_event_add_io(UNIT(s)->manager->event, &p->event_source, p->fd, EPOLLIN, socket_dispatch_io, p);
-
- if (r < 0) {
- log_unit_warning_errno(UNIT(s)->id, r, "Failed to watch listening fds: %m");
- goto fail;
- }
- }
-
- return 0;
-
-fail:
- socket_unwatch_fds(s);
- return r;
-}
-
-static void socket_set_state(Socket *s, SocketState state) {
- SocketState old_state;
- assert(s);
-
- old_state = s->state;
- s->state = state;
-
- if (!IN_SET(state,
- SOCKET_START_PRE,
- SOCKET_START_CHOWN,
- SOCKET_START_POST,
- SOCKET_STOP_PRE,
- SOCKET_STOP_PRE_SIGTERM,
- SOCKET_STOP_PRE_SIGKILL,
- SOCKET_STOP_POST,
- SOCKET_FINAL_SIGTERM,
- SOCKET_FINAL_SIGKILL)) {
-
- s->timer_event_source = sd_event_source_unref(s->timer_event_source);
- socket_unwatch_control_pid(s);
- s->control_command = NULL;
- s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID;
- }
-
- if (state != SOCKET_LISTENING)
- socket_unwatch_fds(s);
-
- if (!IN_SET(state,
- SOCKET_START_CHOWN,
- SOCKET_START_POST,
- SOCKET_LISTENING,
- SOCKET_RUNNING,
- SOCKET_STOP_PRE,
- SOCKET_STOP_PRE_SIGTERM,
- SOCKET_STOP_PRE_SIGKILL))
- socket_close_fds(s);
-
- if (state != old_state)
- log_unit_debug(UNIT(s)->id, "%s changed %s -> %s",
- UNIT(s)->id, 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);
-}
-
-static int socket_coldplug(Unit *u, Hashmap *deferred_work) {
- Socket *s = SOCKET(u);
- int r;
-
- assert(s);
- assert(s->state == SOCKET_DEAD);
-
- if (s->deserialized_state == s->state)
- return 0;
-
- if (IN_SET(s->deserialized_state,
- SOCKET_START_PRE,
- SOCKET_START_CHOWN,
- SOCKET_START_POST,
- SOCKET_STOP_PRE,
- SOCKET_STOP_PRE_SIGTERM,
- SOCKET_STOP_PRE_SIGKILL,
- SOCKET_STOP_POST,
- SOCKET_FINAL_SIGTERM,
- SOCKET_FINAL_SIGKILL)) {
-
- if (s->control_pid <= 0)
- return -EBADMSG;
-
- r = unit_watch_pid(UNIT(s), s->control_pid);
- if (r < 0)
- return r;
-
- r = socket_arm_timer(s);
- if (r < 0)
- return r;
- }
-
- if (IN_SET(s->deserialized_state,
- SOCKET_START_CHOWN,
- SOCKET_START_POST,
- SOCKET_LISTENING,
- SOCKET_RUNNING,
- SOCKET_STOP_PRE,
- SOCKET_STOP_PRE_SIGTERM,
- SOCKET_STOP_PRE_SIGKILL)) {
- r = socket_open_fds(s);
- if (r < 0)
- return r;
- }
-
- if (s->deserialized_state == SOCKET_LISTENING) {
- r = socket_watch_fds(s);
- if (r < 0)
- return r;
- }
-
- socket_set_state(s, s->deserialized_state);
- return 0;
-}
-
-static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
- _cleanup_free_ char **argv = NULL;
- pid_t pid;
- int r;
- ExecParameters exec_params = {
- .apply_permissions = true,
- .apply_chroot = true,
- .apply_tty_stdin = true,
- };
-
- assert(s);
- assert(c);
- assert(_pid);
-
- (void) unit_realize_cgroup(UNIT(s));
- if (s->reset_cpu_usage) {
- (void) unit_reset_cpu_usage(UNIT(s));
- s->reset_cpu_usage = false;
- }
-
- r = unit_setup_exec_runtime(UNIT(s));
- if (r < 0)
- goto fail;
-
- r = socket_arm_timer(s);
- if (r < 0)
- goto fail;
-
- r = unit_full_printf_strv(UNIT(s), c->argv, &argv);
- if (r < 0)
- goto fail;
-
- exec_params.argv = argv;
- exec_params.environment = UNIT(s)->manager->environment;
- exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn;
- exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
- exec_params.cgroup_path = UNIT(s)->cgroup_path;
- exec_params.cgroup_delegate = s->cgroup_context.delegate;
- exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager);
- exec_params.unit_id = UNIT(s)->id;
-
- r = exec_spawn(c,
- &s->exec_context,
- &exec_params,
- s->exec_runtime,
- &pid);
- if (r < 0)
- goto fail;
-
- r = unit_watch_pid(UNIT(s), pid);
- if (r < 0)
- /* FIXME: we need to do something here */
- goto fail;
-
- *_pid = pid;
- return 0;
-
-fail:
- s->timer_event_source = sd_event_source_unref(s->timer_event_source);
- return r;
-}
-
-static int socket_chown(Socket *s, pid_t *_pid) {
- pid_t pid;
- int r;
-
- r = socket_arm_timer(s);
- if (r < 0)
- goto fail;
-
- /* We have to resolve the user names out-of-process, hence
- * let's fork here. It's messy, but well, what can we do? */
-
- pid = fork();
- if (pid < 0)
- return -errno;
-
- if (pid == 0) {
- SocketPort *p;
- uid_t uid = UID_INVALID;
- gid_t gid = GID_INVALID;
- int ret;
-
- default_signals(SIGNALS_CRASH_HANDLER, SIGNALS_IGNORE, -1);
- ignore_signals(SIGPIPE, -1);
- log_forget_fds();
-
- if (!isempty(s->user)) {
- const char *user = s->user;
-
- r = get_user_creds(&user, &uid, &gid, NULL, NULL);
- if (r < 0) {
- ret = EXIT_USER;
- goto fail_child;
- }
- }
-
- if (!isempty(s->group)) {
- const char *group = s->group;
-
- r = get_group_creds(&group, &gid);
- if (r < 0) {
- ret = EXIT_GROUP;
- goto fail_child;
- }
- }
-
- LIST_FOREACH(port, p, s->ports) {
- const char *path = NULL;
-
- if (p->type == SOCKET_SOCKET)
- path = socket_address_get_path(&p->address);
- else if (p->type == SOCKET_FIFO)
- path = p->path;
-
- if (!path)
- continue;
-
- if (chown(path, uid, gid) < 0) {
- r = -errno;
- ret = EXIT_CHOWN;
- goto fail_child;
- }
- }
-
- _exit(0);
-
- fail_child:
- log_open();
- log_error_errno(r, "Failed to chown socket at step %s: %m", exit_status_to_string(ret, EXIT_STATUS_SYSTEMD));
-
- _exit(ret);
- }
-
- r = unit_watch_pid(UNIT(s), pid);
- if (r < 0)
- goto fail;
-
- *_pid = pid;
- return 0;
-
-fail:
- s->timer_event_source = sd_event_source_unref(s->timer_event_source);
- return r;
-}
-
-static void socket_enter_dead(Socket *s, SocketResult f) {
- assert(s);
-
- if (f != SOCKET_SUCCESS)
- s->result = f;
-
- exec_runtime_destroy(s->exec_runtime);
- s->exec_runtime = exec_runtime_unref(s->exec_runtime);
-
- exec_context_destroy_runtime_directory(&s->exec_context, manager_get_runtime_prefix(UNIT(s)->manager));
-
- socket_set_state(s, s->result != SOCKET_SUCCESS ? SOCKET_FAILED : SOCKET_DEAD);
-}
-
-static void socket_enter_signal(Socket *s, SocketState state, SocketResult f);
-
-static void socket_enter_stop_post(Socket *s, SocketResult f) {
- int r;
- assert(s);
-
- if (f != SOCKET_SUCCESS)
- s->result = f;
-
- socket_unwatch_control_pid(s);
- s->control_command_id = SOCKET_EXEC_STOP_POST;
- s->control_command = s->exec_command[SOCKET_EXEC_STOP_POST];
-
- if (s->control_command) {
- r = socket_spawn(s, s->control_command, &s->control_pid);
- if (r < 0)
- goto fail;
-
- socket_set_state(s, SOCKET_STOP_POST);
- } else
- socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_SUCCESS);
-
- return;
-
-fail:
- log_unit_warning(UNIT(s)->id,
- "%s failed to run 'stop-post' task: %s",
- UNIT(s)->id, strerror(-r));
- socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_RESOURCES);
-}
-
-static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
- int r;
-
- assert(s);
-
- if (f != SOCKET_SUCCESS)
- s->result = f;
-
- r = unit_kill_context(
- UNIT(s),
- &s->kill_context,
- (state != SOCKET_STOP_PRE_SIGTERM && state != SOCKET_FINAL_SIGTERM) ?
- KILL_KILL : KILL_TERMINATE,
- -1,
- s->control_pid,
- false);
- if (r < 0)
- goto fail;
-
- if (r > 0) {
- r = socket_arm_timer(s);
- if (r < 0)
- goto fail;
-
- socket_set_state(s, state);
- } else if (state == SOCKET_STOP_PRE_SIGTERM)
- socket_enter_signal(s, SOCKET_STOP_PRE_SIGKILL, SOCKET_SUCCESS);
- else if (state == SOCKET_STOP_PRE_SIGKILL)
- socket_enter_stop_post(s, SOCKET_SUCCESS);
- else if (state == SOCKET_FINAL_SIGTERM)
- socket_enter_signal(s, SOCKET_FINAL_SIGKILL, SOCKET_SUCCESS);
- else
- socket_enter_dead(s, SOCKET_SUCCESS);
-
- return;
-
-fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to kill processes: %m", UNIT(s)->id);
-
- if (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_STOP_PRE_SIGKILL)
- socket_enter_stop_post(s, SOCKET_FAILURE_RESOURCES);
- else
- socket_enter_dead(s, SOCKET_FAILURE_RESOURCES);
-}
-
-static void socket_enter_stop_pre(Socket *s, SocketResult f) {
- int r;
- assert(s);
-
- if (f != SOCKET_SUCCESS)
- s->result = f;
-
- socket_unwatch_control_pid(s);
- s->control_command_id = SOCKET_EXEC_STOP_PRE;
- s->control_command = s->exec_command[SOCKET_EXEC_STOP_PRE];
-
- if (s->control_command) {
- r = socket_spawn(s, s->control_command, &s->control_pid);
- if (r < 0)
- goto fail;
-
- socket_set_state(s, SOCKET_STOP_PRE);
- } else
- socket_enter_stop_post(s, SOCKET_SUCCESS);
-
- return;
-
-fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'stop-pre' task: %m", UNIT(s)->id);
- socket_enter_stop_post(s, SOCKET_FAILURE_RESOURCES);
-}
-
-static void socket_enter_listening(Socket *s) {
- int r;
- assert(s);
-
- r = socket_watch_fds(s);
- if (r < 0) {
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to watch sockets: %m", UNIT(s)->id);
- goto fail;
- }
-
- socket_set_state(s, SOCKET_LISTENING);
- return;
-
-fail:
- socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
-}
-
-static void socket_enter_start_post(Socket *s) {
- int r;
- assert(s);
-
- socket_unwatch_control_pid(s);
- s->control_command_id = SOCKET_EXEC_START_POST;
- s->control_command = s->exec_command[SOCKET_EXEC_START_POST];
-
- if (s->control_command) {
- r = socket_spawn(s, s->control_command, &s->control_pid);
- if (r < 0) {
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'start-post' task: %m", UNIT(s)->id);
- goto fail;
- }
-
- socket_set_state(s, SOCKET_START_POST);
- } else
- socket_enter_listening(s);
-
- return;
-
-fail:
- socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
-}
-
-static void socket_enter_start_chown(Socket *s) {
- int r;
-
- assert(s);
-
- r = socket_open_fds(s);
- if (r < 0) {
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to listen on sockets: %m", UNIT(s)->id);
- goto fail;
- }
-
- if (!isempty(s->user) || !isempty(s->group)) {
-
- socket_unwatch_control_pid(s);
- s->control_command_id = SOCKET_EXEC_START_CHOWN;
- s->control_command = NULL;
-
- r = socket_chown(s, &s->control_pid);
- if (r < 0) {
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to fork 'start-chown' task: %m", UNIT(s)->id);
- goto fail;
- }
-
- socket_set_state(s, SOCKET_START_CHOWN);
- } else
- socket_enter_start_post(s);
-
- return;
-
-fail:
- socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
-}
-
-static void socket_enter_start_pre(Socket *s) {
- int r;
- assert(s);
-
- socket_unwatch_control_pid(s);
- s->control_command_id = SOCKET_EXEC_START_PRE;
- s->control_command = s->exec_command[SOCKET_EXEC_START_PRE];
-
- if (s->control_command) {
- r = socket_spawn(s, s->control_command, &s->control_pid);
- if (r < 0) {
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'start-pre' task: %m", UNIT(s)->id);
- goto fail;
- }
-
- socket_set_state(s, SOCKET_START_PRE);
- } else
- socket_enter_start_chown(s);
-
- return;
-
-fail:
- socket_enter_dead(s, SOCKET_FAILURE_RESOURCES);
-}
-
-static void socket_enter_running(Socket *s, int cfd) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- int r;
-
- assert(s);
-
- /* We don't take connections anymore if we are supposed to
- * shut down anyway */
- if (unit_stop_pending(UNIT(s))) {
-
- log_unit_debug(UNIT(s)->id, "Suppressing connection request on %s since unit stop is scheduled.", UNIT(s)->id);
-
- if (cfd >= 0)
- safe_close(cfd);
- else {
- /* Flush all sockets by closing and reopening them */
- socket_close_fds(s);
-
- r = socket_open_fds(s);
- if (r < 0) {
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to listen on sockets: %m", UNIT(s)->id);
- socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
- return;
- }
-
- r = socket_watch_fds(s);
- if (r < 0) {
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to watch sockets: %m", UNIT(s)->id);
- socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
- }
- }
-
- return;
- }
-
- if (cfd < 0) {
- Iterator i;
- Unit *other;
- bool pending = false;
-
- /* If there's already a start pending don't bother to
- * do anything */
- SET_FOREACH(other, UNIT(s)->dependencies[UNIT_TRIGGERS], i)
- if (unit_active_or_pending(other)) {
- pending = true;
- break;
- }
-
- if (!pending) {
- if (!UNIT_ISSET(s->service)) {
- log_unit_error(UNIT(s)->id, "%s: service to activate vanished, refusing activation.", UNIT(s)->id);
- r = -ENOENT;
- goto fail;
- }
-
- r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT_DEREF(s->service), JOB_REPLACE, true, &error, NULL);
- if (r < 0)
- goto fail;
- }
-
- socket_set_state(s, SOCKET_RUNNING);
- } else {
- _cleanup_free_ char *prefix = NULL, *instance = NULL, *name = NULL;
- Service *service;
-
- if (s->n_connections >= s->max_connections) {
- log_unit_warning(UNIT(s)->id, "%s: Too many incoming connections (%u)", UNIT(s)->id, s->n_connections);
- safe_close(cfd);
- return;
- }
-
- r = socket_instantiate_service(s);
- if (r < 0)
- goto fail;
-
- r = instance_from_socket(cfd, s->n_accepted, &instance);
- if (r < 0) {
- if (r != -ENOTCONN)
- goto fail;
-
- /* ENOTCONN is legitimate if TCP RST was received.
- * This connection is over, but the socket unit lives on. */
- safe_close(cfd);
- return;
- }
-
- prefix = unit_name_to_prefix(UNIT(s)->id);
- if (!prefix) {
- r = -ENOMEM;
- goto fail;
- }
-
- name = unit_name_build(prefix, instance, ".service");
- if (!name) {
- r = -ENOMEM;
- goto fail;
- }
-
- r = unit_add_name(UNIT_DEREF(s->service), name);
- if (r < 0)
- goto fail;
-
- service = SERVICE(UNIT_DEREF(s->service));
- unit_ref_unset(&s->service);
- s->n_accepted ++;
-
- UNIT(service)->no_gc = false;
-
- unit_choose_id(UNIT(service), name);
-
- r = service_set_socket_fd(service, cfd, s, s->selinux_context_from_net);
- if (r < 0)
- goto fail;
-
- cfd = -1;
- s->n_connections ++;
-
- r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, true, &error, NULL);
- if (r < 0)
- goto fail;
-
- /* Notify clients about changed counters */
- unit_add_to_dbus_queue(UNIT(s));
- }
-
- return;
-
-fail:
- log_unit_warning(UNIT(s)->id, "%s failed to queue service startup job (Maybe the service file is missing or not a %s unit?): %s",
- UNIT(s)->id, cfd >= 0 ? "template" : "non-template",
- bus_error_message(&error, r));
-
- socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
- safe_close(cfd);
-}
-
-static void socket_run_next(Socket *s) {
- int r;
-
- assert(s);
- assert(s->control_command);
- assert(s->control_command->command_next);
-
- socket_unwatch_control_pid(s);
-
- s->control_command = s->control_command->command_next;
-
- r = socket_spawn(s, s->control_command, &s->control_pid);
- if (r < 0)
- goto fail;
-
- return;
-
-fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run next task: %m", UNIT(s)->id);
-
- if (s->state == SOCKET_START_POST)
- socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
- else if (s->state == SOCKET_STOP_POST)
- socket_enter_dead(s, SOCKET_FAILURE_RESOURCES);
- else
- socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_RESOURCES);
-}
-
-static int socket_start(Unit *u) {
- Socket *s = SOCKET(u);
-
- assert(s);
-
- /* We cannot fulfill this request right now, try again later
- * please! */
- if (IN_SET(s->state,
- SOCKET_STOP_PRE,
- SOCKET_STOP_PRE_SIGKILL,
- SOCKET_STOP_PRE_SIGTERM,
- SOCKET_STOP_POST,
- SOCKET_FINAL_SIGTERM,
- SOCKET_FINAL_SIGKILL))
- return -EAGAIN;
-
- /* Already on it! */
- if (IN_SET(s->state,
- SOCKET_START_PRE,
- SOCKET_START_CHOWN,
- SOCKET_START_POST))
- return 0;
-
- /* Cannot run this without the service being around */
- if (UNIT_ISSET(s->service)) {
- Service *service;
-
- service = SERVICE(UNIT_DEREF(s->service));
-
- if (UNIT(service)->load_state != UNIT_LOADED) {
- log_unit_error(u->id, "Socket service %s not loaded, refusing.", UNIT(service)->id);
- return -ENOENT;
- }
-
- /* If the service is already active we cannot start the
- * socket */
- if (service->state != SERVICE_DEAD &&
- service->state != SERVICE_FAILED &&
- service->state != SERVICE_AUTO_RESTART) {
- log_unit_error(u->id, "Socket service %s already active, refusing.", UNIT(service)->id);
- return -EBUSY;
- }
- }
-
- assert(s->state == SOCKET_DEAD || s->state == SOCKET_FAILED);
-
- s->result = SOCKET_SUCCESS;
- s->reset_cpu_usage = true;
-
- socket_enter_start_pre(s);
-
- return 1;
-}
-
-static int socket_stop(Unit *u) {
- Socket *s = SOCKET(u);
-
- assert(s);
-
- /* Already on it */
- if (IN_SET(s->state,
- SOCKET_STOP_PRE,
- SOCKET_STOP_PRE_SIGTERM,
- SOCKET_STOP_PRE_SIGKILL,
- SOCKET_STOP_POST,
- SOCKET_FINAL_SIGTERM,
- SOCKET_FINAL_SIGKILL))
- return 0;
-
- /* If there's already something running we go directly into
- * kill mode. */
- if (IN_SET(s->state,
- SOCKET_START_PRE,
- SOCKET_START_CHOWN,
- SOCKET_START_POST)) {
- socket_enter_signal(s, SOCKET_STOP_PRE_SIGTERM, SOCKET_SUCCESS);
- return -EAGAIN;
- }
-
- assert(s->state == SOCKET_LISTENING || s->state == SOCKET_RUNNING);
-
- socket_enter_stop_pre(s, SOCKET_SUCCESS);
- return 1;
-}
-
-static int socket_serialize(Unit *u, FILE *f, FDSet *fds) {
- Socket *s = SOCKET(u);
- SocketPort *p;
- int r;
-
- assert(u);
- assert(f);
- assert(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);
-
- if (s->control_pid > 0)
- unit_serialize_item_format(u, f, "control-pid", PID_FMT, s->control_pid);
-
- if (s->control_command_id >= 0)
- unit_serialize_item(u, f, "control-command", socket_exec_command_to_string(s->control_command_id));
-
- LIST_FOREACH(port, p, s->ports) {
- int copy;
-
- if (p->fd < 0)
- continue;
-
- copy = fdset_put_dup(fds, p->fd);
- if (copy < 0)
- return copy;
-
- if (p->type == SOCKET_SOCKET) {
- _cleanup_free_ char *t = NULL;
-
- r = socket_address_print(&p->address, &t);
- if (r < 0)
- return r;
-
- if (socket_address_family(&p->address) == AF_NETLINK)
- unit_serialize_item_format(u, f, "netlink", "%i %s", copy, t);
- else
- unit_serialize_item_format(u, f, "socket", "%i %i %s", copy, p->address.type, t);
-
- } else if (p->type == SOCKET_SPECIAL)
- unit_serialize_item_format(u, f, "special", "%i %s", copy, p->path);
- else if (p->type == SOCKET_MQUEUE)
- unit_serialize_item_format(u, f, "mqueue", "%i %s", copy, p->path);
- else {
- assert(p->type == SOCKET_FIFO);
- unit_serialize_item_format(u, f, "fifo", "%i %s", copy, p->path);
- }
- }
-
- return 0;
-}
-
-static int socket_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Socket *s = SOCKET(u);
-
- assert(u);
- assert(key);
- assert(value);
-
- if (streq(key, "state")) {
- SocketState state;
-
- state = socket_state_from_string(value);
- if (state < 0)
- log_unit_debug(u->id, "Failed to parse state value %s", value);
- else
- s->deserialized_state = state;
- } else if (streq(key, "result")) {
- SocketResult f;
-
- f = socket_result_from_string(value);
- if (f < 0)
- log_unit_debug(u->id, "Failed to parse result value %s", value);
- else if (f != SOCKET_SUCCESS)
- s->result = f;
-
- } else if (streq(key, "n-accepted")) {
- unsigned k;
-
- if (safe_atou(value, &k) < 0)
- log_unit_debug(u->id, "Failed to parse n-accepted value %s", value);
- else
- s->n_accepted += k;
- } else if (streq(key, "control-pid")) {
- pid_t pid;
-
- if (parse_pid(value, &pid) < 0)
- log_unit_debug(u->id, "Failed to parse control-pid value %s", value);
- else
- s->control_pid = pid;
- } else if (streq(key, "control-command")) {
- SocketExecCommand id;
-
- id = socket_exec_command_from_string(value);
- if (id < 0)
- log_unit_debug(u->id, "Failed to parse exec-command value %s", value);
- else {
- s->control_command_id = id;
- s->control_command = s->exec_command[id];
- }
- } else if (streq(key, "fifo")) {
- int fd, skip = 0;
- SocketPort *p;
-
- if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u->id, "Failed to parse fifo value %s", value);
- else {
-
- LIST_FOREACH(port, p, s->ports)
- if (p->type == SOCKET_FIFO &&
- path_equal_or_files_same(p->path, value+skip))
- break;
-
- if (p) {
- safe_close(p->fd);
- p->fd = fdset_remove(fds, fd);
- }
- }
-
- } else if (streq(key, "special")) {
- int fd, skip = 0;
- SocketPort *p;
-
- if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u->id, "Failed to parse special value %s", value);
- else {
-
- LIST_FOREACH(port, p, s->ports)
- if (p->type == SOCKET_SPECIAL &&
- path_equal_or_files_same(p->path, value+skip))
- break;
-
- if (p) {
- safe_close(p->fd);
- p->fd = fdset_remove(fds, fd);
- }
- }
-
- } else if (streq(key, "mqueue")) {
- int fd, skip = 0;
- SocketPort *p;
-
- if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u->id, "Failed to parse mqueue value %s", value);
- else {
-
- LIST_FOREACH(port, p, s->ports)
- if (p->type == SOCKET_MQUEUE &&
- streq(p->path, value+skip))
- break;
-
- if (p) {
- safe_close(p->fd);
- p->fd = fdset_remove(fds, fd);
- }
- }
-
- } else if (streq(key, "socket")) {
- int fd, type, skip = 0;
- SocketPort *p;
-
- if (sscanf(value, "%i %i %n", &fd, &type, &skip) < 2 || fd < 0 || type < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u->id, "Failed to parse socket value %s", value);
- else {
-
- LIST_FOREACH(port, p, s->ports)
- if (socket_address_is(&p->address, value+skip, type))
- break;
-
- if (p) {
- safe_close(p->fd);
- p->fd = fdset_remove(fds, fd);
- }
- }
-
- } else if (streq(key, "netlink")) {
- int fd, skip = 0;
- SocketPort *p;
-
- if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u->id, "Failed to parse socket value %s", value);
- else {
-
- LIST_FOREACH(port, p, s->ports)
- if (socket_address_is_netlink(&p->address, value+skip))
- break;
-
- if (p) {
- safe_close(p->fd);
- p->fd = fdset_remove(fds, fd);
- }
- }
- } else
- log_unit_debug(UNIT(s)->id, "Unknown serialization key '%s'", key);
-
- return 0;
-}
-
-static int socket_distribute_fds(Unit *u, FDSet *fds) {
- Socket *s = SOCKET(u);
- SocketPort *p;
-
- assert(u);
-
- LIST_FOREACH(port, p, s->ports) {
- Iterator i;
- int fd;
-
- if (p->type != SOCKET_SOCKET)
- continue;
-
- if (p->fd >= 0)
- continue;
-
- FDSET_FOREACH(fd, fds, i) {
- if (socket_address_matches_fd(&p->address, fd)) {
- p->fd = fdset_remove(fds, fd);
- s->deserialized_state = SOCKET_LISTENING;
- break;
- }
- }
- }
-
- return 0;
-}
-
-_pure_ static UnitActiveState socket_active_state(Unit *u) {
- assert(u);
-
- return state_translation_table[SOCKET(u)->state];
-}
-
-_pure_ static const char *socket_sub_state_to_string(Unit *u) {
- assert(u);
-
- return socket_state_to_string(SOCKET(u)->state);
-}
-
-const char* socket_port_type_to_string(SocketPort *p) {
-
- assert(p);
-
- switch (p->type) {
-
- case SOCKET_SOCKET:
-
- switch (p->address.type) {
-
- case SOCK_STREAM:
- return "Stream";
-
- case SOCK_DGRAM:
- return "Datagram";
-
- case SOCK_SEQPACKET:
- return "SequentialPacket";
-
- case SOCK_RAW:
- if (socket_address_family(&p->address) == AF_NETLINK)
- return "Netlink";
-
- default:
- return NULL;
- }
-
- case SOCKET_SPECIAL:
- return "Special";
-
- case SOCKET_MQUEUE:
- return "MessageQueue";
-
- case SOCKET_FIFO:
- return "FIFO";
-
- default:
- return NULL;
- }
-}
-
-_pure_ static bool socket_check_gc(Unit *u) {
- Socket *s = SOCKET(u);
-
- assert(u);
-
- return s->n_connections > 0;
-}
-
-static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
- SocketPort *p = userdata;
- int cfd = -1;
-
- assert(p);
- assert(fd >= 0);
-
- if (p->socket->state != SOCKET_LISTENING)
- return 0;
-
- log_unit_debug(UNIT(p->socket)->id, "Incoming traffic on %s", UNIT(p->socket)->id);
-
- if (revents != EPOLLIN) {
-
- if (revents & EPOLLHUP)
- log_unit_error(UNIT(p->socket)->id, "%s: Got POLLHUP on a listening socket. The service probably invoked shutdown() on it, and should better not do that.",
- UNIT(p->socket)->id);
- else
- log_unit_error(UNIT(p->socket)->id, "%s: Got unexpected poll event (0x%x) on socket.",
- UNIT(p->socket)->id, revents);
-
- goto fail;
- }
-
- if (p->socket->accept &&
- p->type == SOCKET_SOCKET &&
- socket_address_can_accept(&p->address)) {
-
- for (;;) {
-
- cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK);
- if (cfd < 0) {
-
- if (errno == EINTR)
- continue;
-
- log_unit_error(UNIT(p->socket)->id,
- "Failed to accept socket: %m");
- goto fail;
- }
-
- break;
- }
-
- socket_apply_socket_options(p->socket, cfd);
- }
-
- socket_enter_running(p->socket, cfd);
- return 0;
-
-fail:
- socket_enter_stop_pre(p->socket, SOCKET_FAILURE_RESOURCES);
- return 0;
-}
-
-static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
- Socket *s = SOCKET(u);
- SocketResult f;
-
- assert(s);
- assert(pid >= 0);
-
- if (pid != s->control_pid)
- return;
-
- s->control_pid = 0;
-
- if (is_clean_exit(code, status, NULL))
- f = SOCKET_SUCCESS;
- else if (code == CLD_EXITED)
- f = SOCKET_FAILURE_EXIT_CODE;
- else if (code == CLD_KILLED)
- f = SOCKET_FAILURE_SIGNAL;
- else if (code == CLD_DUMPED)
- f = SOCKET_FAILURE_CORE_DUMP;
- else
- assert_not_reached("Unknown sigchld code");
-
- if (s->control_command) {
- exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status);
-
- if (s->control_command->ignore)
- f = SOCKET_SUCCESS;
- }
-
- log_unit_full(u->id,
- f == SOCKET_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
- "%s control process exited, code=%s status=%i",
- u->id, sigchld_code_to_string(code), status);
-
- if (f != SOCKET_SUCCESS)
- s->result = f;
-
- if (s->control_command &&
- s->control_command->command_next &&
- f == SOCKET_SUCCESS) {
-
- log_unit_debug(u->id,
- "%s running next command for state %s",
- u->id, socket_state_to_string(s->state));
- socket_run_next(s);
- } else {
- s->control_command = NULL;
- s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID;
-
- /* No further commands for this step, so let's figure
- * out what to do next */
-
- log_unit_debug(u->id,
- "%s got final SIGCHLD for state %s",
- u->id, socket_state_to_string(s->state));
-
- switch (s->state) {
-
- case SOCKET_START_PRE:
- if (f == SOCKET_SUCCESS)
- socket_enter_start_chown(s);
- else
- socket_enter_signal(s, SOCKET_FINAL_SIGTERM, f);
- break;
-
- case SOCKET_START_CHOWN:
- if (f == SOCKET_SUCCESS)
- socket_enter_start_post(s);
- else
- socket_enter_stop_pre(s, f);
- break;
-
- case SOCKET_START_POST:
- if (f == SOCKET_SUCCESS)
- socket_enter_listening(s);
- else
- socket_enter_stop_pre(s, f);
- break;
-
- case SOCKET_STOP_PRE:
- case SOCKET_STOP_PRE_SIGTERM:
- case SOCKET_STOP_PRE_SIGKILL:
- socket_enter_stop_post(s, f);
- break;
-
- case SOCKET_STOP_POST:
- case SOCKET_FINAL_SIGTERM:
- case SOCKET_FINAL_SIGKILL:
- socket_enter_dead(s, f);
- break;
-
- default:
- assert_not_reached("Uh, control process died at wrong time.");
- }
- }
-
- /* Notify clients about changed exit status */
- unit_add_to_dbus_queue(u);
-}
-
-static int socket_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
- Socket *s = SOCKET(userdata);
-
- assert(s);
- assert(s->timer_event_source == source);
-
- switch (s->state) {
-
- case SOCKET_START_PRE:
- log_unit_warning(UNIT(s)->id, "%s starting timed out. Terminating.", UNIT(s)->id);
- socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_TIMEOUT);
- break;
-
- case SOCKET_START_CHOWN:
- case SOCKET_START_POST:
- log_unit_warning(UNIT(s)->id, "%s starting timed out. Stopping.", UNIT(s)->id);
- socket_enter_stop_pre(s, SOCKET_FAILURE_TIMEOUT);
- break;
-
- case SOCKET_STOP_PRE:
- log_unit_warning(UNIT(s)->id, "%s stopping timed out. Terminating.", UNIT(s)->id);
- socket_enter_signal(s, SOCKET_STOP_PRE_SIGTERM, SOCKET_FAILURE_TIMEOUT);
- break;
-
- case SOCKET_STOP_PRE_SIGTERM:
- if (s->kill_context.send_sigkill) {
- log_unit_warning(UNIT(s)->id, "%s stopping timed out. Killing.", UNIT(s)->id);
- socket_enter_signal(s, SOCKET_STOP_PRE_SIGKILL, SOCKET_FAILURE_TIMEOUT);
- } else {
- log_unit_warning(UNIT(s)->id, "%s stopping timed out. Skipping SIGKILL. Ignoring.", UNIT(s)->id);
- socket_enter_stop_post(s, SOCKET_FAILURE_TIMEOUT);
- }
- break;
-
- case SOCKET_STOP_PRE_SIGKILL:
- log_unit_warning(UNIT(s)->id, "%s still around after SIGKILL. Ignoring.", UNIT(s)->id);
- socket_enter_stop_post(s, SOCKET_FAILURE_TIMEOUT);
- break;
-
- case SOCKET_STOP_POST:
- log_unit_warning(UNIT(s)->id, "%s stopping timed out (2). Terminating.", UNIT(s)->id);
- socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_TIMEOUT);
- break;
-
- case SOCKET_FINAL_SIGTERM:
- if (s->kill_context.send_sigkill) {
- log_unit_warning(UNIT(s)->id, "%s stopping timed out (2). Killing.", UNIT(s)->id);
- socket_enter_signal(s, SOCKET_FINAL_SIGKILL, SOCKET_FAILURE_TIMEOUT);
- } else {
- log_unit_warning(UNIT(s)->id, "%s stopping timed out (2). Skipping SIGKILL. Ignoring.", UNIT(s)->id);
- socket_enter_dead(s, SOCKET_FAILURE_TIMEOUT);
- }
- break;
-
- case SOCKET_FINAL_SIGKILL:
- log_unit_warning(UNIT(s)->id, "%s still around after SIGKILL (2). Entering failed mode.", UNIT(s)->id);
- socket_enter_dead(s, SOCKET_FAILURE_TIMEOUT);
- break;
-
- default:
- assert_not_reached("Timeout at wrong time.");
- }
-
- return 0;
-}
-
-int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds) {
- int *rfds;
- unsigned rn_fds, k;
- SocketPort *p;
-
- assert(s);
- assert(fds);
- assert(n_fds);
-
- /* Called from the service code for requesting our fds */
-
- rn_fds = 0;
- LIST_FOREACH(port, p, s->ports)
- if (p->fd >= 0)
- rn_fds++;
-
- if (rn_fds <= 0) {
- *fds = NULL;
- *n_fds = 0;
- return 0;
- }
-
- if (!(rfds = new(int, rn_fds)))
- return -ENOMEM;
-
- k = 0;
- LIST_FOREACH(port, p, s->ports)
- if (p->fd >= 0)
- rfds[k++] = p->fd;
-
- assert(k == rn_fds);
-
- *fds = rfds;
- *n_fds = rn_fds;
-
- return 0;
-}
-
-static void socket_reset_failed(Unit *u) {
- Socket *s = SOCKET(u);
-
- assert(s);
-
- if (s->state == SOCKET_FAILED)
- socket_set_state(s, SOCKET_DEAD);
-
- s->result = SOCKET_SUCCESS;
-}
-
-static void socket_notify_service_dead(Socket *s, bool failed_permanent) {
- assert(s);
-
- /* The service is dead. Dang!
- *
- * This is strictly for one-instance-for-all-connections
- * services. */
-
- if (s->state == SOCKET_RUNNING) {
- log_unit_debug(UNIT(s)->id, "%s got notified about service death (failed permanently: %s)", UNIT(s)->id, yes_no(failed_permanent));
- if (failed_permanent)
- socket_enter_stop_pre(s, SOCKET_FAILURE_SERVICE_FAILED_PERMANENT);
- else
- socket_enter_listening(s);
- }
-}
-
-void socket_connection_unref(Socket *s) {
- assert(s);
-
- /* The service is dead. Yay!
- *
- * This is strictly for one-instance-per-connection
- * services. */
-
- assert(s->n_connections > 0);
- s->n_connections--;
-
- log_unit_debug(UNIT(s)->id, "%s: One connection closed, %u left.", UNIT(s)->id, s->n_connections);
-}
-
-static void socket_trigger_notify(Unit *u, Unit *other) {
- Socket *s = SOCKET(u);
- Service *se;
-
- assert(u);
- assert(other);
-
- /* Don't propagate state changes from the service if we are
- already down or accepting connections */
- if ((s->state != SOCKET_RUNNING &&
- s->state != SOCKET_LISTENING) ||
- s->accept)
- return;
-
- if (other->load_state != UNIT_LOADED ||
- other->type != UNIT_SERVICE)
- return;
-
- se = SERVICE(other);
-
- if (se->state == SERVICE_FAILED)
- socket_notify_service_dead(s, se->result == SERVICE_FAILURE_START_LIMIT);
-
- if (se->state == SERVICE_DEAD ||
- se->state == SERVICE_FINAL_SIGTERM ||
- se->state == SERVICE_FINAL_SIGKILL ||
- se->state == SERVICE_AUTO_RESTART)
- socket_notify_service_dead(s, false);
-
- if (se->state == SERVICE_RUNNING)
- socket_set_state(s, SOCKET_RUNNING);
-}
-
-static int socket_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
- return unit_kill_common(u, who, signo, -1, SOCKET(u)->control_pid, error);
-}
-
-static int socket_get_timeout(Unit *u, uint64_t *timeout) {
- Socket *s = SOCKET(u);
- int r;
-
- if (!s->timer_event_source)
- return 0;
-
- r = sd_event_source_get_time(s->timer_event_source, timeout);
- if (r < 0)
- return r;
-
- return 1;
-}
-
-static const char* const socket_state_table[_SOCKET_STATE_MAX] = {
- [SOCKET_DEAD] = "dead",
- [SOCKET_START_PRE] = "start-pre",
- [SOCKET_START_CHOWN] = "start-chown",
- [SOCKET_START_POST] = "start-post",
- [SOCKET_LISTENING] = "listening",
- [SOCKET_RUNNING] = "running",
- [SOCKET_STOP_PRE] = "stop-pre",
- [SOCKET_STOP_PRE_SIGTERM] = "stop-pre-sigterm",
- [SOCKET_STOP_PRE_SIGKILL] = "stop-pre-sigkill",
- [SOCKET_STOP_POST] = "stop-post",
- [SOCKET_FINAL_SIGTERM] = "final-sigterm",
- [SOCKET_FINAL_SIGKILL] = "final-sigkill",
- [SOCKET_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(socket_state, SocketState);
-
-static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = {
- [SOCKET_EXEC_START_PRE] = "StartPre",
- [SOCKET_EXEC_START_CHOWN] = "StartChown",
- [SOCKET_EXEC_START_POST] = "StartPost",
- [SOCKET_EXEC_STOP_PRE] = "StopPre",
- [SOCKET_EXEC_STOP_POST] = "StopPost"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(socket_exec_command, SocketExecCommand);
-
-static const char* const socket_result_table[_SOCKET_RESULT_MAX] = {
- [SOCKET_SUCCESS] = "success",
- [SOCKET_FAILURE_RESOURCES] = "resources",
- [SOCKET_FAILURE_TIMEOUT] = "timeout",
- [SOCKET_FAILURE_EXIT_CODE] = "exit-code",
- [SOCKET_FAILURE_SIGNAL] = "signal",
- [SOCKET_FAILURE_CORE_DUMP] = "core-dump",
- [SOCKET_FAILURE_SERVICE_FAILED_PERMANENT] = "service-failed-permanent"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(socket_result, SocketResult);
-
-const UnitVTable socket_vtable = {
- .object_size = sizeof(Socket),
- .exec_context_offset = offsetof(Socket, exec_context),
- .cgroup_context_offset = offsetof(Socket, cgroup_context),
- .kill_context_offset = offsetof(Socket, kill_context),
- .exec_runtime_offset = offsetof(Socket, exec_runtime),
-
- .sections =
- "Unit\0"
- "Socket\0"
- "Install\0",
- .private_section = "Socket",
-
- .init = socket_init,
- .done = socket_done,
- .load = socket_load,
-
- .coldplug = socket_coldplug,
-
- .dump = socket_dump,
-
- .start = socket_start,
- .stop = socket_stop,
-
- .kill = socket_kill,
-
- .get_timeout = socket_get_timeout,
-
- .serialize = socket_serialize,
- .deserialize_item = socket_deserialize_item,
- .distribute_fds = socket_distribute_fds,
-
- .active_state = socket_active_state,
- .sub_state_to_string = socket_sub_state_to_string,
-
- .check_gc = socket_check_gc,
-
- .sigchld_event = socket_sigchld_event,
-
- .trigger_notify = socket_trigger_notify,
-
- .reset_failed = socket_reset_failed,
-
- .bus_interface = "org.freedesktop.systemd1.Socket",
- .bus_vtable = bus_socket_vtable,
- .bus_set_property = bus_socket_set_property,
- .bus_commit_properties = bus_socket_commit_properties,
-
- .status_message_formats = {
- /*.starting_stopping = {
- [0] = "Starting socket %s...",
- [1] = "Stopping socket %s...",
- },*/
- .finished_start_job = {
- [JOB_DONE] = "Listening on %s.",
- [JOB_FAILED] = "Failed to listen on %s.",
- [JOB_DEPENDENCY] = "Dependency failed for %s.",
- [JOB_TIMEOUT] = "Timed out starting %s.",
- },
- .finished_stop_job = {
- [JOB_DONE] = "Closed %s.",
- [JOB_FAILED] = "Failed stopping %s.",
- [JOB_TIMEOUT] = "Timed out stopping %s.",
- },
- },
-};
diff --git a/src/core/socket.h b/src/core/socket.h
deleted file mode 100644
index fa3ebdafa..000000000
--- a/src/core/socket.h
+++ /dev/null
@@ -1,194 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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;
-
-#include "socket-util.h"
-#include "mount.h"
-#include "service.h"
-
-typedef enum SocketState {
- SOCKET_DEAD,
- SOCKET_START_PRE,
- SOCKET_START_CHOWN,
- SOCKET_START_POST,
- SOCKET_LISTENING,
- SOCKET_RUNNING,
- SOCKET_STOP_PRE,
- SOCKET_STOP_PRE_SIGTERM,
- SOCKET_STOP_PRE_SIGKILL,
- SOCKET_STOP_POST,
- SOCKET_FINAL_SIGTERM,
- SOCKET_FINAL_SIGKILL,
- SOCKET_FAILED,
- _SOCKET_STATE_MAX,
- _SOCKET_STATE_INVALID = -1
-} SocketState;
-
-typedef enum SocketExecCommand {
- SOCKET_EXEC_START_PRE,
- SOCKET_EXEC_START_CHOWN,
- SOCKET_EXEC_START_POST,
- SOCKET_EXEC_STOP_PRE,
- SOCKET_EXEC_STOP_POST,
- _SOCKET_EXEC_COMMAND_MAX,
- _SOCKET_EXEC_COMMAND_INVALID = -1
-} SocketExecCommand;
-
-typedef enum SocketType {
- SOCKET_SOCKET,
- SOCKET_FIFO,
- SOCKET_SPECIAL,
- SOCKET_MQUEUE,
- _SOCKET_FIFO_MAX,
- _SOCKET_FIFO_INVALID = -1
-} SocketType;
-
-typedef enum SocketResult {
- SOCKET_SUCCESS,
- SOCKET_FAILURE_RESOURCES,
- SOCKET_FAILURE_TIMEOUT,
- SOCKET_FAILURE_EXIT_CODE,
- SOCKET_FAILURE_SIGNAL,
- SOCKET_FAILURE_CORE_DUMP,
- SOCKET_FAILURE_SERVICE_FAILED_PERMANENT,
- _SOCKET_RESULT_MAX,
- _SOCKET_RESULT_INVALID = -1
-} SocketResult;
-
-typedef struct SocketPort {
- Socket *socket;
-
- SocketType type;
- int fd;
-
- SocketAddress address;
- char *path;
- sd_event_source *event_source;
-
- LIST_FIELDS(struct SocketPort, port);
-} SocketPort;
-
-struct Socket {
- Unit meta;
-
- LIST_HEAD(SocketPort, ports);
-
- unsigned n_accepted;
- unsigned n_connections;
- unsigned max_connections;
-
- unsigned backlog;
- unsigned keep_alive_cnt;
- usec_t timeout_usec;
- usec_t keep_alive_time;
- usec_t keep_alive_interval;
- usec_t defer_accept;
-
- ExecCommand* exec_command[_SOCKET_EXEC_COMMAND_MAX];
- ExecContext exec_context;
- KillContext kill_context;
- CGroupContext cgroup_context;
- ExecRuntime *exec_runtime;
-
- /* For Accept=no sockets refers to the one service we'll
- activate. For Accept=yes sockets is either NULL, or filled
- when the next service we spawn. */
- UnitRef service;
-
- SocketState state, deserialized_state;
-
- sd_event_source *timer_event_source;
-
- ExecCommand* control_command;
- SocketExecCommand control_command_id;
- pid_t control_pid;
-
- mode_t directory_mode;
- mode_t socket_mode;
-
- SocketResult result;
-
- char **symlinks;
-
- bool accept;
- bool remove_on_stop;
-
- /* Socket options */
- bool keep_alive;
- bool no_delay;
- bool free_bind;
- bool transparent;
- bool broadcast;
- bool pass_cred;
- bool pass_sec;
-
- /* Only for INET6 sockets: issue IPV6_V6ONLY sockopt */
- SocketAddressBindIPv6Only bind_ipv6_only;
-
- int priority;
- int mark;
- size_t receive_buffer;
- size_t send_buffer;
- int ip_tos;
- int ip_ttl;
- size_t pipe_size;
- char *bind_to_device;
- char *tcp_congestion;
- bool reuse_port;
- long mq_maxmsg;
- long mq_msgsize;
-
- char *smack;
- char *smack_ip_in;
- char *smack_ip_out;
-
- bool selinux_context_from_net;
-
- char *user, *group;
-
- bool reset_cpu_usage:1;
-};
-
-/* Called from the service code when collecting fds */
-int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds);
-
-/* Called from the service code when a per-connection service ended */
-void socket_connection_unref(Socket *s);
-
-void socket_free_ports(Socket *s);
-
-extern const UnitVTable socket_vtable;
-
-const char* socket_state_to_string(SocketState i) _const_;
-SocketState socket_state_from_string(const char *s) _pure_;
-
-const char* socket_exec_command_to_string(SocketExecCommand i) _const_;
-SocketExecCommand socket_exec_command_from_string(const char *s) _pure_;
-
-const char* socket_result_to_string(SocketResult i) _const_;
-SocketResult socket_result_from_string(const char *s) _pure_;
-
-const char* socket_port_type_to_string(SocketPort *p) _pure_;
-
-int socket_instantiate_service(Socket *s);
diff --git a/src/core/swap.c b/src/core/swap.c
deleted file mode 100644
index 6b1bdb5c1..000000000
--- a/src/core/swap.c
+++ /dev/null
@@ -1,1522 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 <unistd.h>
-#include <sys/epoll.h>
-#include <sys/stat.h>
-#include <libudev.h>
-
-#include "unit.h"
-#include "swap.h"
-#include "unit-name.h"
-#include "dbus-swap.h"
-#include "special.h"
-#include "exit-status.h"
-#include "path-util.h"
-#include "virt.h"
-#include "udev-util.h"
-#include "fstab-util.h"
-
-static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = {
- [SWAP_DEAD] = UNIT_INACTIVE,
- [SWAP_ACTIVATING] = UNIT_ACTIVATING,
- [SWAP_ACTIVATING_DONE] = UNIT_ACTIVE,
- [SWAP_ACTIVE] = UNIT_ACTIVE,
- [SWAP_DEACTIVATING] = UNIT_DEACTIVATING,
- [SWAP_ACTIVATING_SIGTERM] = UNIT_DEACTIVATING,
- [SWAP_ACTIVATING_SIGKILL] = UNIT_DEACTIVATING,
- [SWAP_DEACTIVATING_SIGTERM] = UNIT_DEACTIVATING,
- [SWAP_DEACTIVATING_SIGKILL] = UNIT_DEACTIVATING,
- [SWAP_FAILED] = UNIT_FAILED
-};
-
-static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata);
-static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata);
-
-static void swap_unset_proc_swaps(Swap *s) {
- assert(s);
-
- if (!s->from_proc_swaps)
- return;
-
- free(s->parameters_proc_swaps.what);
- s->parameters_proc_swaps.what = NULL;
-
- s->from_proc_swaps = false;
-}
-
-static int swap_set_devnode(Swap *s, const char *devnode) {
- Hashmap *swaps;
- Swap *first;
- int r;
-
- assert(s);
-
- r = hashmap_ensure_allocated(&UNIT(s)->manager->swaps_by_devnode, &string_hash_ops);
- if (r < 0)
- return r;
-
- swaps = UNIT(s)->manager->swaps_by_devnode;
-
- if (s->devnode) {
- first = hashmap_get(swaps, s->devnode);
-
- LIST_REMOVE(same_devnode, first, s);
- if (first)
- hashmap_replace(swaps, first->devnode, first);
- else
- hashmap_remove(swaps, s->devnode);
-
- free(s->devnode);
- s->devnode = NULL;
- }
-
- if (devnode) {
- s->devnode = strdup(devnode);
- if (!s->devnode)
- return -ENOMEM;
-
- first = hashmap_get(swaps, s->devnode);
- LIST_PREPEND(same_devnode, first, s);
-
- return hashmap_replace(swaps, first->devnode, first);
- }
-
- return 0;
-}
-
-static void swap_init(Unit *u) {
- Swap *s = SWAP(u);
-
- assert(s);
- assert(UNIT(s)->load_state == UNIT_STUB);
-
- s->timeout_usec = u->manager->default_timeout_start_usec;
-
- s->exec_context.std_output = u->manager->default_std_output;
- s->exec_context.std_error = u->manager->default_std_error;
-
- s->parameters_proc_swaps.priority = s->parameters_fragment.priority = -1;
-
- s->control_command_id = _SWAP_EXEC_COMMAND_INVALID;
-
- u->ignore_on_isolate = true;
-}
-
-static void swap_unwatch_control_pid(Swap *s) {
- assert(s);
-
- if (s->control_pid <= 0)
- return;
-
- unit_unwatch_pid(UNIT(s), s->control_pid);
- s->control_pid = 0;
-}
-
-static void swap_done(Unit *u) {
- Swap *s = SWAP(u);
-
- assert(s);
-
- swap_unset_proc_swaps(s);
- swap_set_devnode(s, NULL);
-
- free(s->what);
- s->what = NULL;
-
- free(s->parameters_fragment.what);
- s->parameters_fragment.what = NULL;
-
- free(s->parameters_fragment.options);
- s->parameters_fragment.options = NULL;
-
- s->exec_runtime = exec_runtime_unref(s->exec_runtime);
- exec_command_done_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX);
- s->control_command = NULL;
-
- swap_unwatch_control_pid(s);
-
- s->timer_event_source = sd_event_source_unref(s->timer_event_source);
-}
-
-static int swap_arm_timer(Swap *s) {
- int r;
-
- assert(s);
-
- if (s->timeout_usec <= 0) {
- s->timer_event_source = sd_event_source_unref(s->timer_event_source);
- return 0;
- }
-
- if (s->timer_event_source) {
- r = sd_event_source_set_time(s->timer_event_source, now(CLOCK_MONOTONIC) + s->timeout_usec);
- if (r < 0)
- return r;
-
- return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
- }
-
- return sd_event_add_time(
- UNIT(s)->manager->event,
- &s->timer_event_source,
- CLOCK_MONOTONIC,
- now(CLOCK_MONOTONIC) + s->timeout_usec, 0,
- swap_dispatch_timer, s);
-}
-
-static int swap_add_device_links(Swap *s) {
- assert(s);
-
- if (!s->what)
- return 0;
-
- if (!s->from_fragment)
- return 0;
-
- if (is_device_path(s->what))
- return unit_add_node_link(UNIT(s), s->what, UNIT(s)->manager->running_as == SYSTEMD_SYSTEM);
- else
- /* File based swap devices need to be ordered after
- * systemd-remount-fs.service, since they might need a
- * writable file system. */
- return unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_REMOUNT_FS_SERVICE, NULL, true);
-}
-
-static int swap_add_default_dependencies(Swap *s) {
- assert(s);
-
- if (UNIT(s)->manager->running_as != SYSTEMD_SYSTEM)
- return 0;
-
- if (detect_container(NULL) > 0)
- return 0;
-
- return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
-}
-
-static int swap_verify(Swap *s) {
- bool b;
- _cleanup_free_ char *e = NULL;
-
- if (UNIT(s)->load_state != UNIT_LOADED)
- return 0;
-
- e = unit_name_from_path(s->what, ".swap");
- if (!e)
- return log_oom();
-
- b = unit_has_name(UNIT(s), e);
- if (!b) {
- log_unit_error(UNIT(s)->id, "%s: Value of \"What\" and unit name do not match, not loading.", UNIT(s)->id);
- return -EINVAL;
- }
-
- if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) {
- log_unit_error(UNIT(s)->id, "%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing to load.", UNIT(s)->id);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int swap_load_devnode(Swap *s) {
- _cleanup_udev_device_unref_ struct udev_device *d = NULL;
- struct stat st;
- const char *p;
-
- 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)
- return 0;
-
- p = udev_device_get_devnode(d);
- if (!p)
- return 0;
-
- return swap_set_devnode(s, p);
-}
-
-static int swap_load(Unit *u) {
- int r;
- Swap *s = SWAP(u);
-
- assert(s);
- assert(u->load_state == UNIT_STUB);
-
- /* Load a .swap file */
- r = unit_load_fragment_and_dropin_optional(u);
- if (r < 0)
- return r;
-
- if (u->load_state == UNIT_LOADED) {
-
- if (UNIT(s)->fragment_path)
- s->from_fragment = true;
-
- if (!s->what) {
- if (s->parameters_fragment.what)
- s->what = strdup(s->parameters_fragment.what);
- else if (s->parameters_proc_swaps.what)
- s->what = strdup(s->parameters_proc_swaps.what);
- else
- s->what = unit_name_to_path(u->id);
-
- if (!s->what)
- return -ENOMEM;
- }
-
- path_kill_slashes(s->what);
-
- if (!UNIT(s)->description) {
- r = unit_set_description(u, s->what);
- if (r < 0)
- return r;
- }
-
- r = unit_require_mounts_for(UNIT(s), s->what);
- if (r < 0)
- return r;
-
- r = swap_add_device_links(s);
- if (r < 0)
- return r;
-
- r = swap_load_devnode(s);
- if (r < 0)
- return r;
-
- r = unit_patch_contexts(u);
- if (r < 0)
- return r;
-
- r = unit_add_exec_dependencies(u, &s->exec_context);
- if (r < 0)
- return r;
-
- r = unit_add_default_slice(u, &s->cgroup_context);
- if (r < 0)
- return r;
-
- if (UNIT(s)->default_dependencies) {
- r = swap_add_default_dependencies(s);
- if (r < 0)
- return r;
- }
- }
-
- return swap_verify(s);
-}
-
-static int swap_setup_unit(
- Manager *m,
- const char *what,
- const char *what_proc_swaps,
- int priority,
- bool set_flags) {
-
- _cleanup_free_ char *e = NULL;
- bool delete = false;
- Unit *u = NULL;
- int r;
- SwapParameters *p;
-
- assert(m);
- assert(what);
- assert(what_proc_swaps);
-
- e = unit_name_from_path(what, ".swap");
- if (!e)
- return log_oom();
-
- u = manager_get_unit(m, e);
-
- if (u &&
- SWAP(u)->from_proc_swaps &&
- !path_equal(SWAP(u)->parameters_proc_swaps.what, what_proc_swaps)) {
- log_error("Swap %s appeared twice with different device paths %s and %s", e, SWAP(u)->parameters_proc_swaps.what, what_proc_swaps);
- return -EEXIST;
- }
-
- if (!u) {
- delete = true;
-
- u = unit_new(m, sizeof(Swap));
- if (!u)
- return log_oom();
-
- r = unit_add_name(u, e);
- if (r < 0)
- goto fail;
-
- SWAP(u)->what = strdup(what);
- if (!SWAP(u)->what) {
- r = -ENOMEM;
- goto fail;
- }
-
- unit_add_to_load_queue(u);
- } else
- delete = false;
-
- p = &SWAP(u)->parameters_proc_swaps;
-
- if (!p->what) {
- p->what = strdup(what_proc_swaps);
- if (!p->what) {
- r = -ENOMEM;
- goto fail;
- }
- }
-
- if (set_flags) {
- SWAP(u)->is_active = true;
- SWAP(u)->just_activated = !SWAP(u)->from_proc_swaps;
- }
-
- SWAP(u)->from_proc_swaps = true;
-
- p->priority = priority;
-
- unit_add_to_dbus_queue(u);
- return 0;
-
-fail:
- log_unit_warning_errno(e, r, "Failed to load swap unit: %m");
-
- if (delete && u)
- unit_free(u);
-
- return r;
-}
-
-static int swap_process_new(Manager *m, const char *device, int prio, bool set_flags) {
- _cleanup_udev_device_unref_ struct udev_device *d = NULL;
- struct udev_list_entry *item = NULL, *first = NULL;
- const char *dn;
- struct stat st;
- int r;
-
- assert(m);
-
- r = swap_setup_unit(m, device, device, prio, set_flags);
- if (r < 0)
- return r;
-
- /* If this is a block device, then let's add duplicates for
- * all other names of this block device */
- 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)
- return 0;
-
- /* Add the main device node */
- dn = udev_device_get_devnode(d);
- if (dn && !streq(dn, device))
- swap_setup_unit(m, dn, device, prio, set_flags);
-
- /* Add additional units for all symlinks */
- first = udev_device_get_devlinks_list_entry(d);
- udev_list_entry_foreach(item, first) {
- const char *p;
-
- /* Don't bother with the /dev/block links */
- p = udev_list_entry_get_name(item);
-
- if (streq(p, device))
- continue;
-
- if (path_startswith(p, "/dev/block/"))
- continue;
-
- if (stat(p, &st) >= 0)
- if (!S_ISBLK(st.st_mode) ||
- st.st_rdev != udev_device_get_devnum(d))
- continue;
-
- swap_setup_unit(m, p, device, prio, set_flags);
- }
-
- return r;
-}
-
-static void swap_set_state(Swap *s, SwapState state) {
- SwapState old_state;
- Swap *other;
-
- assert(s);
-
- old_state = s->state;
- s->state = state;
-
- if (state != SWAP_ACTIVATING &&
- state != SWAP_ACTIVATING_SIGTERM &&
- state != SWAP_ACTIVATING_SIGKILL &&
- state != SWAP_ACTIVATING_DONE &&
- state != SWAP_DEACTIVATING &&
- state != SWAP_DEACTIVATING_SIGTERM &&
- state != SWAP_DEACTIVATING_SIGKILL) {
- s->timer_event_source = sd_event_source_unref(s->timer_event_source);
- swap_unwatch_control_pid(s);
- s->control_command = NULL;
- s->control_command_id = _SWAP_EXEC_COMMAND_INVALID;
- }
-
- if (state != old_state)
- log_unit_debug(UNIT(s)->id,
- "%s changed %s -> %s",
- UNIT(s)->id,
- 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);
-
- /* If there other units for the same device node have a job
- queued it might be worth checking again if it is runnable
- now. This is necessary, since swap_start() refuses
- operation with EAGAIN if there's already another job for
- the same device node queued. */
- LIST_FOREACH_OTHERS(same_devnode, other, s)
- if (UNIT(other)->job)
- job_add_to_run_queue(UNIT(other)->job);
-}
-
-static int swap_coldplug(Unit *u, Hashmap *deferred_work) {
- Swap *s = SWAP(u);
- SwapState new_state = SWAP_DEAD;
- int r;
-
- assert(s);
- assert(s->state == SWAP_DEAD);
-
- if (s->deserialized_state != s->state)
- new_state = s->deserialized_state;
- else if (s->from_proc_swaps)
- new_state = SWAP_ACTIVE;
-
- if (new_state == s->state)
- return 0;
-
- if (new_state == SWAP_ACTIVATING ||
- new_state == SWAP_ACTIVATING_SIGTERM ||
- new_state == SWAP_ACTIVATING_SIGKILL ||
- new_state == SWAP_ACTIVATING_DONE ||
- new_state == SWAP_DEACTIVATING ||
- new_state == SWAP_DEACTIVATING_SIGTERM ||
- new_state == SWAP_DEACTIVATING_SIGKILL) {
-
- if (s->control_pid <= 0)
- return -EBADMSG;
-
- r = unit_watch_pid(UNIT(s), s->control_pid);
- if (r < 0)
- return r;
-
- r = swap_arm_timer(s);
- if (r < 0)
- return r;
- }
-
- swap_set_state(s, new_state);
- return 0;
-}
-
-static void swap_dump(Unit *u, FILE *f, const char *prefix) {
- Swap *s = SWAP(u);
- SwapParameters *p;
-
- assert(s);
- assert(f);
-
- if (s->from_proc_swaps)
- p = &s->parameters_proc_swaps;
- else if (s->from_fragment)
- p = &s->parameters_fragment;
- else
- p = NULL;
-
- fprintf(f,
- "%sSwap State: %s\n"
- "%sResult: %s\n"
- "%sWhat: %s\n"
- "%sFrom /proc/swaps: %s\n"
- "%sFrom fragment: %s\n",
- prefix, swap_state_to_string(s->state),
- prefix, swap_result_to_string(s->result),
- prefix, s->what,
- prefix, yes_no(s->from_proc_swaps),
- prefix, yes_no(s->from_fragment));
-
- if (s->devnode)
- fprintf(f, "%sDevice Node: %s\n", prefix, s->devnode);
-
- if (p)
- fprintf(f,
- "%sPriority: %i\n"
- "%sOptions: %s\n",
- prefix, p->priority,
- prefix, strempty(p->options));
-
- if (s->control_pid > 0)
- fprintf(f,
- "%sControl PID: "PID_FMT"\n",
- prefix, s->control_pid);
-
- exec_context_dump(&s->exec_context, f, prefix);
- kill_context_dump(&s->kill_context, f, prefix);
-}
-
-static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
- pid_t pid;
- int r;
- ExecParameters exec_params = {
- .apply_permissions = true,
- .apply_chroot = true,
- .apply_tty_stdin = true,
- };
-
- assert(s);
- assert(c);
- assert(_pid);
-
- (void) unit_realize_cgroup(UNIT(s));
- if (s->reset_cpu_usage) {
- (void) unit_reset_cpu_usage(UNIT(s));
- s->reset_cpu_usage = false;
- }
-
- r = unit_setup_exec_runtime(UNIT(s));
- if (r < 0)
- goto fail;
-
- r = swap_arm_timer(s);
- if (r < 0)
- goto fail;
-
- exec_params.environment = UNIT(s)->manager->environment;
- exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn;
- exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
- exec_params.cgroup_path = UNIT(s)->cgroup_path;
- exec_params.cgroup_delegate = s->cgroup_context.delegate;
- exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager);
- exec_params.unit_id = UNIT(s)->id;
-
- r = exec_spawn(c,
- &s->exec_context,
- &exec_params,
- s->exec_runtime,
- &pid);
- if (r < 0)
- goto fail;
-
- r = unit_watch_pid(UNIT(s), pid);
- if (r < 0)
- /* FIXME: we need to do something here */
- goto fail;
-
- *_pid = pid;
-
- return 0;
-
-fail:
- s->timer_event_source = sd_event_source_unref(s->timer_event_source);
- return r;
-}
-
-static void swap_enter_dead(Swap *s, SwapResult f) {
- assert(s);
-
- if (f != SWAP_SUCCESS)
- s->result = f;
-
- exec_runtime_destroy(s->exec_runtime);
- s->exec_runtime = exec_runtime_unref(s->exec_runtime);
-
- exec_context_destroy_runtime_directory(&s->exec_context, manager_get_runtime_prefix(UNIT(s)->manager));
-
- swap_set_state(s, s->result != SWAP_SUCCESS ? SWAP_FAILED : SWAP_DEAD);
-}
-
-static void swap_enter_active(Swap *s, SwapResult f) {
- assert(s);
-
- if (f != SWAP_SUCCESS)
- s->result = f;
-
- swap_set_state(s, SWAP_ACTIVE);
-}
-
-static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) {
- int r;
-
- assert(s);
-
- if (f != SWAP_SUCCESS)
- s->result = f;
-
- r = unit_kill_context(
- UNIT(s),
- &s->kill_context,
- (state != SWAP_ACTIVATING_SIGTERM && state != SWAP_DEACTIVATING_SIGTERM) ?
- KILL_KILL : KILL_TERMINATE,
- -1,
- s->control_pid,
- false);
- if (r < 0)
- goto fail;
-
- if (r > 0) {
- r = swap_arm_timer(s);
- if (r < 0)
- goto fail;
-
- swap_set_state(s, state);
- } else if (state == SWAP_ACTIVATING_SIGTERM)
- swap_enter_signal(s, SWAP_ACTIVATING_SIGKILL, SWAP_SUCCESS);
- else if (state == SWAP_DEACTIVATING_SIGTERM)
- swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, SWAP_SUCCESS);
- else
- swap_enter_dead(s, SWAP_SUCCESS);
-
- return;
-
-fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to kill processes: %m", UNIT(s)->id);
- swap_enter_dead(s, SWAP_FAILURE_RESOURCES);
-}
-
-static void swap_enter_activating(Swap *s) {
- _cleanup_free_ char *discard = NULL;
- int r, priority = -1;
-
- assert(s);
-
- s->control_command_id = SWAP_EXEC_ACTIVATE;
- s->control_command = s->exec_command + SWAP_EXEC_ACTIVATE;
-
- if (s->from_fragment) {
- fstab_filter_options(s->parameters_fragment.options, "discard\0",
- NULL, &discard, NULL);
-
- priority = s->parameters_fragment.priority;
- if (priority < 0) {
- r = fstab_find_pri(s->parameters_fragment.options, &priority);
- if (r < 0)
- log_notice_errno(r, "Failed to parse swap priority \"%s\", ignoring: %m",
- s->parameters_fragment.options);
- }
- }
-
- r = exec_command_set(s->control_command, "/sbin/swapon", NULL);
- if (r < 0)
- goto fail;
-
- if (priority >= 0) {
- char p[DECIMAL_STR_MAX(int)];
-
- sprintf(p, "%i", priority);
- r = exec_command_append(s->control_command, "-p", p, NULL);
- if (r < 0)
- goto fail;
- }
-
- if (discard && !streq(discard, "none")) {
- const char *discard_arg;
-
- if (streq(discard, "all"))
- discard_arg = "--discard";
- else
- discard_arg = strjoina("--discard=", discard);
-
- r = exec_command_append(s->control_command, discard_arg, NULL);
- if (r < 0)
- goto fail;
- }
-
- r = exec_command_append(s->control_command, s->what, NULL);
- if (r < 0)
- goto fail;
-
- swap_unwatch_control_pid(s);
-
- r = swap_spawn(s, s->control_command, &s->control_pid);
- if (r < 0)
- goto fail;
-
- swap_set_state(s, SWAP_ACTIVATING);
-
- return;
-
-fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'swapon' task: %m", UNIT(s)->id);
- swap_enter_dead(s, SWAP_FAILURE_RESOURCES);
-}
-
-static void swap_enter_deactivating(Swap *s) {
- int r;
-
- assert(s);
-
- s->control_command_id = SWAP_EXEC_DEACTIVATE;
- s->control_command = s->exec_command + SWAP_EXEC_DEACTIVATE;
-
- r = exec_command_set(s->control_command,
- "/sbin/swapoff",
- s->what,
- NULL);
- if (r < 0)
- goto fail;
-
- swap_unwatch_control_pid(s);
-
- r = swap_spawn(s, s->control_command, &s->control_pid);
- if (r < 0)
- goto fail;
-
- swap_set_state(s, SWAP_DEACTIVATING);
-
- return;
-
-fail:
- log_unit_warning_errno(UNIT(s)->id, r, "%s failed to run 'swapoff' task: %m", UNIT(s)->id);
- swap_enter_active(s, SWAP_FAILURE_RESOURCES);
-}
-
-static int swap_start(Unit *u) {
- Swap *s = SWAP(u), *other;
-
- assert(s);
-
- /* We cannot fulfill this request right now, try again later
- * please! */
-
- if (s->state == SWAP_DEACTIVATING ||
- s->state == SWAP_DEACTIVATING_SIGTERM ||
- s->state == SWAP_DEACTIVATING_SIGKILL ||
- s->state == SWAP_ACTIVATING_SIGTERM ||
- s->state == SWAP_ACTIVATING_SIGKILL)
- return -EAGAIN;
-
- if (s->state == SWAP_ACTIVATING)
- return 0;
-
- assert(s->state == SWAP_DEAD || s->state == SWAP_FAILED);
-
- if (detect_container(NULL) > 0)
- return -EPERM;
-
- /* If there's a job for another swap unit for the same node
- * running, then let's not dispatch this one for now, and wait
- * until that other job has finished. */
- LIST_FOREACH_OTHERS(same_devnode, other, s)
- if (UNIT(other)->job && UNIT(other)->job->state == JOB_RUNNING)
- return -EAGAIN;
-
- s->result = SWAP_SUCCESS;
- s->reset_cpu_usage = true;
-
- swap_enter_activating(s);
- return 1;
-}
-
-static int swap_stop(Unit *u) {
- Swap *s = SWAP(u);
-
- assert(s);
-
- if (s->state == SWAP_DEACTIVATING ||
- s->state == SWAP_DEACTIVATING_SIGTERM ||
- s->state == SWAP_DEACTIVATING_SIGKILL ||
- s->state == SWAP_ACTIVATING_SIGTERM ||
- s->state == SWAP_ACTIVATING_SIGKILL)
- return 0;
-
- assert(s->state == SWAP_ACTIVATING ||
- s->state == SWAP_ACTIVATING_DONE ||
- s->state == SWAP_ACTIVE);
-
- if (detect_container(NULL) > 0)
- return -EPERM;
-
- swap_enter_deactivating(s);
- return 1;
-}
-
-static int swap_serialize(Unit *u, FILE *f, FDSet *fds) {
- Swap *s = SWAP(u);
-
- assert(s);
- assert(f);
- assert(fds);
-
- unit_serialize_item(u, f, "state", swap_state_to_string(s->state));
- unit_serialize_item(u, f, "result", swap_result_to_string(s->result));
-
- if (s->control_pid > 0)
- unit_serialize_item_format(u, f, "control-pid", PID_FMT, s->control_pid);
-
- if (s->control_command_id >= 0)
- unit_serialize_item(u, f, "control-command", swap_exec_command_to_string(s->control_command_id));
-
- return 0;
-}
-
-static int swap_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Swap *s = SWAP(u);
-
- assert(s);
- assert(fds);
-
- if (streq(key, "state")) {
- SwapState state;
-
- state = swap_state_from_string(value);
- if (state < 0)
- log_unit_debug(u->id, "Failed to parse state value %s", value);
- else
- s->deserialized_state = state;
- } else if (streq(key, "result")) {
- SwapResult f;
-
- f = swap_result_from_string(value);
- if (f < 0)
- log_unit_debug(u->id, "Failed to parse result value %s", value);
- else if (f != SWAP_SUCCESS)
- s->result = f;
- } else if (streq(key, "control-pid")) {
- pid_t pid;
-
- if (parse_pid(value, &pid) < 0)
- log_unit_debug(u->id, "Failed to parse control-pid value %s", value);
- else
- s->control_pid = pid;
-
- } else if (streq(key, "control-command")) {
- SwapExecCommand id;
-
- id = swap_exec_command_from_string(value);
- if (id < 0)
- log_unit_debug(u->id, "Failed to parse exec-command value %s", value);
- else {
- s->control_command_id = id;
- s->control_command = s->exec_command + id;
- }
- } else
- log_unit_debug(u->id, "Unknown serialization key '%s'", key);
-
- return 0;
-}
-
-_pure_ static UnitActiveState swap_active_state(Unit *u) {
- assert(u);
-
- return state_translation_table[SWAP(u)->state];
-}
-
-_pure_ static const char *swap_sub_state_to_string(Unit *u) {
- assert(u);
-
- return swap_state_to_string(SWAP(u)->state);
-}
-
-_pure_ static bool swap_check_gc(Unit *u) {
- Swap *s = SWAP(u);
-
- assert(s);
-
- return s->from_proc_swaps;
-}
-
-static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) {
- Swap *s = SWAP(u);
- SwapResult f;
-
- assert(s);
- assert(pid >= 0);
-
- if (pid != s->control_pid)
- return;
-
- s->control_pid = 0;
-
- if (is_clean_exit(code, status, NULL))
- f = SWAP_SUCCESS;
- else if (code == CLD_EXITED)
- f = SWAP_FAILURE_EXIT_CODE;
- else if (code == CLD_KILLED)
- f = SWAP_FAILURE_SIGNAL;
- else if (code == CLD_DUMPED)
- f = SWAP_FAILURE_CORE_DUMP;
- else
- assert_not_reached("Unknown code");
-
- if (f != SWAP_SUCCESS)
- s->result = f;
-
- if (s->control_command) {
- exec_status_exit(&s->control_command->exec_status, &s->exec_context, pid, code, status);
-
- s->control_command = NULL;
- s->control_command_id = _SWAP_EXEC_COMMAND_INVALID;
- }
-
- log_unit_full(u->id,
- f == SWAP_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
- "%s swap process exited, code=%s status=%i",
- u->id, sigchld_code_to_string(code), status);
-
- switch (s->state) {
-
- case SWAP_ACTIVATING:
- case SWAP_ACTIVATING_DONE:
- case SWAP_ACTIVATING_SIGTERM:
- case SWAP_ACTIVATING_SIGKILL:
-
- if (f == SWAP_SUCCESS)
- swap_enter_active(s, f);
- else
- swap_enter_dead(s, f);
- break;
-
- case SWAP_DEACTIVATING:
- case SWAP_DEACTIVATING_SIGKILL:
- case SWAP_DEACTIVATING_SIGTERM:
-
- swap_enter_dead(s, f);
- break;
-
- default:
- assert_not_reached("Uh, control process died at wrong time.");
- }
-
- /* Notify clients about changed exit status */
- unit_add_to_dbus_queue(u);
-}
-
-static int swap_dispatch_timer(sd_event_source *source, usec_t usec, void *userdata) {
- Swap *s = SWAP(userdata);
-
- assert(s);
- assert(s->timer_event_source == source);
-
- switch (s->state) {
-
- case SWAP_ACTIVATING:
- case SWAP_ACTIVATING_DONE:
- log_unit_warning(UNIT(s)->id, "%s activation timed out. Stopping.", UNIT(s)->id);
- swap_enter_signal(s, SWAP_ACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT);
- break;
-
- case SWAP_DEACTIVATING:
- log_unit_warning(UNIT(s)->id, "%s deactivation timed out. Stopping.", UNIT(s)->id);
- swap_enter_signal(s, SWAP_DEACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT);
- break;
-
- case SWAP_ACTIVATING_SIGTERM:
- if (s->kill_context.send_sigkill) {
- log_unit_warning(UNIT(s)->id, "%s activation timed out. Killing.", UNIT(s)->id);
- swap_enter_signal(s, SWAP_ACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT);
- } else {
- log_unit_warning(UNIT(s)->id, "%s activation timed out. Skipping SIGKILL. Ignoring.", UNIT(s)->id);
- swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
- }
- break;
-
- case SWAP_DEACTIVATING_SIGTERM:
- if (s->kill_context.send_sigkill) {
- log_unit_warning(UNIT(s)->id, "%s deactivation timed out. Killing.", UNIT(s)->id);
- swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT);
- } else {
- log_unit_warning(UNIT(s)->id, "%s deactivation timed out. Skipping SIGKILL. Ignoring.", UNIT(s)->id);
- swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
- }
- break;
-
- case SWAP_ACTIVATING_SIGKILL:
- case SWAP_DEACTIVATING_SIGKILL:
- log_unit_warning(UNIT(s)->id, "%s swap process still around after SIGKILL. Ignoring.", UNIT(s)->id);
- swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
- break;
-
- default:
- assert_not_reached("Timeout at wrong time.");
- }
-
- return 0;
-}
-
-static int swap_load_proc_swaps(Manager *m, bool set_flags) {
- unsigned i;
- int r = 0;
-
- assert(m);
-
- rewind(m->proc_swaps);
-
- (void) fscanf(m->proc_swaps, "%*s %*s %*s %*s %*s\n");
-
- for (i = 1;; i++) {
- _cleanup_free_ char *dev = NULL, *d = NULL;
- int prio = 0, k;
-
- k = fscanf(m->proc_swaps,
- "%ms " /* device/file */
- "%*s " /* type of swap */
- "%*s " /* swap size */
- "%*s " /* used */
- "%i\n", /* priority */
- &dev, &prio);
- if (k != 2) {
- if (k == EOF)
- break;
-
- log_warning("Failed to parse /proc/swaps:%u.", i);
- continue;
- }
-
- d = cunescape(dev);
- if (!d)
- return log_oom();
-
- device_found_node(m, d, true, DEVICE_FOUND_SWAP, set_flags);
-
- k = swap_process_new(m, d, prio, set_flags);
- if (k < 0)
- r = k;
- }
-
- return r;
-}
-
-static int swap_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
- Manager *m = userdata;
- Unit *u;
- int r;
-
- assert(m);
- assert(revents & EPOLLPRI);
-
- r = swap_load_proc_swaps(m, true);
- if (r < 0) {
- log_error_errno(r, "Failed to reread /proc/swaps: %m");
-
- /* Reset flags, just in case, for late calls */
- LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_SWAP]) {
- Swap *swap = SWAP(u);
-
- swap->is_active = swap->just_activated = false;
- }
-
- return 0;
- }
-
- manager_dispatch_load_queue(m);
-
- LIST_FOREACH(units_by_type, u, m->units_by_type[UNIT_SWAP]) {
- Swap *swap = SWAP(u);
-
- if (!swap->is_active) {
- /* This has just been deactivated */
-
- swap_unset_proc_swaps(swap);
-
- switch (swap->state) {
-
- case SWAP_ACTIVE:
- swap_enter_dead(swap, SWAP_SUCCESS);
- break;
-
- default:
- /* Fire again */
- swap_set_state(swap, swap->state);
- break;
- }
-
- if (swap->what)
- device_found_node(m, swap->what, false, DEVICE_FOUND_SWAP, true);
-
- } else if (swap->just_activated) {
-
- /* New swap entry */
-
- switch (swap->state) {
-
- case SWAP_DEAD:
- case SWAP_FAILED:
- swap_enter_active(swap, SWAP_SUCCESS);
- break;
-
- case SWAP_ACTIVATING:
- swap_set_state(swap, SWAP_ACTIVATING_DONE);
- break;
-
- default:
- /* Nothing really changed, but let's
- * issue an notification call
- * nonetheless, in case somebody is
- * waiting for this. */
- swap_set_state(swap, swap->state);
- break;
- }
- }
-
- /* Reset the flags for later calls */
- swap->is_active = swap->just_activated = false;
- }
-
- return 1;
-}
-
-static Unit *swap_following(Unit *u) {
- Swap *s = SWAP(u);
- Swap *other, *first = NULL;
-
- assert(s);
-
- /* If the user configured the swap through /etc/fstab or
- * a device unit, follow that. */
-
- if (s->from_fragment)
- return NULL;
-
- LIST_FOREACH_OTHERS(same_devnode, other, s)
- if (other->from_fragment)
- return UNIT(other);
-
- /* Otherwise make everybody follow the unit that's named after
- * the swap device in the kernel */
-
- if (streq_ptr(s->what, s->devnode))
- return NULL;
-
- LIST_FOREACH_AFTER(same_devnode, other, s)
- if (streq_ptr(other->what, other->devnode))
- return UNIT(other);
-
- LIST_FOREACH_BEFORE(same_devnode, other, s) {
- if (streq_ptr(other->what, other->devnode))
- return UNIT(other);
-
- first = other;
- }
-
- /* Fall back to the first on the list */
- return UNIT(first);
-}
-
-static int swap_following_set(Unit *u, Set **_set) {
- Swap *s = SWAP(u), *other;
- Set *set;
- int r;
-
- assert(s);
- assert(_set);
-
- if (LIST_JUST_US(same_devnode, s)) {
- *_set = NULL;
- return 0;
- }
-
- set = set_new(NULL);
- if (!set)
- return -ENOMEM;
-
- LIST_FOREACH_OTHERS(same_devnode, other, s) {
- r = set_put(set, other);
- if (r < 0)
- goto fail;
- }
-
- *_set = 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);
-
- if (m->proc_swaps) {
- fclose(m->proc_swaps);
- m->proc_swaps = NULL;
- }
-
- hashmap_free(m->swaps_by_devnode);
- m->swaps_by_devnode = NULL;
-}
-
-static int swap_enumerate(Manager *m) {
- int r;
-
- assert(m);
-
- if (!m->proc_swaps) {
- m->proc_swaps = fopen("/proc/swaps", "re");
- if (!m->proc_swaps)
- return errno == ENOENT ? 0 : -errno;
-
- r = sd_event_add_io(m->event, &m->swap_event_source, fileno(m->proc_swaps), EPOLLPRI, swap_dispatch_io, m);
- if (r < 0)
- goto fail;
-
- /* Dispatch this before we dispatch SIGCHLD, so that
- * we always get the events from /proc/swaps before
- * the SIGCHLD of /sbin/swapon. */
- r = sd_event_source_set_priority(m->swap_event_source, -10);
- if (r < 0)
- goto fail;
- }
-
- r = swap_load_proc_swaps(m, false);
- if (r < 0)
- goto fail;
-
- return 0;
-
-fail:
- swap_shutdown(m);
- return r;
-}
-
-int swap_process_device_new(Manager *m, struct udev_device *dev) {
- struct udev_list_entry *item = NULL, *first = NULL;
- _cleanup_free_ char *e = NULL;
- const char *dn;
- Swap *s;
- int r = 0;
-
- assert(m);
- assert(dev);
-
- dn = udev_device_get_devnode(dev);
- if (!dn)
- return 0;
-
- e = unit_name_from_path(dn, ".swap");
- if (!e)
- return -ENOMEM;
-
- s = hashmap_get(m->units, e);
- if (s)
- r = swap_set_devnode(s, dn);
-
- first = udev_device_get_devlinks_list_entry(dev);
- udev_list_entry_foreach(item, first) {
- _cleanup_free_ char *n = NULL;
-
- n = unit_name_from_path(udev_list_entry_get_name(item), ".swap");
- if (!n)
- return -ENOMEM;
-
- s = hashmap_get(m->units, n);
- if (s) {
- int q;
-
- q = swap_set_devnode(s, dn);
- if (q < 0)
- r = q;
- }
- }
-
- return r;
-}
-
-int swap_process_device_remove(Manager *m, struct udev_device *dev) {
- const char *dn;
- int r = 0;
- Swap *s;
-
- dn = udev_device_get_devnode(dev);
- if (!dn)
- return 0;
-
- while ((s = hashmap_get(m->swaps_by_devnode, dn))) {
- int q;
-
- q = swap_set_devnode(s, NULL);
- if (q < 0)
- r = q;
- }
-
- return r;
-}
-
-static void swap_reset_failed(Unit *u) {
- Swap *s = SWAP(u);
-
- assert(s);
-
- if (s->state == SWAP_FAILED)
- swap_set_state(s, SWAP_DEAD);
-
- s->result = SWAP_SUCCESS;
-}
-
-static int swap_kill(Unit *u, KillWho who, int signo, sd_bus_error *error) {
- return unit_kill_common(u, who, signo, -1, SWAP(u)->control_pid, error);
-}
-
-static int swap_get_timeout(Unit *u, uint64_t *timeout) {
- Swap *s = SWAP(u);
- int r;
-
- if (!s->timer_event_source)
- return 0;
-
- r = sd_event_source_get_time(s->timer_event_source, timeout);
- if (r < 0)
- return r;
-
- return 1;
-}
-
-static bool swap_supported(Manager *m) {
- static int supported = -1;
-
- /* If swap support is not available in the kernel, or we are
- * running in a container we don't support swap units, and any
- * attempts to starting one should fail immediately. */
-
- if (supported < 0)
- supported =
- access("/proc/swaps", F_OK) >= 0 &&
- detect_container(NULL) <= 0;
-
- return supported;
-}
-
-static const char* const swap_state_table[_SWAP_STATE_MAX] = {
- [SWAP_DEAD] = "dead",
- [SWAP_ACTIVATING] = "activating",
- [SWAP_ACTIVATING_DONE] = "activating-done",
- [SWAP_ACTIVE] = "active",
- [SWAP_DEACTIVATING] = "deactivating",
- [SWAP_ACTIVATING_SIGTERM] = "activating-sigterm",
- [SWAP_ACTIVATING_SIGKILL] = "activating-sigkill",
- [SWAP_DEACTIVATING_SIGTERM] = "deactivating-sigterm",
- [SWAP_DEACTIVATING_SIGKILL] = "deactivating-sigkill",
- [SWAP_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState);
-
-static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = {
- [SWAP_EXEC_ACTIVATE] = "ExecActivate",
- [SWAP_EXEC_DEACTIVATE] = "ExecDeactivate",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(swap_exec_command, SwapExecCommand);
-
-static const char* const swap_result_table[_SWAP_RESULT_MAX] = {
- [SWAP_SUCCESS] = "success",
- [SWAP_FAILURE_RESOURCES] = "resources",
- [SWAP_FAILURE_TIMEOUT] = "timeout",
- [SWAP_FAILURE_EXIT_CODE] = "exit-code",
- [SWAP_FAILURE_SIGNAL] = "signal",
- [SWAP_FAILURE_CORE_DUMP] = "core-dump"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(swap_result, SwapResult);
-
-const UnitVTable swap_vtable = {
- .object_size = sizeof(Swap),
- .exec_context_offset = offsetof(Swap, exec_context),
- .cgroup_context_offset = offsetof(Swap, cgroup_context),
- .kill_context_offset = offsetof(Swap, kill_context),
- .exec_runtime_offset = offsetof(Swap, exec_runtime),
-
- .sections =
- "Unit\0"
- "Swap\0"
- "Install\0",
- .private_section = "Swap",
-
- .no_alias = true,
- .no_instances = true,
-
- .init = swap_init,
- .load = swap_load,
- .done = swap_done,
-
- .coldplug = swap_coldplug,
-
- .dump = swap_dump,
-
- .start = swap_start,
- .stop = swap_stop,
-
- .kill = swap_kill,
-
- .get_timeout = swap_get_timeout,
-
- .serialize = swap_serialize,
- .deserialize_item = swap_deserialize_item,
-
- .active_state = swap_active_state,
- .sub_state_to_string = swap_sub_state_to_string,
-
- .check_gc = swap_check_gc,
-
- .sigchld_event = swap_sigchld_event,
-
- .reset_failed = swap_reset_failed,
-
- .bus_interface = "org.freedesktop.systemd1.Swap",
- .bus_vtable = bus_swap_vtable,
- .bus_set_property = bus_swap_set_property,
- .bus_commit_properties = bus_swap_commit_properties,
-
- .following = swap_following,
- .following_set = swap_following_set,
-
- .enumerate = swap_enumerate,
- .shutdown = swap_shutdown,
- .supported = swap_supported,
-
- .status_message_formats = {
- .starting_stopping = {
- [0] = "Activating swap %s...",
- [1] = "Deactivating swap %s...",
- },
- .finished_start_job = {
- [JOB_DONE] = "Activated swap %s.",
- [JOB_FAILED] = "Failed to activate swap %s.",
- [JOB_DEPENDENCY] = "Dependency failed for %s.",
- [JOB_TIMEOUT] = "Timed out activating swap %s.",
- },
- .finished_stop_job = {
- [JOB_DONE] = "Deactivated swap %s.",
- [JOB_FAILED] = "Failed deactivating swap %s.",
- [JOB_TIMEOUT] = "Timed out deactivating swap %s.",
- },
- },
-};
diff --git a/src/core/swap.h b/src/core/swap.h
deleted file mode 100644
index 9136b9aba..000000000
--- a/src/core/swap.h
+++ /dev/null
@@ -1,130 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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/>.
-***/
-
-#include <libudev.h>
-
-typedef struct Swap Swap;
-
-
-typedef enum SwapState {
- SWAP_DEAD,
- SWAP_ACTIVATING, /* /sbin/swapon is running, but the swap not yet enabled. */
- SWAP_ACTIVATING_DONE, /* /sbin/swapon is running, and the swap is done. */
- SWAP_ACTIVE,
- SWAP_DEACTIVATING,
- SWAP_ACTIVATING_SIGTERM,
- SWAP_ACTIVATING_SIGKILL,
- SWAP_DEACTIVATING_SIGTERM,
- SWAP_DEACTIVATING_SIGKILL,
- SWAP_FAILED,
- _SWAP_STATE_MAX,
- _SWAP_STATE_INVALID = -1
-} SwapState;
-
-typedef enum SwapExecCommand {
- SWAP_EXEC_ACTIVATE,
- SWAP_EXEC_DEACTIVATE,
- _SWAP_EXEC_COMMAND_MAX,
- _SWAP_EXEC_COMMAND_INVALID = -1
-} SwapExecCommand;
-
-typedef enum SwapResult {
- SWAP_SUCCESS,
- SWAP_FAILURE_RESOURCES,
- SWAP_FAILURE_TIMEOUT,
- SWAP_FAILURE_EXIT_CODE,
- SWAP_FAILURE_SIGNAL,
- SWAP_FAILURE_CORE_DUMP,
- _SWAP_RESULT_MAX,
- _SWAP_RESULT_INVALID = -1
-} SwapResult;
-
-typedef struct SwapParameters {
- char *what;
- char *options;
- int priority;
-} SwapParameters;
-
-struct Swap {
- Unit meta;
-
- char *what;
-
- /* If the device has already shown up, this is the device
- * node, which might be different from what, due to
- * symlinks */
- char *devnode;
-
- SwapParameters parameters_proc_swaps;
- SwapParameters parameters_fragment;
-
- bool from_proc_swaps:1;
- bool from_fragment:1;
-
- /* Used while looking for swaps that vanished or got added
- * from/to /proc/swaps */
- bool is_active:1;
- bool just_activated:1;
-
- bool reset_cpu_usage:1;
-
- SwapResult result;
-
- usec_t timeout_usec;
-
- ExecCommand exec_command[_SWAP_EXEC_COMMAND_MAX];
- ExecContext exec_context;
- KillContext kill_context;
- CGroupContext cgroup_context;
-
- ExecRuntime *exec_runtime;
-
- SwapState state, deserialized_state;
-
- ExecCommand* control_command;
- SwapExecCommand control_command_id;
- pid_t control_pid;
-
- sd_event_source *timer_event_source;
-
- /* In order to be able to distinguish dependencies on
- different device nodes we might end up creating multiple
- devices for the same swap. We chain them up here. */
-
- LIST_FIELDS(struct Swap, same_devnode);
-};
-
-extern const UnitVTable swap_vtable;
-
-int swap_process_device_new(Manager *m, struct udev_device *dev);
-int swap_process_device_remove(Manager *m, struct udev_device *dev);
-
-const char* swap_state_to_string(SwapState i) _const_;
-SwapState swap_state_from_string(const char *s) _pure_;
-
-const char* swap_exec_command_to_string(SwapExecCommand i) _const_;
-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_;
diff --git a/src/core/system.conf b/src/core/system.conf
deleted file mode 100644
index 231609033..000000000
--- a/src/core/system.conf
+++ /dev/null
@@ -1,57 +0,0 @@
-# This file is part of systemd.
-#
-# 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.
-#
-# Entries in this file show the compile time defaults.
-# You can change settings by editing this file.
-# Defaults can be restored by simply deleting this file.
-#
-# See systemd-system.conf(5) for details.
-
-[Manager]
-#LogLevel=info
-#LogTarget=journal-or-kmsg
-#LogColor=yes
-#LogLocation=no
-#DumpCore=yes
-#CrashShell=no
-#ShowStatus=yes
-#CrashChVT=1
-#CPUAffinity=1 2
-#JoinControllers=cpu,cpuacct net_cls,net_prio
-#RuntimeWatchdogSec=0
-#ShutdownWatchdogSec=10min
-#CapabilityBoundingSet=
-#SystemCallArchitectures=
-#TimerSlackNSec=
-#DefaultTimerAccuracySec=1min
-#DefaultStandardOutput=journal
-#DefaultStandardError=inherit
-#DefaultTimeoutStartSec=90s
-#DefaultTimeoutStopSec=90s
-#DefaultRestartSec=100ms
-#DefaultStartLimitInterval=10s
-#DefaultStartLimitBurst=5
-#DefaultEnvironment=
-#DefaultCPUAccounting=no
-#DefaultBlockIOAccounting=no
-#DefaultMemoryAccounting=no
-#DefaultLimitCPU=
-#DefaultLimitFSIZE=
-#DefaultLimitDATA=
-#DefaultLimitSTACK=
-#DefaultLimitCORE=
-#DefaultLimitRSS=
-#DefaultLimitNOFILE=
-#DefaultLimitAS=
-#DefaultLimitNPROC=
-#DefaultLimitMEMLOCK=
-#DefaultLimitLOCKS=
-#DefaultLimitSIGPENDING=
-#DefaultLimitMSGQUEUE=
-#DefaultLimitNICE=
-#DefaultLimitRTPRIO=
-#DefaultLimitRTTIME=
diff --git a/src/core/systemd.pc.in b/src/core/systemd.pc.in
deleted file mode 100644
index d5b86bf65..000000000
--- a/src/core/systemd.pc.in
+++ /dev/null
@@ -1,35 +0,0 @@
-# This file is part of systemd.
-#
-# 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.
-
-prefix=@prefix@
-libdir=@libdir@
-systemdutildir=@rootlibexecdir@
-systemdsystemunitdir=@systemunitdir@
-systemdsystempresetdir=@systempresetdir@
-systemduserunitdir=@userunitdir@
-systemduserpresetdir=@userpresetdir@
-systemdsystemconfdir=@pkgsysconfdir@/system
-systemduserconfdir=@pkgsysconfdir@/user
-systemdsystemunitpath=${systemdsystemconfdir}:/etc/systemd/system:/run/systemd/system:/usr/local/lib/systemd/system:${systemdsystemunitdir}:/usr/lib/systemd/system:/lib/systemd/system
-systemduserunitpath=${systemduserconfdir}:/etc/systemd/user:/run/systemd/user:/usr/local/lib/systemd/user:/usr/local/share/systemd/user:${systemduserunitdir}:/usr/lib/systemd/user:/usr/share/systemd/user
-systemdsystemgeneratordir=@systemgeneratordir@
-systemdusergeneratordir=@usergeneratordir@
-systemdsleepdir=@systemsleepdir@
-systemdshutdowndir=@systemshutdowndir@
-tmpfilesdir=@tmpfilesdir@
-sysusersdir=@sysusersdir@
-sysctldir=@sysctldir@
-binfmtdir=@binfmtdir@
-modulesloaddir=@modulesloaddir@
-catalogdir=@catalogdir@
-systemuidmax=@systemuidmax@
-systemgidmax=@systemgidmax@
-
-Name: systemd
-Description: systemd System and Service Manager
-URL: @PACKAGE_URL@
-Version: @PACKAGE_VERSION@
diff --git a/src/core/target.c b/src/core/target.c
deleted file mode 100644
index 5f6440247..000000000
--- a/src/core/target.c
+++ /dev/null
@@ -1,236 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 "target.h"
-#include "log.h"
-#include "dbus-target.h"
-#include "special.h"
-#include "unit-name.h"
-
-static const UnitActiveState state_translation_table[_TARGET_STATE_MAX] = {
- [TARGET_DEAD] = UNIT_INACTIVE,
- [TARGET_ACTIVE] = UNIT_ACTIVE
-};
-
-static void target_set_state(Target *t, TargetState state) {
- TargetState old_state;
- assert(t);
-
- old_state = t->state;
- t->state = state;
-
- if (state != old_state)
- log_debug("%s changed %s -> %s",
- UNIT(t)->id,
- 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);
-}
-
-static int target_add_default_dependencies(Target *t) {
-
- static const UnitDependency deps[] = {
- UNIT_REQUIRES,
- UNIT_REQUIRES_OVERRIDABLE,
- UNIT_REQUISITE,
- UNIT_REQUISITE_OVERRIDABLE,
- UNIT_WANTS,
- UNIT_BINDS_TO,
- UNIT_PART_OF
- };
-
- Iterator i;
- Unit *other;
- int r;
- unsigned k;
-
- assert(t);
-
- /* Imply ordering for requirement dependencies on target
- * units. Note that when the user created a contradicting
- * ordering manually we won't add anything in here to make
- * sure we don't create a loop. */
-
- for (k = 0; k < ELEMENTSOF(deps); k++)
- SET_FOREACH(other, UNIT(t)->dependencies[deps[k]], i) {
- r = unit_add_default_target_dependency(other, UNIT(t));
- if (r < 0)
- return r;
- }
-
- /* Make sure targets are unloaded on shutdown */
- return unit_add_dependency_by_name(UNIT(t), UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
-}
-
-static int target_load(Unit *u) {
- Target *t = TARGET(u);
- int r;
-
- assert(t);
-
- r = unit_load_fragment_and_dropin(u);
- if (r < 0)
- return r;
-
- /* This is a new unit? Then let's add in some extras */
- if (u->load_state == UNIT_LOADED && u->default_dependencies) {
- r = target_add_default_dependencies(t);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-static int target_coldplug(Unit *u, Hashmap *deferred_work) {
- Target *t = TARGET(u);
-
- assert(t);
- assert(t->state == TARGET_DEAD);
-
- if (t->deserialized_state != t->state)
- target_set_state(t, t->deserialized_state);
-
- return 0;
-}
-
-static void target_dump(Unit *u, FILE *f, const char *prefix) {
- Target *t = TARGET(u);
-
- assert(t);
- assert(f);
-
- fprintf(f,
- "%sTarget State: %s\n",
- prefix, target_state_to_string(t->state));
-}
-
-static int target_start(Unit *u) {
- Target *t = TARGET(u);
-
- assert(t);
- assert(t->state == TARGET_DEAD);
-
- target_set_state(t, TARGET_ACTIVE);
- return 1;
-}
-
-static int target_stop(Unit *u) {
- Target *t = TARGET(u);
-
- assert(t);
- assert(t->state == TARGET_ACTIVE);
-
- target_set_state(t, TARGET_DEAD);
- return 1;
-}
-
-static int target_serialize(Unit *u, FILE *f, FDSet *fds) {
- Target *s = TARGET(u);
-
- assert(s);
- assert(f);
- assert(fds);
-
- unit_serialize_item(u, f, "state", target_state_to_string(s->state));
- return 0;
-}
-
-static int target_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Target *s = TARGET(u);
-
- assert(u);
- assert(key);
- assert(value);
- assert(fds);
-
- if (streq(key, "state")) {
- TargetState state;
-
- state = target_state_from_string(value);
- if (state < 0)
- log_debug("Failed to parse state value %s", value);
- else
- s->deserialized_state = state;
-
- } else
- log_debug("Unknown serialization key '%s'", key);
-
- return 0;
-}
-
-_pure_ static UnitActiveState target_active_state(Unit *u) {
- assert(u);
-
- return state_translation_table[TARGET(u)->state];
-}
-
-_pure_ static const char *target_sub_state_to_string(Unit *u) {
- assert(u);
-
- return target_state_to_string(TARGET(u)->state);
-}
-
-static const char* const target_state_table[_TARGET_STATE_MAX] = {
- [TARGET_DEAD] = "dead",
- [TARGET_ACTIVE] = "active"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(target_state, TargetState);
-
-const UnitVTable target_vtable = {
- .object_size = sizeof(Target),
-
- .sections =
- "Unit\0"
- "Target\0"
- "Install\0",
-
- .load = target_load,
- .coldplug = target_coldplug,
-
- .dump = target_dump,
-
- .start = target_start,
- .stop = target_stop,
-
- .serialize = target_serialize,
- .deserialize_item = target_deserialize_item,
-
- .active_state = target_active_state,
- .sub_state_to_string = target_sub_state_to_string,
-
- .bus_interface = "org.freedesktop.systemd1.Target",
- .bus_vtable = bus_target_vtable,
-
- .status_message_formats = {
- .finished_start_job = {
- [JOB_DONE] = "Reached target %s.",
- [JOB_DEPENDENCY] = "Dependency failed for %s.",
- },
- .finished_stop_job = {
- [JOB_DONE] = "Stopped target %s.",
- },
- },
-};
diff --git a/src/core/target.h b/src/core/target.h
deleted file mode 100644
index 0a25ef469..000000000
--- a/src/core/target.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 Target Target;
-
-
-typedef enum TargetState {
- TARGET_DEAD,
- TARGET_ACTIVE,
- _TARGET_STATE_MAX,
- _TARGET_STATE_INVALID = -1
-} TargetState;
-
-struct Target {
- Unit meta;
-
- TargetState state, deserialized_state;
-};
-
-extern const UnitVTable target_vtable;
-
-const char* target_state_to_string(TargetState i) _const_;
-TargetState target_state_from_string(const char *s) _pure_;
diff --git a/src/core/timer.c b/src/core/timer.c
deleted file mode 100644
index 79a754055..000000000
--- a/src/core/timer.c
+++ /dev/null
@@ -1,785 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 "unit.h"
-#include "unit-name.h"
-#include "timer.h"
-#include "dbus-timer.h"
-#include "special.h"
-#include "bus-util.h"
-#include "bus-error.h"
-
-static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = {
- [TIMER_DEAD] = UNIT_INACTIVE,
- [TIMER_WAITING] = UNIT_ACTIVE,
- [TIMER_RUNNING] = UNIT_ACTIVE,
- [TIMER_ELAPSED] = UNIT_ACTIVE,
- [TIMER_FAILED] = UNIT_FAILED
-};
-
-static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata);
-
-static void timer_init(Unit *u) {
- Timer *t = TIMER(u);
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
-
- t->next_elapse_monotonic_or_boottime = USEC_INFINITY;
- t->next_elapse_realtime = USEC_INFINITY;
- t->accuracy_usec = u->manager->default_timer_accuracy_usec;
-}
-
-void timer_free_values(Timer *t) {
- TimerValue *v;
-
- assert(t);
-
- while ((v = t->values)) {
- LIST_REMOVE(value, t->values, v);
-
- if (v->calendar_spec)
- calendar_spec_free(v->calendar_spec);
-
- free(v);
- }
-}
-
-static void timer_done(Unit *u) {
- Timer *t = TIMER(u);
-
- assert(t);
-
- timer_free_values(t);
-
- t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source);
- t->realtime_event_source = sd_event_source_unref(t->realtime_event_source);
-
- free(t->stamp_path);
-}
-
-static int timer_verify(Timer *t) {
- assert(t);
-
- if (UNIT(t)->load_state != UNIT_LOADED)
- return 0;
-
- if (!t->values) {
- log_unit_error(UNIT(t)->id, "%s lacks value setting. Refusing.", UNIT(t)->id);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int timer_add_default_dependencies(Timer *t) {
- int r;
- TimerValue *v;
-
- assert(t);
-
- r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, NULL, true);
- if (r < 0)
- return r;
-
- if (UNIT(t)->manager->running_as == SYSTEMD_SYSTEM) {
- r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
- if (r < 0)
- return r;
-
- LIST_FOREACH(value, v, t->values) {
- if (v->base == TIMER_CALENDAR) {
- r = unit_add_dependency_by_name(UNIT(t), UNIT_AFTER, SPECIAL_TIME_SYNC_TARGET, NULL, true);
- if (r < 0)
- return r;
- break;
- }
- }
- }
-
- return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
-}
-
-static int timer_setup_persistent(Timer *t) {
- int r;
-
- assert(t);
-
- if (!t->persistent)
- return 0;
-
- if (UNIT(t)->manager->running_as == SYSTEMD_SYSTEM) {
-
- r = unit_require_mounts_for(UNIT(t), "/var/lib/systemd/timers");
- if (r < 0)
- return r;
-
- t->stamp_path = strappend("/var/lib/systemd/timers/stamp-", UNIT(t)->id);
- } else {
- const char *e;
-
- e = getenv("XDG_DATA_HOME");
- if (e)
- t->stamp_path = strjoin(e, "/systemd/timers/stamp-", UNIT(t)->id, NULL);
- else {
-
- _cleanup_free_ char *h = NULL;
-
- r = get_home_dir(&h);
- if (r < 0)
- return log_error_errno(r, "Failed to determine home directory: %m");
-
- t->stamp_path = strjoin(h, "/.local/share/systemd/timers/stamp-", UNIT(t)->id, NULL);
- }
- }
-
- if (!t->stamp_path)
- return log_oom();
-
- return 0;
-}
-
-static int timer_load(Unit *u) {
- Timer *t = TIMER(u);
- int r;
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
-
- r = unit_load_fragment_and_dropin(u);
- if (r < 0)
- return r;
-
- if (u->load_state == UNIT_LOADED) {
-
- if (set_isempty(u->dependencies[UNIT_TRIGGERS])) {
- Unit *x;
-
- r = unit_load_related_unit(u, ".service", &x);
- if (r < 0)
- return r;
-
- r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, x, true);
- if (r < 0)
- return r;
- }
-
- r = timer_setup_persistent(t);
- if (r < 0)
- return r;
-
- if (u->default_dependencies) {
- r = timer_add_default_dependencies(t);
- if (r < 0)
- return r;
- }
- }
-
- return timer_verify(t);
-}
-
-static void timer_dump(Unit *u, FILE *f, const char *prefix) {
- char buf[FORMAT_TIMESPAN_MAX];
- Timer *t = TIMER(u);
- Unit *trigger;
- TimerValue *v;
-
- trigger = UNIT_TRIGGER(u);
-
- fprintf(f,
- "%sTimer State: %s\n"
- "%sResult: %s\n"
- "%sUnit: %s\n"
- "%sPersistent: %s\n"
- "%sWakeSystem: %s\n"
- "%sAccuracy: %s\n",
- prefix, timer_state_to_string(t->state),
- prefix, timer_result_to_string(t->result),
- prefix, trigger ? trigger->id : "n/a",
- prefix, yes_no(t->persistent),
- prefix, yes_no(t->wake_system),
- prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1));
-
- LIST_FOREACH(value, v, t->values) {
-
- if (v->base == TIMER_CALENDAR) {
- _cleanup_free_ char *p = NULL;
-
- calendar_spec_to_string(v->calendar_spec, &p);
-
- fprintf(f,
- "%s%s: %s\n",
- prefix,
- timer_base_to_string(v->base),
- strna(p));
- } else {
- char timespan1[FORMAT_TIMESPAN_MAX];
-
- fprintf(f,
- "%s%s: %s\n",
- prefix,
- timer_base_to_string(v->base),
- format_timespan(timespan1, sizeof(timespan1), v->value, 0));
- }
- }
-}
-
-static void timer_set_state(Timer *t, TimerState state) {
- TimerState old_state;
- assert(t);
-
- old_state = t->state;
- t->state = state;
-
- if (state != TIMER_WAITING) {
- t->monotonic_event_source = sd_event_source_unref(t->monotonic_event_source);
- t->realtime_event_source = sd_event_source_unref(t->realtime_event_source);
- }
-
- if (state != old_state)
- log_unit_debug(UNIT(t)->id,
- "%s changed %s -> %s", UNIT(t)->id,
- 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);
-}
-
-static void timer_enter_waiting(Timer *t, bool initial);
-
-static int timer_enter_waiting_coldplug(Unit *u) {
- timer_enter_waiting(TIMER(u), false);
- return 0;
-}
-
-static int timer_coldplug(Unit *u, Hashmap *deferred_work) {
- Timer *t = TIMER(u);
-
- assert(t);
- assert(t->state == TIMER_DEAD);
-
- if (t->deserialized_state != t->state) {
-
- if (t->deserialized_state == TIMER_WAITING) {
- hashmap_put(deferred_work, u, &timer_enter_waiting_coldplug);
- timer_set_state(t, TIMER_WAITING);
- } else
- timer_set_state(t, t->deserialized_state);
- }
-
- return 0;
-}
-
-static void timer_enter_dead(Timer *t, TimerResult f) {
- assert(t);
-
- if (f != TIMER_SUCCESS)
- t->result = f;
-
- timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
-}
-
-static usec_t monotonic_to_boottime(usec_t t) {
- usec_t a, b;
-
- if (t <= 0)
- return 0;
-
- a = now(CLOCK_BOOTTIME);
- b = now(CLOCK_MONOTONIC);
-
- if (t + a > b)
- return t + a - b;
- else
- return 0;
-}
-
-static void timer_enter_waiting(Timer *t, bool initial) {
- bool found_monotonic = false, found_realtime = false;
- usec_t ts_realtime, ts_monotonic;
- usec_t base = 0;
- TimerValue *v;
- int r;
-
- /* If we shall wake the system we use the boottime clock
- * rather than the monotonic clock. */
-
- ts_realtime = now(CLOCK_REALTIME);
- ts_monotonic = now(t->wake_system ? CLOCK_BOOTTIME : CLOCK_MONOTONIC);
- t->next_elapse_monotonic_or_boottime = t->next_elapse_realtime = 0;
-
- LIST_FOREACH(value, v, t->values) {
-
- if (v->disabled)
- continue;
-
- if (v->base == TIMER_CALENDAR) {
- usec_t b;
-
- /* If we know the last time this was
- * triggered, schedule the job based relative
- * to that. If we don't just start from
- * now. */
-
- b = t->last_trigger.realtime > 0 ? t->last_trigger.realtime : ts_realtime;
-
- r = calendar_spec_next_usec(v->calendar_spec, b, &v->next_elapse);
- if (r < 0)
- continue;
-
- if (!found_realtime)
- t->next_elapse_realtime = v->next_elapse;
- else
- t->next_elapse_realtime = MIN(t->next_elapse_realtime, v->next_elapse);
-
- found_realtime = true;
-
- } else {
- switch (v->base) {
-
- case TIMER_ACTIVE:
- if (state_translation_table[t->state] == UNIT_ACTIVE)
- base = UNIT(t)->inactive_exit_timestamp.monotonic;
- else
- base = ts_monotonic;
- break;
-
- case TIMER_BOOT:
- /* CLOCK_MONOTONIC equals the uptime on Linux */
- base = 0;
- break;
-
- case TIMER_STARTUP:
- base = UNIT(t)->manager->userspace_timestamp.monotonic;
- break;
-
- case TIMER_UNIT_ACTIVE:
-
- base = UNIT_TRIGGER(UNIT(t))->inactive_exit_timestamp.monotonic;
-
- if (base <= 0)
- base = t->last_trigger.monotonic;
-
- if (base <= 0)
- continue;
-
- break;
-
- case TIMER_UNIT_INACTIVE:
-
- base = UNIT_TRIGGER(UNIT(t))->inactive_enter_timestamp.monotonic;
-
- if (base <= 0)
- base = t->last_trigger.monotonic;
-
- if (base <= 0)
- continue;
-
- break;
-
- default:
- assert_not_reached("Unknown timer base");
- }
-
- if (t->wake_system)
- base = monotonic_to_boottime(base);
-
- v->next_elapse = base + v->value;
-
- if (!initial && v->next_elapse < ts_monotonic && IN_SET(v->base, TIMER_ACTIVE, TIMER_BOOT, TIMER_STARTUP)) {
- /* This is a one time trigger, disable it now */
- v->disabled = true;
- continue;
- }
-
- if (!found_monotonic)
- t->next_elapse_monotonic_or_boottime = v->next_elapse;
- else
- t->next_elapse_monotonic_or_boottime = MIN(t->next_elapse_monotonic_or_boottime, v->next_elapse);
-
- found_monotonic = true;
- }
- }
-
- if (!found_monotonic && !found_realtime) {
- log_unit_debug(UNIT(t)->id, "%s: Timer is elapsed.", UNIT(t)->id);
- timer_set_state(t, TIMER_ELAPSED);
- return;
- }
-
- if (found_monotonic) {
- char buf[FORMAT_TIMESPAN_MAX];
-
- log_unit_debug(UNIT(t)->id, "%s: Monotonic timer elapses in %s.",
- UNIT(t)->id,
- format_timespan(buf, sizeof(buf), t->next_elapse_monotonic_or_boottime > ts_monotonic ? t->next_elapse_monotonic_or_boottime - ts_monotonic : 0, 0));
-
- if (t->monotonic_event_source) {
- r = sd_event_source_set_time(t->monotonic_event_source, t->next_elapse_monotonic_or_boottime);
- if (r < 0)
- goto fail;
-
- r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_ONESHOT);
- } else
- r = sd_event_add_time(
- UNIT(t)->manager->event,
- &t->monotonic_event_source,
- t->wake_system ? CLOCK_BOOTTIME_ALARM : CLOCK_MONOTONIC,
- t->next_elapse_monotonic_or_boottime, t->accuracy_usec,
- timer_dispatch, t);
- if (r < 0)
- goto fail;
-
- } else if (t->monotonic_event_source) {
-
- r = sd_event_source_set_enabled(t->monotonic_event_source, SD_EVENT_OFF);
- if (r < 0)
- goto fail;
- }
-
- if (found_realtime) {
- char buf[FORMAT_TIMESTAMP_MAX];
- log_unit_debug(UNIT(t)->id, "%s: Realtime timer elapses at %s.", UNIT(t)->id, format_timestamp(buf, sizeof(buf), t->next_elapse_realtime));
-
- if (t->realtime_event_source) {
- r = sd_event_source_set_time(t->realtime_event_source, t->next_elapse_realtime);
- if (r < 0)
- goto fail;
-
- r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_ONESHOT);
- } else
- r = sd_event_add_time(
- UNIT(t)->manager->event,
- &t->realtime_event_source,
- t->wake_system ? CLOCK_REALTIME_ALARM : CLOCK_REALTIME,
- t->next_elapse_realtime, t->accuracy_usec,
- timer_dispatch, t);
- if (r < 0)
- goto fail;
-
- } else if (t->realtime_event_source) {
-
- r = sd_event_source_set_enabled(t->realtime_event_source, SD_EVENT_OFF);
- if (r < 0)
- goto fail;
- }
-
- timer_set_state(t, TIMER_WAITING);
- return;
-
-fail:
- log_unit_warning_errno(UNIT(t)->id, r, "%s failed to enter waiting state: %m", UNIT(t)->id);
- timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
-}
-
-static void timer_enter_running(Timer *t) {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
- int r;
-
- assert(t);
-
- /* Don't start job if we are supposed to go down */
- if (unit_stop_pending(UNIT(t)))
- return;
-
- r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_TRIGGER(UNIT(t)),
- JOB_REPLACE, true, &error, NULL);
- if (r < 0)
- goto fail;
-
- dual_timestamp_get(&t->last_trigger);
-
- if (t->stamp_path)
- touch_file(t->stamp_path, true, t->last_trigger.realtime, UID_INVALID, GID_INVALID, 0);
-
- timer_set_state(t, TIMER_RUNNING);
- return;
-
-fail:
- log_unit_warning(UNIT(t)->id,
- "%s failed to queue unit startup job: %s",
- UNIT(t)->id, bus_error_message(&error, r));
- timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
-}
-
-static int timer_start(Unit *u) {
- Timer *t = TIMER(u);
- TimerValue *v;
-
- assert(t);
- assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
-
- if (UNIT_TRIGGER(u)->load_state != UNIT_LOADED)
- return -ENOENT;
-
- t->last_trigger = DUAL_TIMESTAMP_NULL;
-
- /* Reenable all timers that depend on unit activation time */
- LIST_FOREACH(value, v, t->values)
- if (v->base == TIMER_ACTIVE)
- v->disabled = false;
-
- if (t->stamp_path) {
- struct stat st;
-
- if (stat(t->stamp_path, &st) >= 0)
- t->last_trigger.realtime = timespec_load(&st.st_atim);
- else if (errno == ENOENT)
- /* The timer has never run before,
- * make sure a stamp file exists.
- */
- touch_file(t->stamp_path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0);
- }
-
- t->result = TIMER_SUCCESS;
- timer_enter_waiting(t, true);
- return 1;
-}
-
-static int timer_stop(Unit *u) {
- Timer *t = TIMER(u);
-
- assert(t);
- assert(t->state == TIMER_WAITING || t->state == TIMER_RUNNING || t->state == TIMER_ELAPSED);
-
- timer_enter_dead(t, TIMER_SUCCESS);
- return 1;
-}
-
-static int timer_serialize(Unit *u, FILE *f, FDSet *fds) {
- Timer *t = TIMER(u);
-
- assert(u);
- assert(f);
- assert(fds);
-
- unit_serialize_item(u, f, "state", timer_state_to_string(t->state));
- unit_serialize_item(u, f, "result", timer_result_to_string(t->result));
-
- if (t->last_trigger.realtime > 0)
- unit_serialize_item_format(u, f, "last-trigger-realtime", "%" PRIu64, t->last_trigger.realtime);
-
- if (t->last_trigger.monotonic > 0)
- unit_serialize_item_format(u, f, "last-trigger-monotonic", "%" PRIu64, t->last_trigger.monotonic);
-
- return 0;
-}
-
-static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Timer *t = TIMER(u);
- int r;
-
- assert(u);
- assert(key);
- assert(value);
- assert(fds);
-
- if (streq(key, "state")) {
- TimerState state;
-
- state = timer_state_from_string(value);
- if (state < 0)
- log_unit_debug(u->id, "Failed to parse state value %s", value);
- else
- t->deserialized_state = state;
- } else if (streq(key, "result")) {
- TimerResult f;
-
- f = timer_result_from_string(value);
- if (f < 0)
- log_unit_debug(u->id, "Failed to parse result value %s", value);
- else if (f != TIMER_SUCCESS)
- t->result = f;
- } else if (streq(key, "last-trigger-realtime")) {
-
- r = safe_atou64(value, &t->last_trigger.realtime);
- if (r < 0)
- log_unit_debug(u->id, "Failed to parse last-trigger-realtime value %s", value);
-
- } else if (streq(key, "last-trigger-monotonic")) {
-
- r = safe_atou64(value, &t->last_trigger.monotonic);
- if (r < 0)
- log_unit_debug(u->id, "Failed to parse last-trigger-monotonic value %s", value);
-
- } else
- log_unit_debug(u->id, "Unknown serialization key '%s'", key);
-
- return 0;
-}
-
-_pure_ static UnitActiveState timer_active_state(Unit *u) {
- assert(u);
-
- return state_translation_table[TIMER(u)->state];
-}
-
-_pure_ static const char *timer_sub_state_to_string(Unit *u) {
- assert(u);
-
- return timer_state_to_string(TIMER(u)->state);
-}
-
-static int timer_dispatch(sd_event_source *s, uint64_t usec, void *userdata) {
- Timer *t = TIMER(userdata);
-
- assert(t);
-
- if (t->state != TIMER_WAITING)
- return 0;
-
- log_unit_debug(UNIT(t)->id, "Timer elapsed on %s", UNIT(t)->id);
- timer_enter_running(t);
- return 0;
-}
-
-static void timer_trigger_notify(Unit *u, Unit *other) {
- Timer *t = TIMER(u);
- TimerValue *v;
-
- assert(u);
- assert(other);
-
- if (other->load_state != UNIT_LOADED)
- return;
-
- /* Reenable all timers that depend on unit state */
- LIST_FOREACH(value, v, t->values)
- if (v->base == TIMER_UNIT_ACTIVE ||
- v->base == TIMER_UNIT_INACTIVE)
- v->disabled = false;
-
- switch (t->state) {
-
- case TIMER_WAITING:
- case TIMER_ELAPSED:
-
- /* Recalculate sleep time */
- timer_enter_waiting(t, false);
- break;
-
- case TIMER_RUNNING:
-
- if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other))) {
- log_unit_debug(UNIT(t)->id, "%s got notified about unit deactivation.", UNIT(t)->id);
- timer_enter_waiting(t, false);
- }
- break;
-
- case TIMER_DEAD:
- case TIMER_FAILED:
- break;
-
- default:
- assert_not_reached("Unknown timer state");
- }
-}
-
-static void timer_reset_failed(Unit *u) {
- Timer *t = TIMER(u);
-
- assert(t);
-
- if (t->state == TIMER_FAILED)
- timer_set_state(t, TIMER_DEAD);
-
- t->result = TIMER_SUCCESS;
-}
-
-static void timer_time_change(Unit *u) {
- Timer *t = TIMER(u);
-
- assert(u);
-
- if (t->state != TIMER_WAITING)
- return;
-
- log_unit_debug(u->id, "%s: time change, recalculating next elapse.", u->id);
- timer_enter_waiting(t, false);
-}
-
-static const char* const timer_state_table[_TIMER_STATE_MAX] = {
- [TIMER_DEAD] = "dead",
- [TIMER_WAITING] = "waiting",
- [TIMER_RUNNING] = "running",
- [TIMER_ELAPSED] = "elapsed",
- [TIMER_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState);
-
-static const char* const timer_base_table[_TIMER_BASE_MAX] = {
- [TIMER_ACTIVE] = "OnActiveSec",
- [TIMER_BOOT] = "OnBootSec",
- [TIMER_STARTUP] = "OnStartupSec",
- [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec",
- [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec",
- [TIMER_CALENDAR] = "OnCalendar"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(timer_base, TimerBase);
-
-static const char* const timer_result_table[_TIMER_RESULT_MAX] = {
- [TIMER_SUCCESS] = "success",
- [TIMER_FAILURE_RESOURCES] = "resources"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(timer_result, TimerResult);
-
-const UnitVTable timer_vtable = {
- .object_size = sizeof(Timer),
-
- .sections =
- "Unit\0"
- "Timer\0"
- "Install\0",
- .private_section = "Timer",
-
- .init = timer_init,
- .done = timer_done,
- .load = timer_load,
-
- .coldplug = timer_coldplug,
-
- .dump = timer_dump,
-
- .start = timer_start,
- .stop = timer_stop,
-
- .serialize = timer_serialize,
- .deserialize_item = timer_deserialize_item,
-
- .active_state = timer_active_state,
- .sub_state_to_string = timer_sub_state_to_string,
-
- .trigger_notify = timer_trigger_notify,
-
- .reset_failed = timer_reset_failed,
- .time_change = timer_time_change,
-
- .bus_interface = "org.freedesktop.systemd1.Timer",
- .bus_vtable = bus_timer_vtable,
- .bus_set_property = bus_timer_set_property,
-
- .can_transient = true,
-};
diff --git a/src/core/timer.h b/src/core/timer.h
deleted file mode 100644
index 9d919e4d3..000000000
--- a/src/core/timer.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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"
-
-typedef enum TimerState {
- TIMER_DEAD,
- TIMER_WAITING,
- TIMER_RUNNING,
- TIMER_ELAPSED,
- TIMER_FAILED,
- _TIMER_STATE_MAX,
- _TIMER_STATE_INVALID = -1
-} TimerState;
-
-typedef enum TimerBase {
- TIMER_ACTIVE,
- TIMER_BOOT,
- TIMER_STARTUP,
- TIMER_UNIT_ACTIVE,
- TIMER_UNIT_INACTIVE,
- TIMER_CALENDAR,
- _TIMER_BASE_MAX,
- _TIMER_BASE_INVALID = -1
-} TimerBase;
-
-typedef struct TimerValue {
- TimerBase base;
- bool disabled;
-
- usec_t value; /* only for monotonic events */
- CalendarSpec *calendar_spec; /* only for calendar events */
- usec_t next_elapse;
-
- LIST_FIELDS(struct TimerValue, value);
-} TimerValue;
-
-typedef enum TimerResult {
- TIMER_SUCCESS,
- TIMER_FAILURE_RESOURCES,
- _TIMER_RESULT_MAX,
- _TIMER_RESULT_INVALID = -1
-} TimerResult;
-
-struct Timer {
- Unit meta;
-
- usec_t accuracy_usec;
-
- LIST_HEAD(TimerValue, values);
- usec_t next_elapse_realtime;
- usec_t next_elapse_monotonic_or_boottime;
- dual_timestamp last_trigger;
-
- TimerState state, deserialized_state;
-
- sd_event_source *monotonic_event_source;
- sd_event_source *realtime_event_source;
-
- TimerResult result;
-
- bool persistent;
- bool wake_system;
-
- char *stamp_path;
-};
-
-void timer_free_values(Timer *t);
-
-extern const UnitVTable timer_vtable;
-
-const char *timer_state_to_string(TimerState i) _const_;
-TimerState timer_state_from_string(const char *s) _pure_;
-
-const char *timer_base_to_string(TimerBase i) _const_;
-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_;
diff --git a/src/core/transaction.c b/src/core/transaction.c
deleted file mode 100644
index 64c2af5a1..000000000
--- a/src/core/transaction.c
+++ /dev/null
@@ -1,1145 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 <unistd.h>
-#include <fcntl.h>
-
-#include "bus-common-errors.h"
-#include "bus-error.h"
-#include "transaction.h"
-
-static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies);
-
-static void transaction_delete_job(Transaction *tr, Job *j, bool delete_dependencies) {
- assert(tr);
- assert(j);
-
- /* Deletes one job from the transaction */
-
- transaction_unlink_job(tr, j, delete_dependencies);
-
- job_free(j);
-}
-
-static void transaction_delete_unit(Transaction *tr, Unit *u) {
- Job *j;
-
- /* Deletes all jobs associated with a certain unit from the
- * transaction */
-
- while ((j = hashmap_get(tr->jobs, u)))
- transaction_delete_job(tr, j, true);
-}
-
-void transaction_abort(Transaction *tr) {
- Job *j;
-
- assert(tr);
-
- while ((j = hashmap_first(tr->jobs)))
- transaction_delete_job(tr, j, false);
-
- assert(hashmap_isempty(tr->jobs));
-}
-
-static void transaction_find_jobs_that_matter_to_anchor(Job *j, unsigned generation) {
- JobDependency *l;
-
- /* A recursive sweep through the graph that marks all units
- * that matter to the anchor job, i.e. are directly or
- * indirectly a dependency of the anchor job via paths that
- * are fully marked as mattering. */
-
- j->matters_to_anchor = true;
- j->generation = generation;
-
- LIST_FOREACH(subject, l, j->subject_list) {
-
- /* This link does not matter */
- if (!l->matters)
- continue;
-
- /* This unit has already been marked */
- if (l->object->generation == generation)
- continue;
-
- transaction_find_jobs_that_matter_to_anchor(l->object, generation);
- }
-}
-
-static void transaction_merge_and_delete_job(Transaction *tr, Job *j, Job *other, JobType t) {
- JobDependency *l, *last;
-
- assert(j);
- assert(other);
- assert(j->unit == other->unit);
- assert(!j->installed);
-
- /* Merges 'other' into 'j' and then deletes 'other'. */
-
- j->type = t;
- j->state = JOB_WAITING;
- j->override = j->override || other->override;
- j->irreversible = j->irreversible || other->irreversible;
-
- j->matters_to_anchor = j->matters_to_anchor || other->matters_to_anchor;
-
- /* Patch us in as new owner of the JobDependency objects */
- last = NULL;
- LIST_FOREACH(subject, l, other->subject_list) {
- assert(l->subject == other);
- l->subject = j;
- last = l;
- }
-
- /* Merge both lists */
- if (last) {
- last->subject_next = j->subject_list;
- if (j->subject_list)
- j->subject_list->subject_prev = last;
- j->subject_list = other->subject_list;
- }
-
- /* Patch us in as new owner of the JobDependency objects */
- last = NULL;
- LIST_FOREACH(object, l, other->object_list) {
- assert(l->object == other);
- l->object = j;
- last = l;
- }
-
- /* Merge both lists */
- if (last) {
- last->object_next = j->object_list;
- if (j->object_list)
- j->object_list->object_prev = last;
- j->object_list = other->object_list;
- }
-
- /* Kill the other job */
- other->subject_list = NULL;
- other->object_list = NULL;
- transaction_delete_job(tr, other, true);
-}
-
-_pure_ static bool job_is_conflicted_by(Job *j) {
- JobDependency *l;
-
- assert(j);
-
- /* Returns true if this job is pulled in by a least one
- * ConflictedBy dependency. */
-
- LIST_FOREACH(object, l, j->object_list)
- if (l->conflicts)
- return true;
-
- return false;
-}
-
-static int delete_one_unmergeable_job(Transaction *tr, Job *j) {
- Job *k;
-
- assert(j);
-
- /* Tries to delete one item in the linked list
- * j->transaction_next->transaction_next->... that conflicts
- * with another one, in an attempt to make an inconsistent
- * transaction work. */
-
- /* We rely here on the fact that if a merged with b does not
- * merge with c, either a or b merge with c neither */
- LIST_FOREACH(transaction, j, j)
- LIST_FOREACH(transaction, k, j->transaction_next) {
- Job *d;
-
- /* Is this one mergeable? Then skip it */
- if (job_type_is_mergeable(j->type, k->type))
- continue;
-
- /* Ok, we found two that conflict, let's see if we can
- * drop one of them */
- if (!j->matters_to_anchor && !k->matters_to_anchor) {
-
- /* Both jobs don't matter, so let's
- * find the one that is smarter to
- * remove. Let's think positive and
- * rather remove stops then starts --
- * except if something is being
- * stopped because it is conflicted by
- * another unit in which case we
- * rather remove the start. */
-
- log_unit_debug(j->unit->id,
- "Looking at job %s/%s conflicted_by=%s",
- j->unit->id, job_type_to_string(j->type),
- yes_no(j->type == JOB_STOP && job_is_conflicted_by(j)));
- log_unit_debug(k->unit->id,
- "Looking at job %s/%s conflicted_by=%s",
- k->unit->id, job_type_to_string(k->type),
- yes_no(k->type == JOB_STOP && job_is_conflicted_by(k)));
-
- if (j->type == JOB_STOP) {
-
- if (job_is_conflicted_by(j))
- d = k;
- else
- d = j;
-
- } else if (k->type == JOB_STOP) {
-
- if (job_is_conflicted_by(k))
- d = j;
- else
- d = k;
- } else
- d = j;
-
- } else if (!j->matters_to_anchor)
- d = j;
- else if (!k->matters_to_anchor)
- d = k;
- else
- return -ENOEXEC;
-
- /* Ok, we can drop one, so let's do so. */
- log_unit_debug(d->unit->id,
- "Fixing conflicting jobs %s/%s,%s/%s by deleting job %s/%s",
- j->unit->id, job_type_to_string(j->type),
- k->unit->id, job_type_to_string(k->type),
- d->unit->id, job_type_to_string(d->type));
- transaction_delete_job(tr, d, true);
- return 0;
- }
-
- return -EINVAL;
-}
-
-static int transaction_merge_jobs(Transaction *tr, sd_bus_error *e) {
- Job *j;
- Iterator i;
- int r;
-
- assert(tr);
-
- /* First step, check whether any of the jobs for one specific
- * task conflict. If so, try to drop one of them. */
- HASHMAP_FOREACH(j, tr->jobs, i) {
- JobType t;
- Job *k;
-
- t = j->type;
- LIST_FOREACH(transaction, k, j->transaction_next) {
- if (job_type_merge_and_collapse(&t, k->type, j->unit) >= 0)
- continue;
-
- /* OK, we could not merge all jobs for this
- * action. Let's see if we can get rid of one
- * of them */
-
- r = delete_one_unmergeable_job(tr, j);
- if (r >= 0)
- /* Ok, we managed to drop one, now
- * let's ask our callers to call us
- * again after garbage collecting */
- return -EAGAIN;
-
- /* We couldn't merge anything. Failure */
- return sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_JOBS_CONFLICTING,
- "Transaction contains conflicting jobs '%s' and '%s' for %s. "
- "Probably contradicting requirement dependencies configured.",
- job_type_to_string(t),
- job_type_to_string(k->type),
- k->unit->id);
- }
- }
-
- /* Second step, merge the jobs. */
- HASHMAP_FOREACH(j, tr->jobs, i) {
- JobType t = j->type;
- Job *k;
-
- /* Merge all transaction jobs for j->unit */
- LIST_FOREACH(transaction, k, j->transaction_next)
- assert_se(job_type_merge_and_collapse(&t, k->type, j->unit) == 0);
-
- while ((k = j->transaction_next)) {
- if (tr->anchor_job == k) {
- transaction_merge_and_delete_job(tr, k, j, t);
- j = k;
- } else
- transaction_merge_and_delete_job(tr, j, k, t);
- }
-
- assert(!j->transaction_next);
- assert(!j->transaction_prev);
- }
-
- return 0;
-}
-
-static void transaction_drop_redundant(Transaction *tr) {
- Job *j;
- Iterator i;
-
- /* Goes through the transaction and removes all jobs of the units
- * whose jobs are all noops. If not all of a unit's jobs are
- * redundant, they are kept. */
-
- assert(tr);
-
-rescan:
- HASHMAP_FOREACH(j, tr->jobs, i) {
- Job *k;
-
- LIST_FOREACH(transaction, k, j) {
-
- if (tr->anchor_job == k ||
- !job_type_is_redundant(k->type, unit_active_state(k->unit)) ||
- (k->unit->job && job_type_is_conflicting(k->type, k->unit->job->type)))
- goto next_unit;
- }
-
- /* log_debug("Found redundant job %s/%s, dropping.", j->unit->id, job_type_to_string(j->type)); */
- transaction_delete_job(tr, j, false);
- goto rescan;
- next_unit:;
- }
-}
-
-_pure_ static bool unit_matters_to_anchor(Unit *u, Job *j) {
- assert(u);
- assert(!j->transaction_prev);
-
- /* Checks whether at least one of the jobs for this unit
- * matters to the anchor. */
-
- LIST_FOREACH(transaction, j, j)
- if (j->matters_to_anchor)
- return true;
-
- return false;
-}
-
-static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsigned generation, sd_bus_error *e) {
- Iterator i;
- Unit *u;
- int r;
-
- assert(tr);
- assert(j);
- assert(!j->transaction_prev);
-
- /* Does a recursive sweep through the ordering graph, looking
- * for a cycle. If we find a cycle we try to break it. */
-
- /* Have we seen this before? */
- if (j->generation == generation) {
- Job *k, *delete;
-
- /* If the marker is NULL we have been here already and
- * decided the job was loop-free from here. Hence
- * shortcut things and return right-away. */
- if (!j->marker)
- return 0;
-
- /* So, the marker is not NULL and we already have been
- * here. We have a cycle. Let's try to break it. We go
- * backwards in our path and try to find a suitable
- * job to remove. We use the marker to find our way
- * back, since smart how we are we stored our way back
- * in there. */
- log_unit_warning(j->unit->id,
- "Found ordering cycle on %s/%s",
- j->unit->id, job_type_to_string(j->type));
-
- delete = NULL;
- for (k = from; k; k = ((k->generation == generation && k->marker != k) ? k->marker : NULL)) {
-
- /* logging for j not k here here to provide consistent narrative */
- log_unit_warning(j->unit->id,
- "Found dependency on %s/%s",
- k->unit->id, job_type_to_string(k->type));
-
- if (!delete && hashmap_get(tr->jobs, k->unit) &&
- !unit_matters_to_anchor(k->unit, k)) {
- /* Ok, we can drop this one, so let's
- * do so. */
- delete = k;
- }
-
- /* Check if this in fact was the beginning of
- * the cycle */
- if (k == j)
- break;
- }
-
-
- if (delete) {
- /* logging for j not k here here to provide consistent narrative */
- log_unit_warning(j->unit->id,
- "Breaking ordering cycle by deleting job %s/%s",
- delete->unit->id, job_type_to_string(delete->type));
- log_unit_error(delete->unit->id,
- "Job %s/%s deleted to break ordering cycle starting with %s/%s",
- delete->unit->id, job_type_to_string(delete->type),
- j->unit->id, job_type_to_string(j->type));
- unit_status_printf(delete->unit, ANSI_HIGHLIGHT_RED_ON " SKIP " ANSI_HIGHLIGHT_OFF,
- "Ordering cycle found, skipping %s");
- transaction_delete_unit(tr, delete->unit);
- return -EAGAIN;
- }
-
- log_error("Unable to break cycle");
-
- return sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC,
- "Transaction order is cyclic. See system logs for details.");
- }
-
- /* Make the marker point to where we come from, so that we can
- * find our way backwards if we want to break a cycle. We use
- * a special marker for the beginning: we point to
- * ourselves. */
- j->marker = from ? from : j;
- j->generation = generation;
-
- /* We assume that the dependencies are bidirectional, and
- * hence can ignore UNIT_AFTER */
- SET_FOREACH(u, j->unit->dependencies[UNIT_BEFORE], i) {
- Job *o;
-
- /* Is there a job for this unit? */
- o = hashmap_get(tr->jobs, u);
- if (!o) {
- /* Ok, there is no job for this in the
- * transaction, but maybe there is already one
- * running? */
- o = u->job;
- if (!o)
- continue;
- }
-
- r = transaction_verify_order_one(tr, o, j, generation, e);
- if (r < 0)
- return r;
- }
-
- /* Ok, let's backtrack, and remember that this entry is not on
- * our path anymore. */
- j->marker = NULL;
-
- return 0;
-}
-
-static int transaction_verify_order(Transaction *tr, unsigned *generation, sd_bus_error *e) {
- Job *j;
- int r;
- Iterator i;
- unsigned g;
-
- assert(tr);
- assert(generation);
-
- /* Check if the ordering graph is cyclic. If it is, try to fix
- * that up by dropping one of the jobs. */
-
- g = (*generation)++;
-
- HASHMAP_FOREACH(j, tr->jobs, i)
- if ((r = transaction_verify_order_one(tr, j, NULL, g, e)) < 0)
- return r;
-
- return 0;
-}
-
-static void transaction_collect_garbage(Transaction *tr) {
- Iterator i;
- Job *j;
-
- assert(tr);
-
- /* Drop jobs that are not required by any other job */
-
-rescan:
- HASHMAP_FOREACH(j, tr->jobs, i) {
- if (tr->anchor_job == j || j->object_list) {
- /* log_debug("Keeping job %s/%s because of %s/%s", */
- /* j->unit->id, job_type_to_string(j->type), */
- /* j->object_list->subject ? j->object_list->subject->unit->id : "root", */
- /* j->object_list->subject ? job_type_to_string(j->object_list->subject->type) : "root"); */
- continue;
- }
-
- /* log_debug("Garbage collecting job %s/%s", j->unit->id, job_type_to_string(j->type)); */
- transaction_delete_job(tr, j, true);
- goto rescan;
- }
-}
-
-static int transaction_is_destructive(Transaction *tr, JobMode mode, sd_bus_error *e) {
- Iterator i;
- Job *j;
-
- assert(tr);
-
- /* Checks whether applying this transaction means that
- * existing jobs would be replaced */
-
- HASHMAP_FOREACH(j, tr->jobs, i) {
-
- /* Assume merged */
- assert(!j->transaction_prev);
- assert(!j->transaction_next);
-
- if (j->unit->job && (mode == JOB_FAIL || j->unit->job->irreversible) &&
- job_type_is_conflicting(j->unit->job->type, j->type))
- return sd_bus_error_setf(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE,
- "Transaction is destructive.");
- }
-
- return 0;
-}
-
-static void transaction_minimize_impact(Transaction *tr) {
- Job *j;
- Iterator i;
-
- assert(tr);
-
- /* Drops all unnecessary jobs that reverse already active jobs
- * or that stop a running service. */
-
-rescan:
- HASHMAP_FOREACH(j, tr->jobs, i) {
- LIST_FOREACH(transaction, j, j) {
- bool stops_running_service, changes_existing_job;
-
- /* If it matters, we shouldn't drop it */
- if (j->matters_to_anchor)
- continue;
-
- /* Would this stop a running service?
- * Would this change an existing job?
- * If so, let's drop this entry */
-
- stops_running_service =
- j->type == JOB_STOP && UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(j->unit));
-
- changes_existing_job =
- j->unit->job &&
- job_type_is_conflicting(j->type, j->unit->job->type);
-
- if (!stops_running_service && !changes_existing_job)
- continue;
-
- if (stops_running_service)
- log_unit_debug(j->unit->id,
- "%s/%s would stop a running service.",
- j->unit->id, job_type_to_string(j->type));
-
- if (changes_existing_job)
- log_unit_debug(j->unit->id,
- "%s/%s would change existing job.",
- j->unit->id, job_type_to_string(j->type));
-
- /* Ok, let's get rid of this */
- log_unit_debug(j->unit->id,
- "Deleting %s/%s to minimize impact.",
- j->unit->id, job_type_to_string(j->type));
-
- transaction_delete_job(tr, j, true);
- goto rescan;
- }
- }
-}
-
-static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) {
- Iterator i;
- Job *j;
- int r;
-
- /* Moves the transaction jobs to the set of active jobs */
-
- if (mode == JOB_ISOLATE || mode == JOB_FLUSH) {
-
- /* When isolating first kill all installed jobs which
- * aren't part of the new transaction */
- HASHMAP_FOREACH(j, m->jobs, i) {
- assert(j->installed);
-
- if (hashmap_get(tr->jobs, j->unit))
- continue;
-
- /* Not invalidating recursively. Avoids triggering
- * OnFailure= actions of dependent jobs. Also avoids
- * invalidating our iterator. */
- job_finish_and_invalidate(j, JOB_CANCELED, false);
- }
- }
-
- HASHMAP_FOREACH(j, tr->jobs, i) {
- /* Assume merged */
- assert(!j->transaction_prev);
- assert(!j->transaction_next);
-
- r = hashmap_put(m->jobs, UINT32_TO_PTR(j->id), j);
- if (r < 0)
- goto rollback;
- }
-
- while ((j = hashmap_steal_first(tr->jobs))) {
- Job *installed_job;
-
- /* Clean the job dependencies */
- transaction_unlink_job(tr, j, false);
-
- installed_job = job_install(j);
- if (installed_job != j) {
- /* j has been merged into a previously installed job */
- if (tr->anchor_job == j)
- tr->anchor_job = installed_job;
- hashmap_remove(m->jobs, UINT32_TO_PTR(j->id));
- job_free(j);
- j = installed_job;
- }
-
- job_add_to_run_queue(j);
- job_add_to_dbus_queue(j);
- job_start_timer(j);
- job_shutdown_magic(j);
- }
-
- return 0;
-
-rollback:
-
- HASHMAP_FOREACH(j, tr->jobs, i)
- hashmap_remove(m->jobs, UINT32_TO_PTR(j->id));
-
- return r;
-}
-
-int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error *e) {
- Iterator i;
- Job *j;
- int r;
- unsigned generation = 1;
-
- assert(tr);
-
- /* This applies the changes recorded in tr->jobs to
- * the actual list of jobs, if possible. */
-
- /* Reset the generation counter of all installed jobs. The detection of cycles
- * looks at installed jobs. If they had a non-zero generation from some previous
- * walk of the graph, the algorithm would break. */
- HASHMAP_FOREACH(j, m->jobs, i)
- j->generation = 0;
-
- /* First step: figure out which jobs matter */
- transaction_find_jobs_that_matter_to_anchor(tr->anchor_job, generation++);
-
- /* Second step: Try not to stop any running services if
- * we don't have to. Don't try to reverse running
- * jobs if we don't have to. */
- if (mode == JOB_FAIL)
- transaction_minimize_impact(tr);
-
- /* Third step: Drop redundant jobs */
- transaction_drop_redundant(tr);
-
- for (;;) {
- /* Fourth step: Let's remove unneeded jobs that might
- * be lurking. */
- if (mode != JOB_ISOLATE)
- transaction_collect_garbage(tr);
-
- /* Fifth step: verify order makes sense and correct
- * cycles if necessary and possible */
- r = transaction_verify_order(tr, &generation, e);
- if (r >= 0)
- break;
-
- if (r != -EAGAIN) {
- log_warning("Requested transaction contains an unfixable cyclic ordering dependency: %s", bus_error_message(e, r));
- return r;
- }
-
- /* Let's see if the resulting transaction ordering
- * graph is still cyclic... */
- }
-
- for (;;) {
- /* Sixth step: let's drop unmergeable entries if
- * necessary and possible, merge entries we can
- * merge */
- r = transaction_merge_jobs(tr, e);
- if (r >= 0)
- break;
-
- if (r != -EAGAIN) {
- log_warning("Requested transaction contains unmergeable jobs: %s", bus_error_message(e, r));
- return r;
- }
-
- /* Seventh step: an entry got dropped, let's garbage
- * collect its dependencies. */
- if (mode != JOB_ISOLATE)
- transaction_collect_garbage(tr);
-
- /* Let's see if the resulting transaction still has
- * unmergeable entries ... */
- }
-
- /* Eights step: Drop redundant jobs again, if the merging now allows us to drop more. */
- transaction_drop_redundant(tr);
-
- /* Ninth step: check whether we can actually apply this */
- r = transaction_is_destructive(tr, mode, e);
- if (r < 0) {
- log_notice("Requested transaction contradicts existing jobs: %s", bus_error_message(e, r));
- return r;
- }
-
- /* Tenth step: apply changes */
- r = transaction_apply(tr, m, mode);
- if (r < 0)
- return log_warning_errno(r, "Failed to apply transaction: %m");
-
- assert(hashmap_isempty(tr->jobs));
-
- if (!hashmap_isempty(m->jobs)) {
- /* Are there any jobs now? Then make sure we have the
- * idle pipe around. We don't really care too much
- * whether this works or not, as the idle pipe is a
- * feature for cosmetics, not actually useful for
- * anything beyond that. */
-
- if (m->idle_pipe[0] < 0 && m->idle_pipe[1] < 0 &&
- m->idle_pipe[2] < 0 && m->idle_pipe[3] < 0) {
- pipe2(m->idle_pipe, O_NONBLOCK|O_CLOEXEC);
- pipe2(m->idle_pipe + 2, O_NONBLOCK|O_CLOEXEC);
- }
- }
-
- return 0;
-}
-
-static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, bool override, bool *is_new) {
- Job *j, *f;
-
- assert(tr);
- assert(unit);
-
- /* Looks for an existing prospective job and returns that. If
- * it doesn't exist it is created and added to the prospective
- * jobs list. */
-
- f = hashmap_get(tr->jobs, unit);
-
- LIST_FOREACH(transaction, j, f) {
- assert(j->unit == unit);
-
- if (j->type == type) {
- if (is_new)
- *is_new = false;
- return j;
- }
- }
-
- j = job_new(unit, type);
- if (!j)
- return NULL;
-
- j->generation = 0;
- j->marker = NULL;
- j->matters_to_anchor = false;
- j->override = override;
- j->irreversible = tr->irreversible;
-
- LIST_PREPEND(transaction, f, j);
-
- if (hashmap_replace(tr->jobs, unit, f) < 0) {
- LIST_REMOVE(transaction, f, j);
- job_free(j);
- return NULL;
- }
-
- if (is_new)
- *is_new = true;
-
- /* log_debug("Added job %s/%s to transaction.", unit->id, job_type_to_string(type)); */
-
- return j;
-}
-
-static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies) {
- assert(tr);
- assert(j);
-
- if (j->transaction_prev)
- j->transaction_prev->transaction_next = j->transaction_next;
- else if (j->transaction_next)
- hashmap_replace(tr->jobs, j->unit, j->transaction_next);
- else
- hashmap_remove_value(tr->jobs, j->unit, j);
-
- if (j->transaction_next)
- j->transaction_next->transaction_prev = j->transaction_prev;
-
- j->transaction_prev = j->transaction_next = NULL;
-
- while (j->subject_list)
- job_dependency_free(j->subject_list);
-
- while (j->object_list) {
- Job *other = j->object_list->matters ? j->object_list->subject : NULL;
-
- job_dependency_free(j->object_list);
-
- if (other && delete_dependencies) {
- log_unit_debug(other->unit->id,
- "Deleting job %s/%s as dependency of job %s/%s",
- other->unit->id, job_type_to_string(other->type),
- j->unit->id, job_type_to_string(j->type));
- transaction_delete_job(tr, other, delete_dependencies);
- }
- }
-}
-
-int transaction_add_job_and_dependencies(
- Transaction *tr,
- JobType type,
- Unit *unit,
- Job *by,
- bool matters,
- bool override,
- bool conflicts,
- bool ignore_requirements,
- bool ignore_order,
- sd_bus_error *e) {
- Job *ret;
- Iterator i;
- Unit *dep;
- int r;
- bool is_new;
-
- assert(tr);
- assert(type < _JOB_TYPE_MAX);
- assert(type < _JOB_TYPE_MAX_IN_TRANSACTION);
- assert(unit);
-
- /* log_debug("Pulling in %s/%s from %s/%s", */
- /* unit->id, job_type_to_string(type), */
- /* 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))
- return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
- "Unit %s is not loaded properly.", unit->id);
-
- if (type != JOB_STOP && unit->load_state == UNIT_ERROR) {
- if (unit->load_error == -ENOENT || unit->manager->test_run)
- return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
- "Unit %s failed to load: %s.",
- unit->id,
- strerror(-unit->load_error));
- else
- return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
- "Unit %s failed to load: %s. "
- "See system logs and 'systemctl status %s' for details.",
- unit->id,
- strerror(-unit->load_error),
- unit->id);
- }
-
- if (type != JOB_STOP && unit->load_state == UNIT_NOT_FOUND)
- return sd_bus_error_setf(e, BUS_ERROR_LOAD_FAILED,
- "Unit %s failed to load: %s.",
- unit->id, strerror(-unit->load_error));
-
- if (type != JOB_STOP && unit->load_state == UNIT_MASKED)
- return sd_bus_error_setf(e, BUS_ERROR_UNIT_MASKED,
- "Unit %s is masked.", unit->id);
-
- if (!unit_job_is_applicable(unit, type))
- return sd_bus_error_setf(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE,
- "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, override, &is_new);
- if (!ret)
- return -ENOMEM;
-
- ret->ignore_order = ret->ignore_order || ignore_order;
-
- /* Then, add a link to the job. */
- if (by) {
- if (!job_dependency_new(by, ret, matters, conflicts))
- return -ENOMEM;
- } else {
- /* If the job has no parent job, it is the anchor job. */
- assert(!tr->anchor_job);
- tr->anchor_job = ret;
- }
-
- if (is_new && !ignore_requirements && type != JOB_NOP) {
- Set *following;
-
- /* If we are following some other unit, make sure we
- * add all dependencies of everybody following. */
- if (unit_following_set(ret->unit, &following) > 0) {
- SET_FOREACH(dep, following, i) {
- r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, override, false, false, ignore_order, e);
- if (r < 0) {
- log_unit_warning(dep->id,
- "Cannot add dependency job for unit %s, ignoring: %s",
- dep->id, bus_error_message(e, r));
-
- if (e)
- sd_bus_error_free(e);
- }
- }
-
- set_free(following);
- }
-
- /* Finally, recursively add in all dependencies. */
- if (type == JOB_START || type == JOB_RESTART) {
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) {
- r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e);
- if (r < 0) {
- if (r != -EBADR)
- goto fail;
-
- if (e)
- sd_bus_error_free(e);
- }
- }
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_BINDS_TO], i) {
- r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e);
- if (r < 0) {
- if (r != -EBADR)
- goto fail;
-
- if (e)
- sd_bus_error_free(e);
- }
- }
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) {
- r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, !override, override, false, false, ignore_order, e);
- if (r < 0) {
- log_unit_full(dep->id,
- r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING,
- "Cannot add dependency job for unit %s, ignoring: %s",
- dep->id, bus_error_message(e, r));
-
- if (e)
- sd_bus_error_free(e);
- }
- }
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) {
- r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, false, ignore_order, e);
- if (r < 0) {
- log_unit_full(dep->id,
- r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING,
- "Cannot add dependency job for unit %s, ignoring: %s",
- dep->id, bus_error_message(e, r));
-
- if (e)
- sd_bus_error_free(e);
- }
- }
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i) {
- r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e);
- if (r < 0) {
- if (r != -EBADR)
- goto fail;
-
- if (e)
- sd_bus_error_free(e);
- }
- }
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) {
- r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e);
- if (r < 0) {
- log_unit_full(dep->id,
- r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING,
- "Cannot add dependency job for unit %s, ignoring: %s",
- dep->id, bus_error_message(e, r));
-
- if (e)
- sd_bus_error_free(e);
- }
- }
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i) {
- r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e);
- if (r < 0) {
- if (r != -EBADR)
- goto fail;
-
- if (e)
- sd_bus_error_free(e);
- }
- }
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) {
- r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e);
- if (r < 0) {
- log_unit_warning(dep->id,
- "Cannot add dependency job for unit %s, ignoring: %s",
- dep->id, bus_error_message(e, r));
-
- if (e)
- sd_bus_error_free(e);
- }
- }
-
- }
-
- if (type == JOB_STOP || type == JOB_RESTART) {
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRED_BY], i) {
- r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
- if (r < 0) {
- if (r != -EBADR)
- goto fail;
-
- if (e)
- sd_bus_error_free(e);
- }
- }
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_BOUND_BY], i) {
- r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
- if (r < 0) {
- if (r != -EBADR)
- goto fail;
-
- if (e)
- sd_bus_error_free(e);
- }
- }
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONSISTS_OF], i) {
- r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
- if (r < 0) {
- if (r != -EBADR)
- goto fail;
-
- if (e)
- sd_bus_error_free(e);
- }
- }
-
- }
-
- if (type == JOB_RELOAD) {
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) {
- r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e);
- if (r < 0) {
- log_unit_warning(dep->id,
- "Cannot add dependency reload job for unit %s, ignoring: %s",
- dep->id, bus_error_message(e, r));
-
- if (e)
- sd_bus_error_free(e);
- }
- }
- }
-
- /* JOB_VERIFY_STARTED require no dependency handling */
- }
-
- return 0;
-
-fail:
- return r;
-}
-
-int transaction_add_isolate_jobs(Transaction *tr, Manager *m) {
- Iterator i;
- Unit *u;
- char *k;
- int r;
-
- assert(tr);
- assert(m);
-
- HASHMAP_FOREACH_KEY(u, k, m->units, i) {
-
- /* ignore aliases */
- if (u->id != k)
- continue;
-
- if (u->ignore_on_isolate)
- continue;
-
- /* No need to stop inactive jobs */
- if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u)) && !u->job)
- continue;
-
- /* Is there already something listed for this? */
- if (hashmap_get(tr->jobs, u))
- continue;
-
- r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, tr->anchor_job, true, false, false, false, false, NULL);
- if (r < 0)
- log_unit_warning(u->id,
- "Cannot add isolate job for unit %s, ignoring: %s",
- u->id, strerror(-r));
- }
-
- return 0;
-}
-
-Transaction *transaction_new(bool irreversible) {
- Transaction *tr;
-
- tr = new0(Transaction, 1);
- if (!tr)
- return NULL;
-
- tr->jobs = hashmap_new(NULL);
- if (!tr->jobs) {
- free(tr);
- return NULL;
- }
-
- tr->irreversible = irreversible;
-
- return tr;
-}
-
-void transaction_free(Transaction *tr) {
- assert(hashmap_isempty(tr->jobs));
- hashmap_free(tr->jobs);
- free(tr);
-}
diff --git a/src/core/transaction.h b/src/core/transaction.h
deleted file mode 100644
index d949b21b8..000000000
--- a/src/core/transaction.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 "unit.h"
-#include "manager.h"
-#include "job.h"
-#include "hashmap.h"
-
-struct Transaction {
- /* Jobs to be added */
- Hashmap *jobs; /* Unit object => Job object list 1:1 */
- Job *anchor_job; /* the job the user asked for */
- bool irreversible;
-};
-
-Transaction *transaction_new(bool irreversible);
-void transaction_free(Transaction *tr);
-
-int transaction_add_job_and_dependencies(
- Transaction *tr,
- JobType type,
- Unit *unit,
- Job *by,
- bool matters,
- bool override,
- bool conflicts,
- bool ignore_requirements,
- bool ignore_order,
- sd_bus_error *e);
-int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error *e);
-int transaction_add_isolate_jobs(Transaction *tr, Manager *m);
-void transaction_abort(Transaction *tr);
diff --git a/src/core/umount.c b/src/core/umount.c
deleted file mode 100644
index ceee70fbe..000000000
--- a/src/core/umount.c
+++ /dev/null
@@ -1,594 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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/>.
-***/
-
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/mount.h>
-#include <sys/swap.h>
-#include <linux/loop.h>
-#include <linux/dm-ioctl.h>
-
-#include "list.h"
-#include "mount-setup.h"
-#include "umount.h"
-#include "path-util.h"
-#include "util.h"
-#include "virt.h"
-#include "libudev.h"
-#include "udev-util.h"
-
-typedef struct MountPoint {
- char *path;
- dev_t devnum;
- LIST_FIELDS(struct MountPoint, mount_point);
-} MountPoint;
-
-static void mount_point_free(MountPoint **head, MountPoint *m) {
- assert(head);
- assert(m);
-
- LIST_REMOVE(mount_point, *head, m);
-
- free(m->path);
- free(m);
-}
-
-static 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;
-
- assert(head);
-
- proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
- if (!proc_self_mountinfo)
- return -errno;
-
- for (i = 1;; i++) {
- _cleanup_free_ char *path = NULL;
- char *p = NULL;
- 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 options */
- "%*[^-]" /* (7) optional fields */
- "- " /* (8) separator */
- "%*s " /* (9) file system type */
- "%*s" /* (10) mount source */
- "%*s" /* (11) mount options 2 */
- "%*[^\n]", /* some rubbish at the end */
- &path);
- if (k != 1) {
- if (k == EOF)
- break;
-
- log_warning("Failed to parse /proc/self/mountinfo:%u.", i);
- continue;
- }
-
- p = cunescape(path);
- if (!p)
- return -ENOMEM;
-
- /* Ignore mount points we can't unmount because they
- * are API or because we are keeping them open (like
- * /dev/console). Also, ignore all mounts below API
- * file systems, since they are likely virtual too,
- * and hence not worth spending time on. Also, in
- * unprivileged containers we might lack the rights to
- * unmount these things, hence don't bother. */
- if (mount_point_is_api(p) ||
- mount_point_ignore(p) ||
- path_startswith(p, "/dev") ||
- path_startswith(p, "/sys") ||
- path_startswith(p, "/proc")) {
- free(p);
- continue;
- }
-
- m = new0(MountPoint, 1);
- if (!m) {
- free(p);
- return -ENOMEM;
- }
-
- m->path = p;
- LIST_PREPEND(mount_point, *head, m);
- }
-
- return 0;
-}
-
-static int swap_list_get(MountPoint **head) {
- _cleanup_fclose_ FILE *proc_swaps = NULL;
- unsigned int i;
-
- assert(head);
-
- if (!(proc_swaps = fopen("/proc/swaps", "re")))
- return (errno == ENOENT) ? 0 : -errno;
-
- (void) fscanf(proc_swaps, "%*s %*s %*s %*s %*s\n");
-
- for (i = 2;; i++) {
- MountPoint *swap;
- char *dev = NULL, *d;
- int k;
-
- if ((k = fscanf(proc_swaps,
- "%ms " /* device/file */
- "%*s " /* type of swap */
- "%*s " /* swap size */
- "%*s " /* used */
- "%*s\n", /* priority */
- &dev)) != 1) {
-
- if (k == EOF)
- break;
-
- log_warning("Failed to parse /proc/swaps:%u.", i);
-
- free(dev);
- continue;
- }
-
- if (endswith(dev, " (deleted)")) {
- free(dev);
- continue;
- }
-
- d = cunescape(dev);
- free(dev);
-
- if (!d) {
- return -ENOMEM;
- }
-
- if (!(swap = new0(MountPoint, 1))) {
- free(d);
- return -ENOMEM;
- }
-
- swap->path = d;
- LIST_PREPEND(mount_point, *head, swap);
- }
-
- return 0;
-}
-
-static int loopback_list_get(MountPoint **head) {
- _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
- struct udev_list_entry *item = NULL, *first = NULL;
- _cleanup_udev_unref_ struct udev *udev = NULL;
- int r;
-
- assert(head);
-
- udev = udev_new();
- if (!udev)
- return -ENOMEM;
-
- e = udev_enumerate_new(udev);
- if (!e)
- return -ENOMEM;
-
- r = udev_enumerate_add_match_subsystem(e, "block");
- if (r < 0)
- return r;
-
- r = udev_enumerate_add_match_sysname(e, "loop*");
- if (r < 0)
- return r;
-
- r = udev_enumerate_add_match_sysattr(e, "loop/backing_file", NULL);
- if (r < 0)
- return r;
-
- r = udev_enumerate_scan_devices(e);
- if (r < 0)
- return r;
-
- 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;
- const char *dn;
-
- d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
- if (!d)
- return -ENOMEM;
-
- dn = udev_device_get_devnode(d);
- if (!dn)
- continue;
-
- loop = strdup(dn);
- if (!loop)
- return -ENOMEM;
-
- lb = new0(MountPoint, 1);
- if (!lb) {
- free(loop);
- return -ENOMEM;
- }
-
- lb->path = loop;
- LIST_PREPEND(mount_point, *head, lb);
- }
-
- return 0;
-}
-
-static int dm_list_get(MountPoint **head) {
- _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
- struct udev_list_entry *item = NULL, *first = NULL;
- _cleanup_udev_unref_ struct udev *udev = NULL;
- int r;
-
- assert(head);
-
- udev = udev_new();
- if (!udev)
- return -ENOMEM;
-
- e = udev_enumerate_new(udev);
- if (!e)
- return -ENOMEM;
-
- r = udev_enumerate_add_match_subsystem(e, "block");
- if (r < 0)
- return r;
-
- r = udev_enumerate_add_match_sysname(e, "dm-*");
- if (r < 0)
- return r;
-
- r = udev_enumerate_scan_devices(e);
- if (r < 0)
- return r;
-
- first = udev_enumerate_get_list_entry(e);
- udev_list_entry_foreach(item, first) {
- MountPoint *m;
- _cleanup_udev_device_unref_ struct udev_device *d;
- dev_t devnum;
- char *node;
- const char *dn;
-
- d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item));
- if (!d)
- return -ENOMEM;
-
- devnum = udev_device_get_devnum(d);
- dn = udev_device_get_devnode(d);
- if (major(devnum) == 0 || !dn)
- continue;
-
- node = strdup(dn);
- if (!node)
- return -ENOMEM;
-
- m = new(MountPoint, 1);
- if (!m) {
- free(node);
- return -ENOMEM;
- }
-
- m->path = node;
- m->devnum = devnum;
- LIST_PREPEND(mount_point, *head, m);
- }
-
- return 0;
-}
-
-static int delete_loopback(const char *device) {
- _cleanup_close_ int fd = -1;
- int r;
-
- fd = open(device, O_RDONLY|O_CLOEXEC);
- if (fd < 0)
- return errno == ENOENT ? 0 : -errno;
-
- r = ioctl(fd, LOOP_CLR_FD, 0);
- if (r >= 0)
- return 1;
-
- /* ENXIO: not bound, so no error */
- if (errno == ENXIO)
- return 0;
-
- return -errno;
-}
-
-static int delete_dm(dev_t devnum) {
- _cleanup_close_ int fd = -1;
- int r;
- struct dm_ioctl dm = {
- .version = {DM_VERSION_MAJOR,
- DM_VERSION_MINOR,
- DM_VERSION_PATCHLEVEL},
- .data_size = sizeof(dm),
- .dev = devnum,
- };
-
- assert(major(devnum) != 0);
-
- fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC);
- if (fd < 0)
- return -errno;
-
- r = ioctl(fd, DM_DEV_REMOVE, &dm);
- return r >= 0 ? 0 : -errno;
-}
-
-static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_error) {
- MountPoint *m, *n;
- int n_failed = 0;
-
- assert(head);
-
- LIST_FOREACH_SAFE(mount_point, m, n, *head) {
-
- /* 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 mound. */
- if (detect_container(NULL) <= 0) {
- /* We always try to remount directories
- * read-only first, before we go on and umount
- * them.
- *
- * Mount points can be stacked. If a mount
- * point is stacked below / or /usr, we
- * cannot umount or remount it directly,
- * since there is no way to refer to the
- * underlying mount. There's nothing we can do
- * about it for the general case, but we can
- * do something about it if it is aliased
- * 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 the fs we
- * can otherwise not see dirty. */
- mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, NULL);
- }
-
- /* Skip / and /usr since we cannot unmount that
- * anyway, since we are running from it. They have
- * already been remounted ro. */
- if (path_equal(m->path, "/")
-#ifndef HAVE_SPLIT_USR
- || path_equal(m->path, "/usr")
-#endif
- )
- continue;
-
- /* Trying to umount. We don't force here since we rely
- * on busy NFS and FUSE file systems to return EBUSY
- * until we closed everything on top of them. */
- log_info("Unmounting %s.", m->path);
- if (umount2(m->path, 0) == 0) {
- if (changed)
- *changed = true;
-
- mount_point_free(head, m);
- } else if (log_error) {
- log_warning_errno(errno, "Could not unmount %s: %m", m->path);
- n_failed++;
- }
- }
-
- return n_failed;
-}
-
-static int swap_points_list_off(MountPoint **head, bool *changed) {
- MountPoint *m, *n;
- int n_failed = 0;
-
- assert(head);
-
- LIST_FOREACH_SAFE(mount_point, m, n, *head) {
- log_info("Deactivating swap %s.", m->path);
- if (swapoff(m->path) == 0) {
- if (changed)
- *changed = true;
-
- mount_point_free(head, m);
- } else {
- log_warning_errno(errno, "Could not deactivate swap %s: %m", m->path);
- n_failed++;
- }
- }
-
- return n_failed;
-}
-
-static int loopback_points_list_detach(MountPoint **head, bool *changed) {
- MountPoint *m, *n;
- int n_failed = 0, k;
- struct stat root_st;
-
- assert(head);
-
- k = lstat("/", &root_st);
-
- LIST_FOREACH_SAFE(mount_point, m, n, *head) {
- int r;
- struct stat loopback_st;
-
- if (k >= 0 &&
- major(root_st.st_dev) != 0 &&
- lstat(m->path, &loopback_st) >= 0 &&
- root_st.st_dev == loopback_st.st_rdev) {
- n_failed ++;
- continue;
- }
-
- log_info("Detaching loopback %s.", m->path);
- r = delete_loopback(m->path);
- if (r >= 0) {
- if (r > 0 && changed)
- *changed = true;
-
- mount_point_free(head, m);
- } else {
- log_warning_errno(errno, "Could not detach loopback %s: %m", m->path);
- n_failed++;
- }
- }
-
- return n_failed;
-}
-
-static int dm_points_list_detach(MountPoint **head, bool *changed) {
- MountPoint *m, *n;
- int n_failed = 0, k;
- struct stat root_st;
-
- assert(head);
-
- k = lstat("/", &root_st);
-
- LIST_FOREACH_SAFE(mount_point, m, n, *head) {
- int r;
-
- if (k >= 0 &&
- major(root_st.st_dev) != 0 &&
- root_st.st_dev == 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;
-
- mount_point_free(head, m);
- } else {
- log_warning_errno(errno, "Could not detach DM %s: %m", m->path);
- n_failed++;
- }
- }
-
- return n_failed;
-}
-
-int umount_all(bool *changed) {
- int r;
- bool umount_changed;
- LIST_HEAD(MountPoint, mp_list_head);
-
- LIST_HEAD_INIT(mp_list_head);
- r = mount_points_list_get(&mp_list_head);
- if (r < 0)
- goto end;
-
- /* retry umount, until nothing can be umounted anymore */
- do {
- umount_changed = false;
-
- mount_points_list_umount(&mp_list_head, &umount_changed, false);
- if (umount_changed)
- *changed = true;
-
- } while (umount_changed);
-
- /* umount one more time with logging enabled */
- r = mount_points_list_umount(&mp_list_head, &umount_changed, true);
- if (r <= 0)
- goto end;
-
- end:
- mount_points_list_free(&mp_list_head);
-
- return r;
-}
-
-int swapoff_all(bool *changed) {
- int r;
- LIST_HEAD(MountPoint, swap_list_head);
-
- LIST_HEAD_INIT(swap_list_head);
-
- r = swap_list_get(&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;
-}
-
-int loopback_detach_all(bool *changed) {
- int r;
- LIST_HEAD(MountPoint, loopback_list_head);
-
- 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;
-}
-
-int dm_detach_all(bool *changed) {
- int r;
- LIST_HEAD(MountPoint, dm_list_head);
-
- 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;
-}
diff --git a/src/core/umount.h b/src/core/umount.h
deleted file mode 100644
index 8439ffe58..000000000
--- a/src/core/umount.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- 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/>.
-***/
-
-int umount_all(bool *changed);
-
-int swapoff_all(bool *changed);
-
-int loopback_detach_all(bool *changed);
-
-int dm_detach_all(bool *changed);
diff --git a/src/core/unit-printf.c b/src/core/unit-printf.c
deleted file mode 100644
index 90cb5040c..000000000
--- a/src/core/unit-printf.c
+++ /dev/null
@@ -1,446 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 "specifier.h"
-#include "strv.h"
-#include "unit-name.h"
-#include "unit-printf.h"
-#include "macro.h"
-#include "cgroup-util.h"
-
-static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) {
- Unit *u = userdata;
- char *n;
-
- assert(u);
-
- n = unit_name_to_prefix_and_instance(u->id);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
-}
-
-static int specifier_prefix(char specifier, void *data, void *userdata, char **ret) {
- Unit *u = userdata;
- char *n;
-
- assert(u);
-
- n = unit_name_to_prefix(u->id);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
-}
-
-static int specifier_prefix_unescaped(char specifier, void *data, void *userdata, char **ret) {
- Unit *u = userdata;
- _cleanup_free_ char *p = NULL;
- char *n;
-
- assert(u);
-
- p = unit_name_to_prefix(u->id);
- if (!p)
- return -ENOMEM;
-
- n = unit_name_unescape(p);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
-}
-
-static int specifier_instance_unescaped(char specifier, void *data, void *userdata, char **ret) {
- Unit *u = userdata;
- char *n;
-
- assert(u);
-
- if (!u->instance)
- return -EOPNOTSUPP;
-
- n = unit_name_unescape(u->instance);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
-}
-
-static int specifier_filename(char specifier, void *data, void *userdata, char **ret) {
- Unit *u = userdata;
- char *n;
-
- assert(u);
-
- if (u->instance)
- n = unit_name_path_unescape(u->instance);
- else
- n = unit_name_to_path(u->id);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
-}
-
-static int specifier_cgroup(char specifier, void *data, void *userdata, char **ret) {
- Unit *u = userdata;
- char *n;
-
- assert(u);
-
- if (u->cgroup_path)
- n = strdup(u->cgroup_path);
- else
- n = unit_default_cgroup_path(u);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
-}
-
-static int specifier_cgroup_root(char specifier, void *data, void *userdata, char **ret) {
- Unit *u = userdata;
- const char *slice;
- char *n;
- int r;
-
- assert(u);
-
- slice = unit_slice_name(u);
- if (specifier == 'R' || !slice)
- n = strdup(u->manager->cgroup_root);
- else {
- _cleanup_free_ char *p = NULL;
-
- r = cg_slice_to_path(slice, &p);
- if (r < 0)
- return r;
-
- n = strjoin(u->manager->cgroup_root, "/", p, NULL);
- if (!n)
- return -ENOMEM;
- }
-
- *ret = n;
- return 0;
-}
-
-static int specifier_runtime(char specifier, void *data, void *userdata, char **ret) {
- Unit *u = userdata;
- const char *e;
- char *n = NULL;
-
- assert(u);
-
- if (u->manager->running_as == SYSTEMD_SYSTEM)
- e = "/run";
- else {
- e = getenv("XDG_RUNTIME_DIR");
- if (!e)
- return -EOPNOTSUPP;
- }
-
- n = strdup(e);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
-}
-
-static int specifier_user_name(char specifier, void *data, void *userdata, char **ret) {
- char *printed = NULL;
- Unit *u = userdata;
- ExecContext *c;
- int r = 0;
-
- assert(u);
-
- c = unit_get_exec_context(u);
- if (!c)
- return -EOPNOTSUPP;
-
- if (u->manager->running_as == SYSTEMD_SYSTEM) {
-
- /* We cannot use NSS from PID 1, hence try to make the
- * best of it in that case, and fail if we can't help
- * it */
-
- if (!c->user || streq(c->user, "root") || streq(c->user, "0"))
- printed = strdup(specifier == 'u' ? "root" : "0");
- else {
- if (specifier == 'u')
- printed = strdup(c->user);
- else {
- uid_t uid;
-
- r = parse_uid(c->user, &uid);
- if (r < 0)
- return -ENODATA;
-
- r = asprintf(&printed, UID_FMT, uid);
- }
- }
-
- } else {
- _cleanup_free_ char *tmp = NULL;
- const char *username = NULL;
- uid_t uid;
-
- if (c->user)
- username = c->user;
- else
- /* get USER env from env or our own uid */
- username = tmp = getusername_malloc();
-
- /* fish username from passwd */
- r = get_user_creds(&username, &uid, NULL, NULL, NULL);
- if (r < 0)
- return r;
-
- if (specifier == 'u')
- printed = strdup(username);
- else
- r = asprintf(&printed, UID_FMT, uid);
- }
-
- if (r < 0 || !printed)
- return -ENOMEM;
-
- *ret = printed;
- return 0;
-}
-
-static int specifier_user_home(char specifier, void *data, void *userdata, char **ret) {
- Unit *u = userdata;
- ExecContext *c;
- char *n;
- int r;
-
- assert(u);
-
- c = unit_get_exec_context(u);
- if (!c)
- return -EOPNOTSUPP;
-
- if (u->manager->running_as == SYSTEMD_SYSTEM) {
-
- /* We cannot use NSS from PID 1, hence try to make the
- * best of it if we can, but fail if we can't */
-
- if (!c->user || streq(c->user, "root") || streq(c->user, "0"))
- n = strdup("/root");
- else
- return -EOPNOTSUPP;
-
- } else {
-
- /* return HOME if set, otherwise from passwd */
- if (!c || !c->user) {
- r = get_home_dir(&n);
- if (r < 0)
- return r;
- } else {
- const char *username, *home;
-
- username = c->user;
- r = get_user_creds(&username, NULL, NULL, &home, NULL);
- if (r < 0)
- return r;
-
- n = strdup(home);
- }
- }
-
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
-}
-
-static int specifier_user_shell(char specifier, void *data, void *userdata, char **ret) {
- Unit *u = userdata;
- ExecContext *c;
- char *n;
- int r;
-
- assert(u);
-
- c = unit_get_exec_context(u);
- if (!c)
- return -EOPNOTSUPP;
-
- if (u->manager->running_as == SYSTEMD_SYSTEM) {
-
- /* We cannot use NSS from PID 1, hence try to make the
- * best of it if we can, but fail if we can't */
-
- if (!c->user || streq(c->user, "root") || streq(c->user, "0"))
- n = strdup("/bin/sh");
- else
- return -EOPNOTSUPP;
-
- } else {
-
- /* return /bin/sh for root, otherwise the value from passwd */
- if (!c->user) {
- r = get_shell(&n);
- if (r < 0)
- return r;
- } else {
- const char *username, *shell;
-
- username = c->user;
- r = get_user_creds(&username, NULL, NULL, NULL, &shell);
- if (r < 0)
- return r;
-
- n = strdup(shell);
- }
- }
-
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
-}
-
-int unit_name_printf(Unit *u, const char* format, char **ret) {
-
- /*
- * This will use the passed string as format string and
- * replace the following specifiers:
- *
- * %n: the full id of the unit (foo@bar.waldo)
- * %N: the id of the unit without the suffix (foo@bar)
- * %p: the prefix (foo)
- * %i: the instance (bar)
- */
-
- const Specifier table[] = {
- { 'n', specifier_string, u->id },
- { 'N', specifier_prefix_and_instance, NULL },
- { 'p', specifier_prefix, NULL },
- { 'i', specifier_string, u->instance },
- { 0, NULL, NULL }
- };
-
- assert(u);
- assert(format);
- assert(ret);
-
- return specifier_printf(format, table, u, ret);
-}
-
-int unit_full_printf(Unit *u, const char *format, char **ret) {
-
- /* This is similar to unit_name_printf() but also supports
- * unescaping. Also, adds a couple of additional codes:
- *
- * %f the instance if set, otherwise the id
- * %c cgroup path of unit
- * %r where units in this slice are placed in the cgroup tree
- * %R the root of this systemd's instance tree
- * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR)
- * %U the UID of the configured user or running user
- * %u the username of the configured user or running user
- * %h the homedir of the configured user or running user
- * %s the shell of the configured user or running user
- * %m the machine ID of the running system
- * %H the host name of the running system
- * %b the boot ID of the running system
- * %v `uname -r` of the running system
- */
-
- 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_root, NULL },
- { 'R', specifier_cgroup_root, NULL },
- { 't', specifier_runtime, NULL },
- { 'U', specifier_user_name, 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 },
- {}
- };
-
- assert(u);
- assert(format);
- assert(ret);
-
- return specifier_printf(format, table, u, ret);
-}
-
-int unit_full_printf_strv(Unit *u, char **l, char ***ret) {
- size_t n;
- char **r, **i, **j;
- int q;
-
- /* Applies unit_full_printf to every entry in l */
-
- assert(u);
-
- n = strv_length(l);
- r = new(char*, n+1);
- if (!r)
- return -ENOMEM;
-
- for (i = l, j = r; *i; i++, j++) {
- q = unit_full_printf(u, *i, j);
- if (q < 0)
- goto fail;
- }
-
- *j = NULL;
- *ret = r;
- return 0;
-
-fail:
- for (j--; j >= r; j--)
- free(*j);
-
- free(r);
- return q;
-}
diff --git a/src/core/unit-printf.h b/src/core/unit-printf.h
deleted file mode 100644
index 51acad63e..000000000
--- a/src/core/unit-printf.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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);
-int unit_full_printf(Unit *u, const char *text, char **ret);
-int unit_full_printf_strv(Unit *u, char **l, char ***ret);
diff --git a/src/core/unit.c b/src/core/unit.c
deleted file mode 100644
index f9aca0188..000000000
--- a/src/core/unit.c
+++ /dev/null
@@ -1,3679 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- 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 <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/stat.h>
-
-#include "sd-id128.h"
-#include "sd-messages.h"
-#include "set.h"
-#include "unit.h"
-#include "macro.h"
-#include "strv.h"
-#include "path-util.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
-#include "log.h"
-#include "unit-name.h"
-#include "dbus-unit.h"
-#include "special.h"
-#include "cgroup-util.h"
-#include "missing.h"
-#include "mkdir.h"
-#include "fileio-label.h"
-#include "bus-common-errors.h"
-#include "dbus.h"
-#include "execute.h"
-#include "dropin.h"
-
-const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
- [UNIT_SERVICE] = &service_vtable,
- [UNIT_SOCKET] = &socket_vtable,
- [UNIT_BUSNAME] = &busname_vtable,
- [UNIT_TARGET] = &target_vtable,
- [UNIT_SNAPSHOT] = &snapshot_vtable,
- [UNIT_DEVICE] = &device_vtable,
- [UNIT_MOUNT] = &mount_vtable,
- [UNIT_AUTOMOUNT] = &automount_vtable,
- [UNIT_SWAP] = &swap_vtable,
- [UNIT_TIMER] = &timer_vtable,
- [UNIT_PATH] = &path_vtable,
- [UNIT_SLICE] = &slice_vtable,
- [UNIT_SCOPE] = &scope_vtable
-};
-
-static int maybe_warn_about_dependency(const char *id, const char *other, UnitDependency dependency);
-
-Unit *unit_new(Manager *m, size_t size) {
- Unit *u;
-
- assert(m);
- assert(size >= sizeof(Unit));
-
- u = malloc0(size);
- if (!u)
- return NULL;
-
- u->names = set_new(&string_hash_ops);
- if (!u->names) {
- free(u);
- return NULL;
- }
-
- u->manager = m;
- u->type = _UNIT_TYPE_INVALID;
- u->deserialized_job = _JOB_TYPE_INVALID;
- u->default_dependencies = true;
- u->unit_file_state = _UNIT_FILE_STATE_INVALID;
- u->unit_file_preset = -1;
- u->on_failure_job_mode = JOB_REPLACE;
-
- return u;
-}
-
-bool unit_has_name(Unit *u, const char *name) {
- assert(u);
- assert(name);
-
- return !!set_get(u->names, (char*) name);
-}
-
-static void unit_init(Unit *u) {
- CGroupContext *cc;
- ExecContext *ec;
- KillContext *kc;
-
- assert(u);
- assert(u->manager);
- assert(u->type >= 0);
-
- cc = unit_get_cgroup_context(u);
- if (cc) {
- cgroup_context_init(cc);
-
- /* Copy in the manager defaults into the cgroup
- * context, _before_ the rest of the settings have
- * been initialized */
-
- cc->cpu_accounting = u->manager->default_cpu_accounting;
- cc->blockio_accounting = u->manager->default_blockio_accounting;
- cc->memory_accounting = u->manager->default_memory_accounting;
- }
-
- ec = unit_get_exec_context(u);
- if (ec)
- exec_context_init(ec);
-
- kc = unit_get_kill_context(u);
- if (kc)
- kill_context_init(kc);
-
- if (UNIT_VTABLE(u)->init)
- UNIT_VTABLE(u)->init(u);
-}
-
-int unit_add_name(Unit *u, const char *text) {
- _cleanup_free_ char *s = NULL, *i = NULL;
- UnitType t;
- int r;
-
- assert(u);
- assert(text);
-
- if (unit_name_is_template(text)) {
-
- if (!u->instance)
- return -EINVAL;
-
- s = unit_name_replace_instance(text, u->instance);
- } else
- s = strdup(text);
- if (!s)
- return -ENOMEM;
-
- if (!unit_name_is_valid(s, TEMPLATE_INVALID))
- return -EINVAL;
-
- assert_se((t = unit_name_to_type(s)) >= 0);
-
- if (u->type != _UNIT_TYPE_INVALID && t != u->type)
- return -EINVAL;
-
- r = unit_name_to_instance(s, &i);
- if (r < 0)
- return r;
-
- if (i && unit_vtable[t]->no_instances)
- return -EINVAL;
-
- /* Ensure that this unit is either instanced or not instanced,
- * but not both. */
- if (u->type != _UNIT_TYPE_INVALID && !u->instance != !i)
- return -EINVAL;
-
- if (unit_vtable[t]->no_alias &&
- !set_isempty(u->names) &&
- !set_get(u->names, s))
- return -EEXIST;
-
- if (hashmap_size(u->manager->units) >= MANAGER_MAX_NAMES)
- return -E2BIG;
-
- r = set_put(u->names, s);
- if (r < 0) {
- if (r == -EEXIST)
- return 0;
-
- return r;
- }
-
- r = hashmap_put(u->manager->units, s, u);
- if (r < 0) {
- set_remove(u->names, s);
- return r;
- }
-
- if (u->type == _UNIT_TYPE_INVALID) {
- u->type = t;
- u->id = s;
- u->instance = i;
-
- LIST_PREPEND(units_by_type, u->manager->units_by_type[t], u);
-
- unit_init(u);
-
- i = NULL;
- }
-
- s = NULL;
-
- unit_add_to_dbus_queue(u);
- return 0;
-}
-
-int unit_choose_id(Unit *u, const char *name) {
- _cleanup_free_ char *t = NULL;
- char *s, *i;
- int r;
-
- assert(u);
- assert(name);
-
- if (unit_name_is_template(name)) {
-
- if (!u->instance)
- return -EINVAL;
-
- t = unit_name_replace_instance(name, u->instance);
- if (!t)
- return -ENOMEM;
-
- name = t;
- }
-
- /* Selects one of the names of this unit as the id */
- s = set_get(u->names, (char*) name);
- if (!s)
- return -ENOENT;
-
- r = unit_name_to_instance(s, &i);
- if (r < 0)
- return r;
-
- u->id = s;
-
- free(u->instance);
- u->instance = i;
-
- unit_add_to_dbus_queue(u);
-
- return 0;
-}
-
-int unit_set_description(Unit *u, const char *description) {
- char *s;
-
- assert(u);
-
- if (isempty(description))
- s = NULL;
- else {
- s = strdup(description);
- if (!s)
- return -ENOMEM;
- }
-
- free(u->description);
- u->description = s;
-
- unit_add_to_dbus_queue(u);
- return 0;
-}
-
-bool unit_check_gc(Unit *u) {
- UnitActiveState state;
- assert(u);
-
- if (u->job)
- return true;
-
- if (u->nop_job)
- return true;
-
- state = unit_active_state(u);
-
- /* If the unit is inactive and failed and no job is queued for
- * it, then release its runtime resources */
- if (UNIT_IS_INACTIVE_OR_FAILED(state) &&
- UNIT_VTABLE(u)->release_resources)
- UNIT_VTABLE(u)->release_resources(u);
-
- /* But we keep the unit object around for longer when it is
- * referenced or configured to not be gc'ed */
- if (state != UNIT_INACTIVE)
- return true;
-
- if (UNIT_VTABLE(u)->no_gc)
- return true;
-
- if (u->no_gc)
- return true;
-
- if (u->refs)
- return true;
-
- if (UNIT_VTABLE(u)->check_gc)
- if (UNIT_VTABLE(u)->check_gc(u))
- return true;
-
- return false;
-}
-
-void unit_add_to_load_queue(Unit *u) {
- assert(u);
- assert(u->type != _UNIT_TYPE_INVALID);
-
- if (u->load_state != UNIT_STUB || u->in_load_queue)
- return;
-
- LIST_PREPEND(load_queue, u->manager->load_queue, u);
- u->in_load_queue = true;
-}
-
-void unit_add_to_cleanup_queue(Unit *u) {
- assert(u);
-
- if (u->in_cleanup_queue)
- return;
-
- LIST_PREPEND(cleanup_queue, u->manager->cleanup_queue, u);
- u->in_cleanup_queue = true;
-}
-
-void unit_add_to_gc_queue(Unit *u) {
- assert(u);
-
- if (u->in_gc_queue || u->in_cleanup_queue)
- return;
-
- if (unit_check_gc(u))
- return;
-
- LIST_PREPEND(gc_queue, u->manager->gc_queue, u);
- u->in_gc_queue = true;
-
- u->manager->n_in_gc_queue ++;
-}
-
-void unit_add_to_dbus_queue(Unit *u) {
- assert(u);
- assert(u->type != _UNIT_TYPE_INVALID);
-
- if (u->load_state == UNIT_STUB || u->in_dbus_queue)
- return;
-
- /* Shortcut things if nobody cares */
- if (sd_bus_track_count(u->manager->subscribed) <= 0 &&
- set_isempty(u->manager->private_buses)) {
- u->sent_dbus_new_signal = true;
- return;
- }
-
- LIST_PREPEND(dbus_queue, u->manager->dbus_unit_queue, u);
- u->in_dbus_queue = true;
-}
-
-static void bidi_set_free(Unit *u, Set *s) {
- Iterator i;
- Unit *other;
-
- assert(u);
-
- /* Frees the set and makes sure we are dropped from the
- * inverse pointers */
-
- SET_FOREACH(other, s, i) {
- UnitDependency d;
-
- for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
- set_remove(other->dependencies[d], u);
-
- unit_add_to_gc_queue(other);
- }
-
- set_free(s);
-}
-
-static void unit_remove_transient(Unit *u) {
- char **i;
-
- assert(u);
-
- if (!u->transient)
- return;
-
- if (u->fragment_path)
- unlink(u->fragment_path);
-
- STRV_FOREACH(i, u->dropin_paths) {
- _cleanup_free_ char *p = NULL;
- int r;
-
- unlink(*i);
-
- r = path_get_parent(*i, &p);
- if (r >= 0)
- rmdir(p);
- }
-}
-
-static void unit_free_requires_mounts_for(Unit *u) {
- char **j;
-
- STRV_FOREACH(j, u->requires_mounts_for) {
- char s[strlen(*j) + 1];
-
- PATH_FOREACH_PREFIX_MORE(s, *j) {
- char *y;
- Set *x;
-
- x = hashmap_get2(u->manager->units_requiring_mounts_for, s, (void**) &y);
- if (!x)
- continue;
-
- set_remove(x, u);
-
- if (set_isempty(x)) {
- hashmap_remove(u->manager->units_requiring_mounts_for, y);
- free(y);
- set_free(x);
- }
- }
- }
-
- strv_free(u->requires_mounts_for);
- u->requires_mounts_for = NULL;
-}
-
-static void unit_done(Unit *u) {
- ExecContext *ec;
- CGroupContext *cc;
-
- assert(u);
-
- if (u->type < 0)
- return;
-
- if (UNIT_VTABLE(u)->done)
- UNIT_VTABLE(u)->done(u);
-
- ec = unit_get_exec_context(u);
- if (ec)
- exec_context_done(ec);
-
- cc = unit_get_cgroup_context(u);
- if (cc)
- cgroup_context_done(cc);
-}
-
-void unit_free(Unit *u) {
- UnitDependency d;
- Iterator i;
- char *t;
-
- assert(u);
-
- if (u->manager->n_reloading <= 0)
- unit_remove_transient(u);
-
- bus_unit_send_removed_signal(u);
-
- unit_done(u);
-
- unit_free_requires_mounts_for(u);
-
- SET_FOREACH(t, u->names, i)
- hashmap_remove_value(u->manager->units, t, u);
-
- if (u->job) {
- Job *j = u->job;
- job_uninstall(j);
- job_free(j);
- }
-
- if (u->nop_job) {
- Job *j = u->nop_job;
- job_uninstall(j);
- job_free(j);
- }
-
- for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
- bidi_set_free(u, u->dependencies[d]);
-
- if (u->type != _UNIT_TYPE_INVALID)
- LIST_REMOVE(units_by_type, u->manager->units_by_type[u->type], u);
-
- if (u->in_load_queue)
- LIST_REMOVE(load_queue, u->manager->load_queue, u);
-
- if (u->in_dbus_queue)
- LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u);
-
- if (u->in_cleanup_queue)
- LIST_REMOVE(cleanup_queue, u->manager->cleanup_queue, u);
-
- if (u->in_gc_queue) {
- LIST_REMOVE(gc_queue, u->manager->gc_queue, u);
- u->manager->n_in_gc_queue--;
- }
-
- if (u->in_cgroup_queue)
- LIST_REMOVE(cgroup_queue, u->manager->cgroup_queue, u);
-
- if (u->cgroup_path) {
- hashmap_remove(u->manager->cgroup_unit, u->cgroup_path);
- free(u->cgroup_path);
- }
-
- manager_update_failed_units(u->manager, u, false);
- set_remove(u->manager->startup_units, u);
-
- free(u->description);
- strv_free(u->documentation);
- free(u->fragment_path);
- free(u->source_path);
- strv_free(u->dropin_paths);
- free(u->instance);
-
- free(u->job_timeout_reboot_arg);
-
- set_free_free(u->names);
-
- unit_unwatch_all_pids(u);
-
- condition_free_list(u->conditions);
- condition_free_list(u->asserts);
-
- unit_ref_unset(&u->slice);
-
- while (u->refs)
- unit_ref_unset(u->refs);
-
- free(u);
-}
-
-UnitActiveState unit_active_state(Unit *u) {
- assert(u);
-
- if (u->load_state == UNIT_MERGED)
- return unit_active_state(unit_follow_merge(u));
-
- /* After a reload it might happen that a unit is not correctly
- * loaded but still has a process around. That's why we won't
- * shortcut failed loading to UNIT_INACTIVE_FAILED. */
-
- return UNIT_VTABLE(u)->active_state(u);
-}
-
-const char* unit_sub_state_to_string(Unit *u) {
- assert(u);
-
- return UNIT_VTABLE(u)->sub_state_to_string(u);
-}
-
-static int complete_move(Set **s, Set **other) {
- int r;
-
- assert(s);
- assert(other);
-
- if (!*other)
- return 0;
-
- if (*s) {
- r = set_move(*s, *other);
- if (r < 0)
- return r;
- } else {
- *s = *other;
- *other = NULL;
- }
-
- return 0;
-}
-
-static int merge_names(Unit *u, Unit *other) {
- char *t;
- Iterator i;
- int r;
-
- assert(u);
- assert(other);
-
- r = complete_move(&u->names, &other->names);
- if (r < 0)
- return r;
-
- set_free_free(other->names);
- other->names = NULL;
- other->id = NULL;
-
- SET_FOREACH(t, u->names, i)
- assert_se(hashmap_replace(u->manager->units, t, u) == 0);
-
- return 0;
-}
-
-static int reserve_dependencies(Unit *u, Unit *other, UnitDependency d) {
- unsigned n_reserve;
-
- assert(u);
- assert(other);
- assert(d < _UNIT_DEPENDENCY_MAX);
-
- /*
- * If u does not have this dependency set allocated, there is no need
- * to reserve anything. In that case other's set will be transferred
- * as a whole to u by complete_move().
- */
- if (!u->dependencies[d])
- return 0;
-
- /* merge_dependencies() will skip a u-on-u dependency */
- n_reserve = set_size(other->dependencies[d]) - !!set_get(other->dependencies[d], u);
-
- return set_reserve(u->dependencies[d], n_reserve);
-}
-
-static void merge_dependencies(Unit *u, Unit *other, const char *other_id, UnitDependency d) {
- Iterator i;
- Unit *back;
- int r;
-
- assert(u);
- assert(other);
- assert(d < _UNIT_DEPENDENCY_MAX);
-
- /* Fix backwards pointers */
- SET_FOREACH(back, other->dependencies[d], i) {
- UnitDependency k;
-
- for (k = 0; k < _UNIT_DEPENDENCY_MAX; k++) {
- /* Do not add dependencies between u and itself */
- if (back == u) {
- if (set_remove(back->dependencies[k], other))
- maybe_warn_about_dependency(u->id, other_id, k);
- } else {
- r = set_remove_and_put(back->dependencies[k], other, u);
- if (r == -EEXIST)
- set_remove(back->dependencies[k], other);
- else
- assert(r >= 0 || r == -ENOENT);
- }
- }
- }
-
- /* Also do not move dependencies on u to itself */
- back = set_remove(other->dependencies[d], u);
- if (back)
- maybe_warn_about_dependency(u->id, other_id, d);
-
- /* The move cannot fail. The caller must have performed a reservation. */
- assert_se(complete_move(&u->dependencies[d], &other->dependencies[d]) == 0);
-
- set_free(other->dependencies[d]);
- other->dependencies[d] = NULL;
-}
-
-int unit_merge(Unit *u, Unit *other) {
- UnitDependency d;
- const char *other_id = NULL;
- int r;
-
- assert(u);
- assert(other);
- assert(u->manager == other->manager);
- assert(u->type != _UNIT_TYPE_INVALID);
-
- other = unit_follow_merge(other);
-
- if (other == u)
- return 0;
-
- if (u->type != other->type)
- return -EINVAL;
-
- if (!u->instance != !other->instance)
- return -EINVAL;
-
- if (other->load_state != UNIT_STUB &&
- other->load_state != UNIT_NOT_FOUND)
- return -EEXIST;
-
- if (other->job)
- return -EEXIST;
-
- if (other->nop_job)
- return -EEXIST;
-
- if (!UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other)))
- return -EEXIST;
-
- if (other->id)
- other_id = strdupa(other->id);
-
- /* Make reservations to ensure merge_dependencies() won't fail */
- for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
- r = reserve_dependencies(u, other, d);
- /*
- * We don't rollback reservations if we fail. We don't have
- * a way to undo reservations. A reservation is not a leak.
- */
- if (r < 0)
- return r;
- }
-
- /* Merge names */
- r = merge_names(u, other);
- if (r < 0)
- return r;
-
- /* Redirect all references */
- while (other->refs)
- unit_ref_set(other->refs, u);
-
- /* Merge dependencies */
- for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
- merge_dependencies(u, other, other_id, d);
-
- other->load_state = UNIT_MERGED;
- other->merged_into = u;
-
- /* If there is still some data attached to the other node, we
- * don't need it anymore, and can free it. */
- if (other->load_state != UNIT_STUB)
- if (UNIT_VTABLE(other)->done)
- UNIT_VTABLE(other)->done(other);
-
- unit_add_to_dbus_queue(u);
- unit_add_to_cleanup_queue(other);
-
- return 0;
-}
-
-int unit_merge_by_name(Unit *u, const char *name) {
- Unit *other;
- int r;
- _cleanup_free_ char *s = NULL;
-
- assert(u);
- assert(name);
-
- if (unit_name_is_template(name)) {
- if (!u->instance)
- return -EINVAL;
-
- s = unit_name_replace_instance(name, u->instance);
- if (!s)
- return -ENOMEM;
-
- name = s;
- }
-
- other = manager_get_unit(u->manager, name);
- if (!other)
- r = unit_add_name(u, name);
- else
- r = unit_merge(u, other);
-
- return r;
-}
-
-Unit* unit_follow_merge(Unit *u) {
- assert(u);
-
- while (u->load_state == UNIT_MERGED)
- assert_se(u = u->merged_into);
-
- return u;
-}
-
-int unit_add_exec_dependencies(Unit *u, ExecContext *c) {
- int r;
-
- assert(u);
- assert(c);
-
- if (c->working_directory) {
- r = unit_require_mounts_for(u, c->working_directory);
- if (r < 0)
- return r;
- }
-
- if (c->root_directory) {
- r = unit_require_mounts_for(u, c->root_directory);
- if (r < 0)
- return r;
- }
-
- if (u->manager->running_as != SYSTEMD_SYSTEM)
- return 0;
-
- if (c->private_tmp) {
- r = unit_require_mounts_for(u, "/tmp");
- if (r < 0)
- return r;
-
- r = unit_require_mounts_for(u, "/var/tmp");
- if (r < 0)
- return r;
- }
-
- if (c->std_output != EXEC_OUTPUT_KMSG &&
- c->std_output != EXEC_OUTPUT_SYSLOG &&
- c->std_output != EXEC_OUTPUT_JOURNAL &&
- c->std_output != EXEC_OUTPUT_KMSG_AND_CONSOLE &&
- c->std_output != EXEC_OUTPUT_SYSLOG_AND_CONSOLE &&
- c->std_output != EXEC_OUTPUT_JOURNAL_AND_CONSOLE &&
- c->std_error != EXEC_OUTPUT_KMSG &&
- c->std_error != EXEC_OUTPUT_SYSLOG &&
- c->std_error != EXEC_OUTPUT_JOURNAL &&
- c->std_error != EXEC_OUTPUT_KMSG_AND_CONSOLE &&
- c->std_error != EXEC_OUTPUT_JOURNAL_AND_CONSOLE &&
- c->std_error != EXEC_OUTPUT_SYSLOG_AND_CONSOLE)
- return 0;
-
- /* If syslog or kernel logging is requested, make sure our own
- * logging daemon is run first. */
-
- r = unit_add_dependency_by_name(u, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, NULL, true);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-const char *unit_description(Unit *u) {
- assert(u);
-
- if (u->description)
- return u->description;
-
- return strna(u->id);
-}
-
-void unit_dump(Unit *u, FILE *f, const char *prefix) {
- char *t, **j;
- UnitDependency d;
- Iterator i;
- const char *prefix2;
- char
- timestamp1[FORMAT_TIMESTAMP_MAX],
- timestamp2[FORMAT_TIMESTAMP_MAX],
- timestamp3[FORMAT_TIMESTAMP_MAX],
- timestamp4[FORMAT_TIMESTAMP_MAX],
- timespan[FORMAT_TIMESPAN_MAX];
- Unit *following;
- _cleanup_set_free_ Set *following_set = NULL;
- int r;
-
- assert(u);
- assert(u->type >= 0);
-
- prefix = strempty(prefix);
- prefix2 = strjoina(prefix, "\t");
-
- fprintf(f,
- "%s-> Unit %s:\n"
- "%s\tDescription: %s\n"
- "%s\tInstance: %s\n"
- "%s\tUnit Load State: %s\n"
- "%s\tUnit Active State: %s\n"
- "%s\tInactive Exit Timestamp: %s\n"
- "%s\tActive Enter Timestamp: %s\n"
- "%s\tActive Exit Timestamp: %s\n"
- "%s\tInactive Enter Timestamp: %s\n"
- "%s\tGC Check Good: %s\n"
- "%s\tNeed Daemon Reload: %s\n"
- "%s\tTransient: %s\n"
- "%s\tSlice: %s\n"
- "%s\tCGroup: %s\n"
- "%s\tCGroup realized: %s\n"
- "%s\tCGroup mask: 0x%x\n"
- "%s\tCGroup members mask: 0x%x\n",
- prefix, u->id,
- prefix, unit_description(u),
- prefix, strna(u->instance),
- prefix, unit_load_state_to_string(u->load_state),
- prefix, unit_active_state_to_string(unit_active_state(u)),
- prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->inactive_exit_timestamp.realtime)),
- prefix, strna(format_timestamp(timestamp2, sizeof(timestamp2), u->active_enter_timestamp.realtime)),
- prefix, strna(format_timestamp(timestamp3, sizeof(timestamp3), u->active_exit_timestamp.realtime)),
- prefix, strna(format_timestamp(timestamp4, sizeof(timestamp4), u->inactive_enter_timestamp.realtime)),
- prefix, yes_no(unit_check_gc(u)),
- prefix, yes_no(unit_need_daemon_reload(u)),
- prefix, yes_no(u->transient),
- prefix, strna(unit_slice_name(u)),
- prefix, strna(u->cgroup_path),
- prefix, yes_no(u->cgroup_realized),
- prefix, u->cgroup_realized_mask,
- prefix, u->cgroup_members_mask);
-
- SET_FOREACH(t, u->names, i)
- fprintf(f, "%s\tName: %s\n", prefix, t);
-
- STRV_FOREACH(j, u->documentation)
- fprintf(f, "%s\tDocumentation: %s\n", prefix, *j);
-
- following = unit_following(u);
- if (following)
- fprintf(f, "%s\tFollowing: %s\n", prefix, following->id);
-
- r = unit_following_set(u, &following_set);
- if (r >= 0) {
- Unit *other;
-
- SET_FOREACH(other, following_set, i)
- fprintf(f, "%s\tFollowing Set Member: %s\n", prefix, other->id);
- }
-
- if (u->fragment_path)
- fprintf(f, "%s\tFragment Path: %s\n", prefix, u->fragment_path);
-
- if (u->source_path)
- fprintf(f, "%s\tSource Path: %s\n", prefix, u->source_path);
-
- STRV_FOREACH(j, u->dropin_paths)
- fprintf(f, "%s\tDropIn Path: %s\n", prefix, *j);
-
- if (u->job_timeout > 0)
- fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout, 0));
-
- if (u->job_timeout_action != FAILURE_ACTION_NONE)
- fprintf(f, "%s\tJob Timeout Action: %s\n", prefix, failure_action_to_string(u->job_timeout_action));
-
- if (u->job_timeout_reboot_arg)
- fprintf(f, "%s\tJob Timeout Reboot Argument: %s\n", prefix, u->job_timeout_reboot_arg);
-
- condition_dump_list(u->conditions, f, prefix, condition_type_to_string);
- condition_dump_list(u->asserts, f, prefix, assert_type_to_string);
-
- if (dual_timestamp_is_set(&u->condition_timestamp))
- fprintf(f,
- "%s\tCondition Timestamp: %s\n"
- "%s\tCondition Result: %s\n",
- prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->condition_timestamp.realtime)),
- prefix, yes_no(u->condition_result));
-
- if (dual_timestamp_is_set(&u->assert_timestamp))
- fprintf(f,
- "%s\tAssert Timestamp: %s\n"
- "%s\tAssert Result: %s\n",
- prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->assert_timestamp.realtime)),
- prefix, yes_no(u->assert_result));
-
- for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
- Unit *other;
-
- SET_FOREACH(other, u->dependencies[d], i)
- fprintf(f, "%s\t%s: %s\n", prefix, unit_dependency_to_string(d), other->id);
- }
-
- if (!strv_isempty(u->requires_mounts_for)) {
- fprintf(f,
- "%s\tRequiresMountsFor:", prefix);
-
- STRV_FOREACH(j, u->requires_mounts_for)
- fprintf(f, " %s", *j);
-
- fputs("\n", f);
- }
-
- if (u->load_state == UNIT_LOADED) {
-
- fprintf(f,
- "%s\tStopWhenUnneeded: %s\n"
- "%s\tRefuseManualStart: %s\n"
- "%s\tRefuseManualStop: %s\n"
- "%s\tDefaultDependencies: %s\n"
- "%s\tOnFailureJobMode: %s\n"
- "%s\tIgnoreOnIsolate: %s\n"
- "%s\tIgnoreOnSnapshot: %s\n",
- prefix, yes_no(u->stop_when_unneeded),
- prefix, yes_no(u->refuse_manual_start),
- prefix, yes_no(u->refuse_manual_stop),
- prefix, yes_no(u->default_dependencies),
- prefix, job_mode_to_string(u->on_failure_job_mode),
- prefix, yes_no(u->ignore_on_isolate),
- prefix, yes_no(u->ignore_on_snapshot));
-
- if (UNIT_VTABLE(u)->dump)
- UNIT_VTABLE(u)->dump(u, f, prefix2);
-
- } else if (u->load_state == UNIT_MERGED)
- fprintf(f,
- "%s\tMerged into: %s\n",
- prefix, u->merged_into->id);
- else if (u->load_state == UNIT_ERROR)
- fprintf(f, "%s\tLoad Error Code: %s\n", prefix, strerror(-u->load_error));
-
-
- if (u->job)
- job_dump(u->job, f, prefix2);
-
- if (u->nop_job)
- job_dump(u->nop_job, f, prefix2);
-
-}
-
-/* Common implementation for multiple backends */
-int unit_load_fragment_and_dropin(Unit *u) {
- int r;
-
- assert(u);
-
- /* Load a .{service,socket,...} file */
- r = unit_load_fragment(u);
- if (r < 0)
- return r;
-
- if (u->load_state == UNIT_STUB)
- return -ENOENT;
-
- /* Load drop-in directory data */
- r = unit_load_dropin(unit_follow_merge(u));
- if (r < 0)
- return r;
-
- return 0;
-}
-
-/* Common implementation for multiple backends */
-int unit_load_fragment_and_dropin_optional(Unit *u) {
- int r;
-
- assert(u);
-
- /* Same as unit_load_fragment_and_dropin(), but whether
- * something can be loaded or not doesn't matter. */
-
- /* Load a .service file */
- r = unit_load_fragment(u);
- if (r < 0)
- return r;
-
- if (u->load_state == UNIT_STUB)
- u->load_state = UNIT_LOADED;
-
- /* Load drop-in directory data */
- r = unit_load_dropin(unit_follow_merge(u));
- if (r < 0)
- return r;
-
- return 0;
-}
-
-int unit_add_default_target_dependency(Unit *u, Unit *target) {
- assert(u);
- assert(target);
-
- if (target->type != UNIT_TARGET)
- return 0;
-
- /* Only add the dependency if both units are loaded, so that
- * that loop check below is reliable */
- if (u->load_state != UNIT_LOADED ||
- target->load_state != UNIT_LOADED)
- return 0;
-
- /* If either side wants no automatic dependencies, then let's
- * skip this */
- if (!u->default_dependencies ||
- !target->default_dependencies)
- return 0;
-
- /* Don't create loops */
- if (set_get(target->dependencies[UNIT_BEFORE], u))
- return 0;
-
- return unit_add_dependency(target, UNIT_AFTER, u, true);
-}
-
-static int unit_add_target_dependencies(Unit *u) {
-
- static const UnitDependency deps[] = {
- UNIT_REQUIRED_BY,
- UNIT_REQUIRED_BY_OVERRIDABLE,
- UNIT_WANTED_BY,
- UNIT_BOUND_BY
- };
-
- Unit *target;
- Iterator i;
- unsigned k;
- int r = 0;
-
- assert(u);
-
- for (k = 0; k < ELEMENTSOF(deps); k++)
- SET_FOREACH(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) {
- assert(u);
-
- if (!unit_get_cgroup_context(u))
- return 0;
-
- if (UNIT_ISSET(u->slice))
- return unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, UNIT_DEREF(u->slice), true);
-
- if (streq(u->id, SPECIAL_ROOT_SLICE))
- return 0;
-
- return unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, SPECIAL_ROOT_SLICE, NULL, true);
-}
-
-static int unit_add_mount_dependencies(Unit *u) {
- char **i;
- int r;
-
- assert(u);
-
- STRV_FOREACH(i, u->requires_mounts_for) {
- char prefix[strlen(*i) + 1];
-
- PATH_FOREACH_PREFIX_MORE(prefix, *i) {
- Unit *m;
-
- r = manager_get_unit_by_path(u->manager, prefix, ".mount", &m);
- if (r < 0)
- return r;
- if (r == 0)
- continue;
- if (m == u)
- continue;
-
- if (m->load_state != UNIT_LOADED)
- continue;
-
- r = unit_add_dependency(u, UNIT_AFTER, m, true);
- if (r < 0)
- return r;
-
- if (m->fragment_path) {
- r = unit_add_dependency(u, UNIT_REQUIRES, m, true);
- if (r < 0)
- return r;
- }
- }
- }
-
- return 0;
-}
-
-static int unit_add_startup_units(Unit *u) {
- CGroupContext *c;
- int r = 0;
-
- c = unit_get_cgroup_context(u);
- if (!c)
- return 0;
-
- if (c->startup_cpu_shares == (unsigned long) -1 &&
- c->startup_blockio_weight == (unsigned long) -1)
- return 0;
-
- r = set_put(u->manager->startup_units, u);
- if (r == -EEXIST)
- return 0;
-
- return r;
-}
-
-int unit_load(Unit *u) {
- int r;
-
- assert(u);
-
- if (u->in_load_queue) {
- LIST_REMOVE(load_queue, u->manager->load_queue, u);
- u->in_load_queue = false;
- }
-
- if (u->type == _UNIT_TYPE_INVALID)
- return -EINVAL;
-
- if (u->load_state != UNIT_STUB)
- return 0;
-
- if (UNIT_VTABLE(u)->load) {
- r = UNIT_VTABLE(u)->load(u);
- if (r < 0)
- goto fail;
- }
-
- if (u->load_state == UNIT_STUB) {
- r = -ENOENT;
- goto fail;
- }
-
- if (u->load_state == UNIT_LOADED) {
-
- r = unit_add_target_dependencies(u);
- if (r < 0)
- goto fail;
-
- r = unit_add_slice_dependencies(u);
- if (r < 0)
- goto fail;
-
- r = unit_add_mount_dependencies(u);
- if (r < 0)
- goto fail;
-
- r = unit_add_startup_units(u);
- if (r < 0)
- goto fail;
-
- if (u->on_failure_job_mode == JOB_ISOLATE && set_size(u->dependencies[UNIT_ON_FAILURE]) > 1) {
- log_unit_error(u->id, "More than one OnFailure= dependencies specified for %s but OnFailureJobMode=isolate set. Refusing.", u->id);
- r = -EINVAL;
- goto fail;
- }
-
- unit_update_cgroup_members_masks(u);
- }
-
- assert((u->load_state != UNIT_MERGED) == !u->merged_into);
-
- unit_add_to_dbus_queue(unit_follow_merge(u));
- unit_add_to_gc_queue(u);
-
- return 0;
-
-fail:
- u->load_state = u->load_state == UNIT_STUB ? UNIT_NOT_FOUND : UNIT_ERROR;
- u->load_error = r;
- unit_add_to_dbus_queue(u);
- unit_add_to_gc_queue(u);
-
- log_unit_debug(u->id, "Failed to load configuration for %s: %s",
- u->id, strerror(-r));
-
- return r;
-}
-
-static bool unit_condition_test_list(Unit *u, Condition *first, const char *(*to_string)(ConditionType t)) {
- Condition *c;
- int triggered = -1;
-
- assert(u);
- assert(to_string);
-
- /* If the condition list is empty, then it is true */
- if (!first)
- return true;
-
- /* Otherwise, if all of the non-trigger conditions apply and
- * if any of the trigger conditions apply (unless there are
- * none) we return true */
- LIST_FOREACH(conditions, c, first) {
- int r;
-
- r = condition_test(c);
- if (r < 0)
- log_unit_warning(u->id,
- "Couldn't determine result for %s=%s%s%s for %s, assuming failed: %s",
- to_string(c->type),
- c->trigger ? "|" : "",
- c->negate ? "!" : "",
- c->parameter,
- u->id,
- strerror(-r));
- else
- log_unit_debug(u->id,
- "%s=%s%s%s %s for %s.",
- to_string(c->type),
- c->trigger ? "|" : "",
- c->negate ? "!" : "",
- c->parameter,
- condition_result_to_string(c->result),
- u->id);
-
- if (!c->trigger && r <= 0)
- return false;
-
- if (c->trigger && triggered <= 0)
- triggered = r > 0;
- }
-
- return triggered != 0;
-}
-
-static bool unit_condition_test(Unit *u) {
- assert(u);
-
- dual_timestamp_get(&u->condition_timestamp);
- u->condition_result = unit_condition_test_list(u, u->conditions, condition_type_to_string);
-
- return u->condition_result;
-}
-
-static bool unit_assert_test(Unit *u) {
- assert(u);
-
- dual_timestamp_get(&u->assert_timestamp);
- u->assert_result = unit_condition_test_list(u, u->asserts, assert_type_to_string);
-
- return u->assert_result;
-}
-
-_pure_ static const char* unit_get_status_message_format(Unit *u, JobType t) {
- const UnitStatusMessageFormats *format_table;
-
- assert(u);
- assert(t >= 0);
- assert(t < _JOB_TYPE_MAX);
-
- if (t != JOB_START && t != JOB_STOP)
- return NULL;
-
- format_table = &UNIT_VTABLE(u)->status_message_formats;
- if (!format_table)
- return NULL;
-
- return format_table->starting_stopping[t == JOB_STOP];
-}
-
-_pure_ static const char *unit_get_status_message_format_try_harder(Unit *u, JobType t) {
- const char *format;
-
- assert(u);
- assert(t >= 0);
- assert(t < _JOB_TYPE_MAX);
-
- format = unit_get_status_message_format(u, t);
- if (format)
- return format;
-
- /* Return generic strings */
- if (t == JOB_START)
- return "Starting %s.";
- else if (t == JOB_STOP)
- return "Stopping %s.";
- else if (t == JOB_RELOAD)
- return "Reloading %s.";
-
- return NULL;
-}
-
-static void unit_status_print_starting_stopping(Unit *u, JobType t) {
- const char *format;
-
- assert(u);
-
- /* We only print status messages for selected units on
- * selected operations. */
-
- format = unit_get_status_message_format(u, t);
- if (!format)
- return;
-
- DISABLE_WARNING_FORMAT_NONLITERAL;
- unit_status_printf(u, "", format);
- REENABLE_WARNING;
-}
-
-static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
- const char *format;
- char buf[LINE_MAX];
- sd_id128_t mid;
-
- assert(u);
-
- if (t != JOB_START && t != JOB_STOP && t != JOB_RELOAD)
- return;
-
- if (log_on_console())
- return;
-
- /* We log status messages for all units and all operations. */
-
- format = unit_get_status_message_format_try_harder(u, t);
- if (!format)
- return;
-
- DISABLE_WARNING_FORMAT_NONLITERAL;
- snprintf(buf, sizeof(buf), format, unit_description(u));
- REENABLE_WARNING;
-
- mid = t == JOB_START ? SD_MESSAGE_UNIT_STARTING :
- t == JOB_STOP ? SD_MESSAGE_UNIT_STOPPING :
- SD_MESSAGE_UNIT_RELOADING;
-
- log_unit_struct(u->id,
- LOG_INFO,
- LOG_MESSAGE_ID(mid),
- LOG_MESSAGE("%s", buf),
- NULL);
-}
-
-/* Errors:
- * -EBADR: This unit type does not support starting.
- * -EALREADY: Unit is already started.
- * -EAGAIN: An operation is already in progress. Retry later.
- * -ECANCELED: Too many requests for now.
- * -EPROTO: Assert failed
- */
-int unit_start(Unit *u) {
- UnitActiveState state;
- Unit *following;
- int r;
-
- assert(u);
-
- if (u->load_state != UNIT_LOADED)
- return -EINVAL;
-
- /* If this is already started, then this will succeed. Note
- * that this will even succeed if this unit is not startable
- * by the user. This is relied on to detect when we need to
- * wait for units and when waiting is finished. */
- state = unit_active_state(u);
- if (UNIT_IS_ACTIVE_OR_RELOADING(state))
- return -EALREADY;
-
- /* 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,
- * but we don't want to recheck the condition in that case. */
- if (state != UNIT_ACTIVATING &&
- !unit_condition_test(u)) {
- log_unit_debug(u->id, "Starting of %s requested but condition failed. Not starting unit.", u->id);
- return -EALREADY;
- }
-
- /* If the asserts failed, fail the entire job */
- if (state != UNIT_ACTIVATING &&
- !unit_assert_test(u)) {
- log_unit_debug(u->id, "Starting of %s requested but asserts failed.", u->id);
- return -EPROTO;
- }
-
- /* Forward to the main object, if we aren't it. */
- following = unit_following(u);
- if (following) {
- log_unit_debug(u->id, "Redirecting start request from %s to %s.", u->id, following->id);
- return unit_start(following);
- }
-
- if (UNIT_VTABLE(u)->supported && !UNIT_VTABLE(u)->supported(u->manager))
- return -EOPNOTSUPP;
-
- /* If it is stopped, but we cannot start it, then fail */
- if (!UNIT_VTABLE(u)->start)
- return -EBADR;
-
- /* We don't suppress calls to ->start() here when we are
- * already starting, to allow this request to be used as a
- * "hurry up" call, for example when the unit is in some "auto
- * restart" state where it waits for a holdoff timer to elapse
- * before it will start again. */
-
- unit_add_to_dbus_queue(u);
-
- r = UNIT_VTABLE(u)->start(u);
- if (r <= 0)
- return r;
-
- /* Log if the start function actually did something */
- unit_status_log_starting_stopping_reloading(u, JOB_START);
- unit_status_print_starting_stopping(u, JOB_START);
- return r;
-}
-
-bool unit_can_start(Unit *u) {
- assert(u);
-
- return !!UNIT_VTABLE(u)->start;
-}
-
-bool unit_can_isolate(Unit *u) {
- assert(u);
-
- return unit_can_start(u) &&
- u->allow_isolate;
-}
-
-/* Errors:
- * -EBADR: This unit type does not support stopping.
- * -EALREADY: Unit is already stopped.
- * -EAGAIN: An operation is already in progress. Retry later.
- */
-int unit_stop(Unit *u) {
- UnitActiveState state;
- Unit *following;
- int r;
-
- assert(u);
-
- state = unit_active_state(u);
- if (UNIT_IS_INACTIVE_OR_FAILED(state))
- return -EALREADY;
-
- following = unit_following(u);
- if (following) {
- log_unit_debug(u->id, "Redirecting stop request from %s to %s.", u->id, following->id);
- return unit_stop(following);
- }
-
- if (!UNIT_VTABLE(u)->stop)
- return -EBADR;
-
- unit_add_to_dbus_queue(u);
-
- r = UNIT_VTABLE(u)->stop(u);
- if (r <= 0)
- return r;
-
- unit_status_log_starting_stopping_reloading(u, JOB_STOP);
- unit_status_print_starting_stopping(u, JOB_STOP);
- return r;
-}
-
-/* Errors:
- * -EBADR: This unit type does not support reloading.
- * -ENOEXEC: Unit is not started.
- * -EAGAIN: An operation is already in progress. Retry later.
- */
-int unit_reload(Unit *u) {
- UnitActiveState state;
- Unit *following;
- int r;
-
- assert(u);
-
- if (u->load_state != UNIT_LOADED)
- return -EINVAL;
-
- if (!unit_can_reload(u))
- return -EBADR;
-
- state = unit_active_state(u);
- if (state == UNIT_RELOADING)
- return -EALREADY;
-
- if (state != UNIT_ACTIVE) {
- log_unit_warning(u->id, "Unit %s cannot be reloaded because it is inactive.", u->id);
- return -ENOEXEC;
- }
-
- following = unit_following(u);
- if (following) {
- log_unit_debug(u->id, "Redirecting reload request from %s to %s.", u->id, following->id);
- return unit_reload(following);
- }
-
- unit_add_to_dbus_queue(u);
-
- r = UNIT_VTABLE(u)->reload(u);
- if (r <= 0)
- return r;
-
- unit_status_log_starting_stopping_reloading(u, JOB_RELOAD);
- return r;
-}
-
-bool unit_can_reload(Unit *u) {
- assert(u);
-
- if (!UNIT_VTABLE(u)->reload)
- return false;
-
- if (!UNIT_VTABLE(u)->can_reload)
- return true;
-
- return UNIT_VTABLE(u)->can_reload(u);
-}
-
-static void unit_check_unneeded(Unit *u) {
- Iterator i;
- Unit *other;
-
- assert(u);
-
- /* If this service shall be shut down when unneeded then do
- * so. */
-
- if (!u->stop_when_unneeded)
- return;
-
- if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)))
- return;
-
- SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i)
- if (unit_active_or_pending(other))
- return;
-
- SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
- if (unit_active_or_pending(other))
- return;
-
- SET_FOREACH(other, u->dependencies[UNIT_WANTED_BY], i)
- if (unit_active_or_pending(other))
- return;
-
- SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
- if (unit_active_or_pending(other))
- return;
-
- log_unit_info(u->id, "Unit %s is not needed anymore. Stopping.", u->id);
-
- /* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */
- manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, true, NULL, NULL);
-}
-
-static void unit_check_binds_to(Unit *u) {
- bool stop = false;
- Unit *other;
- Iterator i;
-
- assert(u);
-
- if (u->job)
- return;
-
- if (unit_active_state(u) != UNIT_ACTIVE)
- return;
-
- SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], i) {
- if (other->job)
- continue;
-
- if (!UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(other)))
- continue;
-
- stop = true;
- break;
- }
-
- if (!stop)
- return;
-
- assert(other);
- log_unit_info(u->id, "Unit %s is bound to inactive unit %s. Stopping, too.", u->id, other->id);
-
- /* A unit we need to run is gone. Sniff. Let's stop this. */
- manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, true, NULL, NULL);
-}
-
-static void retroactively_start_dependencies(Unit *u) {
- Iterator i;
- Unit *other;
-
- assert(u);
- assert(UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)));
-
- SET_FOREACH(other, u->dependencies[UNIT_REQUIRES], i)
- if (!set_get(u->dependencies[UNIT_AFTER], other) &&
- !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
- manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL);
-
- SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], i)
- if (!set_get(u->dependencies[UNIT_AFTER], other) &&
- !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
- manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL);
-
- SET_FOREACH(other, u->dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
- if (!set_get(u->dependencies[UNIT_AFTER], other) &&
- !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
- manager_add_job(u->manager, JOB_START, other, JOB_FAIL, false, NULL, NULL);
-
- SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
- if (!set_get(u->dependencies[UNIT_AFTER], other) &&
- !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
- manager_add_job(u->manager, JOB_START, other, JOB_FAIL, false, NULL, NULL);
-
- SET_FOREACH(other, u->dependencies[UNIT_CONFLICTS], i)
- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
- manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL);
-
- SET_FOREACH(other, u->dependencies[UNIT_CONFLICTED_BY], i)
- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
- manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL);
-}
-
-static void retroactively_stop_dependencies(Unit *u) {
- Iterator i;
- Unit *other;
-
- assert(u);
- assert(UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u)));
-
- /* Pull down units which are bound to us recursively if enabled */
- SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
- manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL);
-}
-
-static void check_unneeded_dependencies(Unit *u) {
- Iterator i;
- Unit *other;
-
- assert(u);
- assert(UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u)));
-
- /* Garbage collect services that might not be needed anymore, if enabled */
- SET_FOREACH(other, u->dependencies[UNIT_REQUIRES], i)
- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
- unit_check_unneeded(other);
- SET_FOREACH(other, u->dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
- unit_check_unneeded(other);
- SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
- unit_check_unneeded(other);
- SET_FOREACH(other, u->dependencies[UNIT_REQUISITE], i)
- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
- unit_check_unneeded(other);
- SET_FOREACH(other, u->dependencies[UNIT_REQUISITE_OVERRIDABLE], i)
- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
- unit_check_unneeded(other);
- SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], i)
- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
- unit_check_unneeded(other);
-}
-
-void unit_start_on_failure(Unit *u) {
- Unit *other;
- Iterator i;
-
- assert(u);
-
- if (set_size(u->dependencies[UNIT_ON_FAILURE]) <= 0)
- return;
-
- log_unit_info(u->id, "Triggering OnFailure= dependencies of %s.", u->id);
-
- SET_FOREACH(other, u->dependencies[UNIT_ON_FAILURE], i) {
- int r;
-
- r = manager_add_job(u->manager, JOB_START, other, u->on_failure_job_mode, true, NULL, NULL);
- if (r < 0)
- log_unit_error_errno(u->id, r, "Failed to enqueue OnFailure= job: %m");
- }
-}
-
-void unit_trigger_notify(Unit *u) {
- Unit *other;
- Iterator i;
-
- assert(u);
-
- SET_FOREACH(other, u->dependencies[UNIT_TRIGGERED_BY], i)
- if (UNIT_VTABLE(other)->trigger_notify)
- UNIT_VTABLE(other)->trigger_notify(other, u);
-}
-
-void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success) {
- Manager *m;
- bool unexpected;
-
- assert(u);
- assert(os < _UNIT_ACTIVE_STATE_MAX);
- assert(ns < _UNIT_ACTIVE_STATE_MAX);
-
- /* Note that this is called for all low-level state changes,
- * even if they might map to the same high-level
- * UnitActiveState! That means that ns == os is an expected
- * behavior here. For example: if a mount point is remounted
- * this function will be called too! */
-
- m = u->manager;
-
- /* Update timestamps for state changes */
- if (m->n_reloading <= 0) {
- dual_timestamp ts;
-
- dual_timestamp_get(&ts);
-
- if (UNIT_IS_INACTIVE_OR_FAILED(os) && !UNIT_IS_INACTIVE_OR_FAILED(ns))
- u->inactive_exit_timestamp = ts;
- else if (!UNIT_IS_INACTIVE_OR_FAILED(os) && UNIT_IS_INACTIVE_OR_FAILED(ns))
- u->inactive_enter_timestamp = ts;
-
- if (!UNIT_IS_ACTIVE_OR_RELOADING(os) && UNIT_IS_ACTIVE_OR_RELOADING(ns))
- u->active_enter_timestamp = ts;
- else if (UNIT_IS_ACTIVE_OR_RELOADING(os) && !UNIT_IS_ACTIVE_OR_RELOADING(ns))
- u->active_exit_timestamp = ts;
- }
-
- /* Keep track of failed units */
- manager_update_failed_units(u->manager, u, ns == UNIT_FAILED);
-
- /* Make sure the cgroup is always removed when we become inactive */
- if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- unit_destroy_cgroup_if_empty(u);
-
- /* Note that this doesn't apply to RemainAfterExit services exiting
- * successfully, since there's no change of state in that case. Which is
- * why it is handled in service_set_state() */
- if (UNIT_IS_INACTIVE_OR_FAILED(os) != UNIT_IS_INACTIVE_OR_FAILED(ns)) {
- ExecContext *ec;
-
- ec = unit_get_exec_context(u);
- if (ec && exec_context_may_touch_console(ec)) {
- if (UNIT_IS_INACTIVE_OR_FAILED(ns)) {
- m->n_on_console --;
-
- if (m->n_on_console == 0)
- /* unset no_console_output flag, since the console is free */
- m->no_console_output = false;
- } else
- m->n_on_console ++;
- }
- }
-
- if (u->job) {
- unexpected = false;
-
- if (u->job->state == JOB_WAITING)
-
- /* So we reached a different state for this
- * job. Let's see if we can run it now if it
- * failed previously due to EAGAIN. */
- job_add_to_run_queue(u->job);
-
- /* Let's check whether this state change constitutes a
- * finished job, or maybe contradicts a running job and
- * hence needs to invalidate jobs. */
-
- switch (u->job->type) {
-
- case JOB_START:
- case JOB_VERIFY_ACTIVE:
-
- if (UNIT_IS_ACTIVE_OR_RELOADING(ns))
- job_finish_and_invalidate(u->job, JOB_DONE, true);
- else if (u->job->state == JOB_RUNNING && ns != UNIT_ACTIVATING) {
- unexpected = true;
-
- if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true);
- }
-
- break;
-
- case JOB_RELOAD:
- case JOB_RELOAD_OR_START:
-
- if (u->job->state == JOB_RUNNING) {
- if (ns == UNIT_ACTIVE)
- job_finish_and_invalidate(u->job, reload_success ? JOB_DONE : JOB_FAILED, true);
- else if (ns != UNIT_ACTIVATING && ns != UNIT_RELOADING) {
- unexpected = true;
-
- if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true);
- }
- }
-
- break;
-
- case JOB_STOP:
- case JOB_RESTART:
- case JOB_TRY_RESTART:
-
- if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- job_finish_and_invalidate(u->job, JOB_DONE, true);
- else if (u->job->state == JOB_RUNNING && ns != UNIT_DEACTIVATING) {
- unexpected = true;
- job_finish_and_invalidate(u->job, JOB_FAILED, true);
- }
-
- break;
-
- default:
- assert_not_reached("Job type unknown");
- }
-
- } else
- unexpected = true;
-
- if (m->n_reloading <= 0) {
-
- /* If this state change happened without being
- * requested by a job, then let's retroactively start
- * or stop dependencies. We skip that step when
- * deserializing, since we don't want to create any
- * additional jobs just because something is already
- * activated. */
-
- if (unexpected) {
- if (UNIT_IS_INACTIVE_OR_FAILED(os) && UNIT_IS_ACTIVE_OR_ACTIVATING(ns))
- retroactively_start_dependencies(u);
- else if (UNIT_IS_ACTIVE_OR_ACTIVATING(os) && UNIT_IS_INACTIVE_OR_DEACTIVATING(ns))
- retroactively_stop_dependencies(u);
- }
-
- /* stop unneeded units regardless if going down was expected or not */
- if (UNIT_IS_INACTIVE_OR_DEACTIVATING(ns))
- check_unneeded_dependencies(u);
-
- if (ns != os && ns == UNIT_FAILED) {
- log_unit_notice(u->id, "Unit %s entered failed state.", u->id);
- unit_start_on_failure(u);
- }
- }
-
- /* Some names are special */
- if (UNIT_IS_ACTIVE_OR_RELOADING(ns)) {
-
- if (unit_has_name(u, SPECIAL_DBUS_SERVICE))
- /* The bus might have just become available,
- * hence try to connect to it, if we aren't
- * yet connected. */
- bus_init(m, true);
-
- if (u->type == UNIT_SERVICE &&
- !UNIT_IS_ACTIVE_OR_RELOADING(os) &&
- m->n_reloading <= 0) {
- /* Write audit record if we have just finished starting up */
- manager_send_unit_audit(m, u, AUDIT_SERVICE_START, true);
- u->in_audit = true;
- }
-
- if (!UNIT_IS_ACTIVE_OR_RELOADING(os))
- manager_send_unit_plymouth(m, u);
-
- } else {
-
- /* We don't care about D-Bus here, since we'll get an
- * asynchronous notification for it anyway. */
-
- if (u->type == UNIT_SERVICE &&
- UNIT_IS_INACTIVE_OR_FAILED(ns) &&
- !UNIT_IS_INACTIVE_OR_FAILED(os) &&
- m->n_reloading <= 0) {
-
- /* Hmm, if there was no start record written
- * write it now, so that we always have a nice
- * pair */
- if (!u->in_audit) {
- manager_send_unit_audit(m, u, AUDIT_SERVICE_START, ns == UNIT_INACTIVE);
-
- if (ns == UNIT_INACTIVE)
- manager_send_unit_audit(m, u, AUDIT_SERVICE_STOP, true);
- } else
- /* Write audit record if we have just finished shutting down */
- manager_send_unit_audit(m, u, AUDIT_SERVICE_STOP, ns == UNIT_INACTIVE);
-
- u->in_audit = false;
- }
- }
-
- manager_recheck_journal(m);
- unit_trigger_notify(u);
-
- if (u->manager->n_reloading <= 0) {
- /* Maybe we finished startup and are now ready for
- * being stopped because unneeded? */
- unit_check_unneeded(u);
-
- /* Maybe we finished startup, but something we needed
- * has vanished? Let's die then. (This happens when
- * something BindsTo= to a Type=oneshot unit, as these
- * units go directly from starting to inactive,
- * without ever entering started.) */
- unit_check_binds_to(u);
- }
-
- unit_add_to_dbus_queue(u);
- unit_add_to_gc_queue(u);
-}
-
-int unit_watch_pid(Unit *u, pid_t pid) {
- int q, r;
-
- assert(u);
- assert(pid >= 1);
-
- /* Watch a specific PID. We only support one or two units
- * watching each PID for now, not more. */
-
- r = set_ensure_allocated(&u->pids, NULL);
- if (r < 0)
- return r;
-
- r = hashmap_ensure_allocated(&u->manager->watch_pids1, NULL);
- if (r < 0)
- return r;
-
- r = hashmap_put(u->manager->watch_pids1, LONG_TO_PTR(pid), u);
- if (r == -EEXIST) {
- r = hashmap_ensure_allocated(&u->manager->watch_pids2, NULL);
- if (r < 0)
- return r;
-
- r = hashmap_put(u->manager->watch_pids2, LONG_TO_PTR(pid), u);
- }
-
- q = set_put(u->pids, LONG_TO_PTR(pid));
- if (q < 0)
- return q;
-
- return r;
-}
-
-void unit_unwatch_pid(Unit *u, pid_t pid) {
- assert(u);
- assert(pid >= 1);
-
- hashmap_remove_value(u->manager->watch_pids1, LONG_TO_PTR(pid), u);
- hashmap_remove_value(u->manager->watch_pids2, LONG_TO_PTR(pid), u);
- set_remove(u->pids, LONG_TO_PTR(pid));
-}
-
-void unit_unwatch_all_pids(Unit *u) {
- assert(u);
-
- while (!set_isempty(u->pids))
- unit_unwatch_pid(u, PTR_TO_LONG(set_first(u->pids)));
-
- set_free(u->pids);
- u->pids = NULL;
-}
-
-static int unit_watch_pids_in_path(Unit *u, const char *path) {
- _cleanup_closedir_ DIR *d = NULL;
- _cleanup_fclose_ FILE *f = NULL;
- int ret = 0, r;
-
- assert(u);
- assert(path);
-
- /* Adds all PIDs from a specific cgroup path to the set of PIDs we watch. */
-
- r = cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, path, &f);
- if (r >= 0) {
- pid_t pid;
-
- while ((r = cg_read_pid(f, &pid)) > 0) {
- r = unit_watch_pid(u, pid);
- if (r < 0 && ret >= 0)
- ret = r;
- }
- if (r < 0 && ret >= 0)
- ret = r;
-
- } else if (ret >= 0)
- ret = r;
-
- r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, path, &d);
- if (r >= 0) {
- char *fn;
-
- while ((r = cg_read_subgroup(d, &fn)) > 0) {
- _cleanup_free_ char *p = NULL;
-
- p = strjoin(path, "/", fn, NULL);
- free(fn);
-
- if (!p)
- return -ENOMEM;
-
- r = unit_watch_pids_in_path(u, p);
- if (r < 0 && ret >= 0)
- ret = r;
- }
- if (r < 0 && ret >= 0)
- ret = r;
-
- } else if (ret >= 0)
- ret = r;
-
- return ret;
-}
-
-int unit_watch_all_pids(Unit *u) {
- assert(u);
-
- /* Adds all PIDs from our cgroup to the set of PIDs we watch */
-
- if (!u->cgroup_path)
- return -ENOENT;
-
- return unit_watch_pids_in_path(u, u->cgroup_path);
-}
-
-void unit_tidy_watch_pids(Unit *u, pid_t except1, pid_t except2) {
- Iterator i;
- void *e;
-
- assert(u);
-
- /* Cleans dead PIDs from our list */
-
- SET_FOREACH(e, u->pids, i) {
- pid_t pid = PTR_TO_LONG(e);
-
- if (pid == except1 || pid == except2)
- continue;
-
- if (!pid_is_unwaited(pid))
- unit_unwatch_pid(u, pid);
- }
-}
-
-bool unit_job_is_applicable(Unit *u, JobType j) {
- assert(u);
- assert(j >= 0 && j < _JOB_TYPE_MAX);
-
- switch (j) {
-
- case JOB_VERIFY_ACTIVE:
- case JOB_START:
- case JOB_STOP:
- case JOB_NOP:
- return true;
-
- case JOB_RESTART:
- case JOB_TRY_RESTART:
- return unit_can_start(u);
-
- case JOB_RELOAD:
- return unit_can_reload(u);
-
- case JOB_RELOAD_OR_START:
- return unit_can_reload(u) && unit_can_start(u);
-
- default:
- assert_not_reached("Invalid job type");
- }
-}
-
-static int maybe_warn_about_dependency(const char *id, const char *other, UnitDependency dependency) {
- assert(id);
-
- switch (dependency) {
- case UNIT_REQUIRES:
- case UNIT_REQUIRES_OVERRIDABLE:
- case UNIT_WANTS:
- case UNIT_REQUISITE:
- case UNIT_REQUISITE_OVERRIDABLE:
- case UNIT_BINDS_TO:
- case UNIT_PART_OF:
- case UNIT_REQUIRED_BY:
- case UNIT_REQUIRED_BY_OVERRIDABLE:
- case UNIT_WANTED_BY:
- case UNIT_BOUND_BY:
- case UNIT_CONSISTS_OF:
- case UNIT_REFERENCES:
- case UNIT_REFERENCED_BY:
- case UNIT_PROPAGATES_RELOAD_TO:
- case UNIT_RELOAD_PROPAGATED_FROM:
- case UNIT_JOINS_NAMESPACE_OF:
- return 0;
-
- case UNIT_CONFLICTS:
- case UNIT_CONFLICTED_BY:
- case UNIT_BEFORE:
- case UNIT_AFTER:
- case UNIT_ON_FAILURE:
- case UNIT_TRIGGERS:
- case UNIT_TRIGGERED_BY:
- if (streq_ptr(id, other))
- log_unit_warning(id, "Dependency %s=%s dropped from unit %s",
- unit_dependency_to_string(dependency), id, other);
- else
- log_unit_warning(id, "Dependency %s=%s dropped from unit %s merged into %s",
- unit_dependency_to_string(dependency), id,
- strna(other), id);
- return -EINVAL;
-
- case _UNIT_DEPENDENCY_MAX:
- case _UNIT_DEPENDENCY_INVALID:
- break;
- }
-
- assert_not_reached("Invalid dependency type");
-}
-
-int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_reference) {
-
- static const UnitDependency inverse_table[_UNIT_DEPENDENCY_MAX] = {
- [UNIT_REQUIRES] = UNIT_REQUIRED_BY,
- [UNIT_REQUIRES_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE,
- [UNIT_WANTS] = UNIT_WANTED_BY,
- [UNIT_REQUISITE] = UNIT_REQUIRED_BY,
- [UNIT_REQUISITE_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE,
- [UNIT_BINDS_TO] = UNIT_BOUND_BY,
- [UNIT_PART_OF] = UNIT_CONSISTS_OF,
- [UNIT_REQUIRED_BY] = _UNIT_DEPENDENCY_INVALID,
- [UNIT_REQUIRED_BY_OVERRIDABLE] = _UNIT_DEPENDENCY_INVALID,
- [UNIT_WANTED_BY] = _UNIT_DEPENDENCY_INVALID,
- [UNIT_BOUND_BY] = UNIT_BINDS_TO,
- [UNIT_CONSISTS_OF] = UNIT_PART_OF,
- [UNIT_CONFLICTS] = UNIT_CONFLICTED_BY,
- [UNIT_CONFLICTED_BY] = UNIT_CONFLICTS,
- [UNIT_BEFORE] = UNIT_AFTER,
- [UNIT_AFTER] = UNIT_BEFORE,
- [UNIT_ON_FAILURE] = _UNIT_DEPENDENCY_INVALID,
- [UNIT_REFERENCES] = UNIT_REFERENCED_BY,
- [UNIT_REFERENCED_BY] = UNIT_REFERENCES,
- [UNIT_TRIGGERS] = UNIT_TRIGGERED_BY,
- [UNIT_TRIGGERED_BY] = UNIT_TRIGGERS,
- [UNIT_PROPAGATES_RELOAD_TO] = UNIT_RELOAD_PROPAGATED_FROM,
- [UNIT_RELOAD_PROPAGATED_FROM] = UNIT_PROPAGATES_RELOAD_TO,
- [UNIT_JOINS_NAMESPACE_OF] = UNIT_JOINS_NAMESPACE_OF,
- };
- int r, q = 0, v = 0, w = 0;
- Unit *orig_u = u, *orig_other = other;
-
- assert(u);
- assert(d >= 0 && d < _UNIT_DEPENDENCY_MAX);
- assert(other);
-
- u = unit_follow_merge(u);
- other = unit_follow_merge(other);
-
- /* We won't allow dependencies on ourselves. We will not
- * consider them an error however. */
- if (u == other) {
- maybe_warn_about_dependency(orig_u->id, orig_other->id, d);
- return 0;
- }
-
- r = set_ensure_allocated(&u->dependencies[d], NULL);
- if (r < 0)
- return r;
-
- if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID) {
- r = set_ensure_allocated(&other->dependencies[inverse_table[d]], NULL);
- if (r < 0)
- return r;
- }
-
- if (add_reference) {
- r = set_ensure_allocated(&u->dependencies[UNIT_REFERENCES], NULL);
- if (r < 0)
- return r;
-
- r = set_ensure_allocated(&other->dependencies[UNIT_REFERENCED_BY], NULL);
- if (r < 0)
- return r;
- }
-
- q = set_put(u->dependencies[d], other);
- if (q < 0)
- return q;
-
- if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID && inverse_table[d] != d) {
- v = set_put(other->dependencies[inverse_table[d]], u);
- if (v < 0) {
- r = v;
- goto fail;
- }
- }
-
- if (add_reference) {
- w = set_put(u->dependencies[UNIT_REFERENCES], other);
- if (w < 0) {
- r = w;
- goto fail;
- }
-
- r = set_put(other->dependencies[UNIT_REFERENCED_BY], u);
- if (r < 0)
- goto fail;
- }
-
- unit_add_to_dbus_queue(u);
- return 0;
-
-fail:
- if (q > 0)
- set_remove(u->dependencies[d], other);
-
- if (v > 0)
- set_remove(other->dependencies[inverse_table[d]], u);
-
- if (w > 0)
- set_remove(u->dependencies[UNIT_REFERENCES], other);
-
- return r;
-}
-
-int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit *other, bool add_reference) {
- int r;
-
- assert(u);
-
- r = unit_add_dependency(u, d, other, add_reference);
- if (r < 0)
- return r;
-
- r = unit_add_dependency(u, e, other, add_reference);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-static const char *resolve_template(Unit *u, const char *name, const char*path, char **p) {
- char *s;
-
- assert(u);
- assert(name || path);
- assert(p);
-
- if (!name)
- name = basename(path);
-
- if (!unit_name_is_template(name)) {
- *p = NULL;
- return name;
- }
-
- if (u->instance)
- s = unit_name_replace_instance(name, u->instance);
- else {
- _cleanup_free_ char *i = NULL;
-
- i = unit_name_to_prefix(u->id);
- if (!i)
- return NULL;
-
- s = unit_name_replace_instance(name, i);
- }
-
- if (!s)
- return NULL;
-
- *p = s;
- return s;
-}
-
-int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) {
- Unit *other;
- int r;
- _cleanup_free_ char *s = NULL;
-
- assert(u);
- assert(name || path);
-
- name = resolve_template(u, name, path, &s);
- if (!name)
- return -ENOMEM;
-
- r = manager_load_unit(u->manager, name, path, NULL, &other);
- if (r < 0)
- return r;
-
- return unit_add_dependency(u, d, other, add_reference);
-}
-
-int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference) {
- _cleanup_free_ char *s = NULL;
- Unit *other;
- int r;
-
- assert(u);
- assert(name || path);
-
- name = resolve_template(u, name, path, &s);
- if (!name)
- return -ENOMEM;
-
- r = manager_load_unit(u->manager, name, path, NULL, &other);
- if (r < 0)
- return r;
-
- return unit_add_two_dependencies(u, d, e, other, add_reference);
-}
-
-int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) {
- Unit *other;
- int r;
- _cleanup_free_ char *s = NULL;
-
- assert(u);
- assert(name || path);
-
- name = resolve_template(u, name, path, &s);
- if (!name)
- return -ENOMEM;
-
- r = manager_load_unit(u->manager, name, path, NULL, &other);
- if (r < 0)
- return r;
-
- return unit_add_dependency(other, d, u, add_reference);
-}
-
-int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference) {
- Unit *other;
- int r;
- _cleanup_free_ char *s = NULL;
-
- assert(u);
- assert(name || path);
-
- name = resolve_template(u, name, path, &s);
- if (!name)
- return -ENOMEM;
-
- r = manager_load_unit(u->manager, name, path, NULL, &other);
- if (r < 0)
- return r;
-
- r = unit_add_two_dependencies(other, d, e, u, add_reference);
- if (r < 0)
- return r;
-
- return r;
-}
-
-int set_unit_path(const char *p) {
- /* This is mostly for debug purposes */
- if (setenv("SYSTEMD_UNIT_PATH", p, 0) < 0)
- return -errno;
-
- return 0;
-}
-
-char *unit_dbus_path(Unit *u) {
- assert(u);
-
- if (!u->id)
- return NULL;
-
- return unit_dbus_path_from_name(u->id);
-}
-
-char *unit_default_cgroup_path(Unit *u) {
- _cleanup_free_ char *escaped = NULL, *slice = NULL;
- int r;
-
- assert(u);
-
- if (unit_has_name(u, SPECIAL_ROOT_SLICE))
- return strdup(u->manager->cgroup_root);
-
- if (UNIT_ISSET(u->slice) && !unit_has_name(UNIT_DEREF(u->slice), SPECIAL_ROOT_SLICE)) {
- r = cg_slice_to_path(UNIT_DEREF(u->slice)->id, &slice);
- if (r < 0)
- return NULL;
- }
-
- escaped = cg_escape(u->id);
- if (!escaped)
- return NULL;
-
- if (slice)
- return strjoin(u->manager->cgroup_root, "/", slice, "/", escaped, NULL);
- else
- return strjoin(u->manager->cgroup_root, "/", escaped, NULL);
-}
-
-int unit_add_default_slice(Unit *u, CGroupContext *c) {
- _cleanup_free_ char *b = NULL;
- const char *slice_name;
- Unit *slice;
- int r;
-
- assert(u);
- assert(c);
-
- if (UNIT_ISSET(u->slice))
- return 0;
-
- if (u->instance) {
- _cleanup_free_ char *prefix = NULL, *escaped = NULL;
-
- /* Implicitly place all instantiated units in their
- * own per-template slice */
-
- prefix = unit_name_to_prefix(u->id);
- if (!prefix)
- return -ENOMEM;
-
- /* The prefix is already escaped, but it might include
- * "-" which has a special meaning for slice units,
- * hence escape it here extra. */
- escaped = strreplace(prefix, "-", "\\x2d");
- if (!escaped)
- return -ENOMEM;
-
- if (u->manager->running_as == SYSTEMD_SYSTEM)
- b = strjoin("system-", escaped, ".slice", NULL);
- else
- b = strappend(escaped, ".slice");
- if (!b)
- return -ENOMEM;
-
- slice_name = b;
- } else
- slice_name =
- u->manager->running_as == SYSTEMD_SYSTEM
- ? SPECIAL_SYSTEM_SLICE
- : SPECIAL_ROOT_SLICE;
-
- r = manager_load_unit(u->manager, slice_name, NULL, NULL, &slice);
- if (r < 0)
- return r;
-
- unit_ref_set(&u->slice, slice);
- return 0;
-}
-
-const char *unit_slice_name(Unit *u) {
- assert(u);
-
- if (!UNIT_ISSET(u->slice))
- return NULL;
-
- return UNIT_DEREF(u->slice)->id;
-}
-
-int unit_load_related_unit(Unit *u, const char *type, Unit **_found) {
- _cleanup_free_ char *t = NULL;
- int r;
-
- assert(u);
- assert(type);
- assert(_found);
-
- t = unit_name_change_suffix(u->id, type);
- if (!t)
- return -ENOMEM;
-
- assert(!unit_has_name(u, t));
-
- r = manager_load_unit(u->manager, t, NULL, NULL, _found);
- assert(r < 0 || *_found != u);
- return r;
-}
-
-int unit_watch_bus_name(Unit *u, const char *name) {
- assert(u);
- assert(name);
-
- /* Watch a specific name on the bus. We only support one unit
- * watching each name for now. */
-
- return hashmap_put(u->manager->watch_bus, name, u);
-}
-
-void unit_unwatch_bus_name(Unit *u, const char *name) {
- assert(u);
- assert(name);
-
- hashmap_remove_value(u->manager->watch_bus, name, u);
-}
-
-bool unit_can_serialize(Unit *u) {
- assert(u);
-
- return UNIT_VTABLE(u)->serialize && UNIT_VTABLE(u)->deserialize_item;
-}
-
-int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
- int r;
-
- assert(u);
- assert(f);
- assert(fds);
-
- if (unit_can_serialize(u)) {
- ExecRuntime *rt;
-
- r = UNIT_VTABLE(u)->serialize(u, f, fds);
- if (r < 0)
- return r;
-
- rt = unit_get_exec_runtime(u);
- if (rt) {
- r = exec_runtime_serialize(rt, u, f, fds);
- if (r < 0)
- return r;
- }
- }
-
- dual_timestamp_serialize(f, "inactive-exit-timestamp", &u->inactive_exit_timestamp);
- dual_timestamp_serialize(f, "active-enter-timestamp", &u->active_enter_timestamp);
- dual_timestamp_serialize(f, "active-exit-timestamp", &u->active_exit_timestamp);
- dual_timestamp_serialize(f, "inactive-enter-timestamp", &u->inactive_enter_timestamp);
- dual_timestamp_serialize(f, "condition-timestamp", &u->condition_timestamp);
- dual_timestamp_serialize(f, "assert-timestamp", &u->assert_timestamp);
-
- if (dual_timestamp_is_set(&u->condition_timestamp))
- unit_serialize_item(u, f, "condition-result", yes_no(u->condition_result));
-
- if (dual_timestamp_is_set(&u->assert_timestamp))
- unit_serialize_item(u, f, "assert-result", yes_no(u->assert_result));
-
- unit_serialize_item(u, f, "transient", yes_no(u->transient));
- unit_serialize_item_format(u, f, "cpuacct-usage-base", "%" PRIu64, u->cpuacct_usage_base);
-
- if (u->cgroup_path)
- unit_serialize_item(u, f, "cgroup", u->cgroup_path);
-
- if (serialize_jobs) {
- if (u->job) {
- fprintf(f, "job\n");
- job_serialize(u->job, f, fds);
- }
-
- if (u->nop_job) {
- fprintf(f, "job\n");
- job_serialize(u->nop_job, f, fds);
- }
- }
-
- /* End marker */
- fputc('\n', f);
- return 0;
-}
-
-void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *format, ...) {
- va_list ap;
-
- assert(u);
- assert(f);
- assert(key);
- assert(format);
-
- fputs(key, f);
- fputc('=', f);
-
- va_start(ap, format);
- vfprintf(f, format, ap);
- va_end(ap);
-
- fputc('\n', f);
-}
-
-void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) {
- assert(u);
- assert(f);
- assert(key);
- assert(value);
-
- fprintf(f, "%s=%s\n", key, value);
-}
-
-int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
- ExecRuntime **rt = NULL;
- size_t offset;
- int r;
-
- assert(u);
- assert(f);
- assert(fds);
-
- offset = UNIT_VTABLE(u)->exec_runtime_offset;
- if (offset > 0)
- rt = (ExecRuntime**) ((uint8_t*) u + offset);
-
- for (;;) {
- char line[LINE_MAX], *l, *v;
- size_t k;
-
- if (!fgets(line, sizeof(line), f)) {
- if (feof(f))
- return 0;
- return -errno;
- }
-
- char_array_0(line);
- l = strstrip(line);
-
- /* End marker */
- if (l[0] == 0)
- return 0;
-
- k = strcspn(l, "=");
-
- if (l[k] == '=') {
- l[k] = 0;
- v = l+k+1;
- } else
- v = l+k;
-
- if (streq(l, "job")) {
- if (v[0] == '\0') {
- /* new-style serialized job */
- Job *j;
-
- j = job_new_raw(u);
- if (!j)
- return -ENOMEM;
-
- r = job_deserialize(j, f, fds);
- if (r < 0) {
- job_free(j);
- return r;
- }
-
- r = hashmap_put(u->manager->jobs, UINT32_TO_PTR(j->id), j);
- if (r < 0) {
- job_free(j);
- return r;
- }
-
- r = job_install_deserialized(j);
- if (r < 0) {
- hashmap_remove(u->manager->jobs, UINT32_TO_PTR(j->id));
- job_free(j);
- return r;
- }
- } else {
- /* legacy */
- JobType type;
-
- type = job_type_from_string(v);
- if (type < 0)
- log_debug("Failed to parse job type value %s", v);
- else
- u->deserialized_job = type;
- }
- continue;
- } else if (streq(l, "inactive-exit-timestamp")) {
- dual_timestamp_deserialize(v, &u->inactive_exit_timestamp);
- continue;
- } else if (streq(l, "active-enter-timestamp")) {
- dual_timestamp_deserialize(v, &u->active_enter_timestamp);
- continue;
- } else if (streq(l, "active-exit-timestamp")) {
- dual_timestamp_deserialize(v, &u->active_exit_timestamp);
- continue;
- } else if (streq(l, "inactive-enter-timestamp")) {
- dual_timestamp_deserialize(v, &u->inactive_enter_timestamp);
- continue;
- } else if (streq(l, "condition-timestamp")) {
- dual_timestamp_deserialize(v, &u->condition_timestamp);
- continue;
- } else if (streq(l, "assert-timestamp")) {
- dual_timestamp_deserialize(v, &u->assert_timestamp);
- continue;
- } else if (streq(l, "condition-result")) {
- int b;
-
- b = parse_boolean(v);
- if (b < 0)
- log_debug("Failed to parse condition result value %s", v);
- else
- u->condition_result = b;
-
- continue;
-
- } else if (streq(l, "assert-result")) {
- int b;
-
- b = parse_boolean(v);
- if (b < 0)
- log_debug("Failed to parse assert result value %s", v);
- else
- u->assert_result = b;
-
- continue;
-
- } else if (streq(l, "transient")) {
- int b;
-
- b = parse_boolean(v);
- if (b < 0)
- log_debug("Failed to parse transient bool %s", v);
- else
- u->transient = b;
-
- continue;
- } else if (streq(l, "cpuacct-usage-base")) {
-
- r = safe_atou64(v, &u->cpuacct_usage_base);
- if (r < 0)
- log_debug("Failed to parse CPU usage %s", v);
-
- } else if (streq(l, "cgroup")) {
- char *s;
-
- s = strdup(v);
- if (!s)
- return -ENOMEM;
-
- if (u->cgroup_path) {
- void *p;
-
- p = hashmap_remove(u->manager->cgroup_unit, u->cgroup_path);
- log_info("Removing cgroup_path %s from hashmap (%p)", u->cgroup_path, p);
- free(u->cgroup_path);
- }
-
- u->cgroup_path = s;
- assert(hashmap_put(u->manager->cgroup_unit, s, u) == 1);
-
- continue;
- }
-
- if (unit_can_serialize(u)) {
- if (rt) {
- r = exec_runtime_deserialize_item(rt, u, l, v, fds);
- if (r < 0)
- return r;
- if (r > 0)
- continue;
- }
-
- r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds);
- if (r < 0)
- return r;
- }
- }
-}
-
-int unit_add_node_link(Unit *u, const char *what, bool wants) {
- Unit *device;
- _cleanup_free_ char *e = NULL;
- int r;
-
- assert(u);
-
- if (!what)
- return 0;
-
- /* Adds in links to the device node that this unit is based on */
-
- if (!is_device_path(what))
- return 0;
-
- e = unit_name_from_path(what, ".device");
- if (!e)
- return -ENOMEM;
-
- r = manager_load_unit(u->manager, e, NULL, NULL, &device);
- if (r < 0)
- return r;
-
- r = unit_add_two_dependencies(u, UNIT_AFTER, u->manager->running_as == SYSTEMD_SYSTEM ? UNIT_BINDS_TO : UNIT_WANTS, device, true);
- if (r < 0)
- return r;
-
- if (wants) {
- r = unit_add_dependency(device, UNIT_WANTS, u, false);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-static int unit_add_deserialized_job_coldplug(Unit *u) {
- int r;
-
- r = manager_add_job(u->manager, u->deserialized_job, u, JOB_IGNORE_REQUIREMENTS, false, NULL, NULL);
- if (r < 0)
- return r;
-
- u->deserialized_job = _JOB_TYPE_INVALID;
-
- return 0;
-}
-
-int unit_coldplug(Unit *u, Hashmap *deferred_work) {
- int r;
-
- assert(u);
-
- if (UNIT_VTABLE(u)->coldplug)
- if ((r = UNIT_VTABLE(u)->coldplug(u, deferred_work)) < 0)
- return r;
-
- if (u->job) {
- r = job_coldplug(u->job);
- if (r < 0)
- return r;
- } else if (u->deserialized_job >= 0)
- /* legacy */
- hashmap_put(deferred_work, u, &unit_add_deserialized_job_coldplug);
-
- return 0;
-}
-
-void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) {
- DISABLE_WARNING_FORMAT_NONLITERAL;
- manager_status_printf(u->manager, STATUS_TYPE_NORMAL,
- status, unit_status_msg_format, unit_description(u));
- REENABLE_WARNING;
-}
-
-bool unit_need_daemon_reload(Unit *u) {
- _cleanup_strv_free_ char **t = NULL;
- char **path;
- struct stat st;
- unsigned loaded_cnt, current_cnt;
-
- assert(u);
-
- if (u->fragment_path) {
- zero(st);
- if (stat(u->fragment_path, &st) < 0)
- /* What, cannot access this anymore? */
- return true;
-
- if (u->fragment_mtime > 0 &&
- timespec_load(&st.st_mtim) != u->fragment_mtime)
- return true;
- }
-
- if (u->source_path) {
- zero(st);
- if (stat(u->source_path, &st) < 0)
- return true;
-
- if (u->source_mtime > 0 &&
- timespec_load(&st.st_mtim) != u->source_mtime)
- return true;
- }
-
- (void) unit_find_dropin_paths(u, &t);
- loaded_cnt = strv_length(t);
- current_cnt = strv_length(u->dropin_paths);
-
- if (loaded_cnt == current_cnt) {
- if (loaded_cnt == 0)
- return false;
-
- if (strv_overlap(u->dropin_paths, t)) {
- STRV_FOREACH(path, u->dropin_paths) {
- zero(st);
- if (stat(*path, &st) < 0)
- return true;
-
- if (u->dropin_mtime > 0 &&
- timespec_load(&st.st_mtim) > u->dropin_mtime)
- return true;
- }
-
- return false;
- } else
- return true;
- } else
- return true;
-}
-
-void unit_reset_failed(Unit *u) {
- assert(u);
-
- if (UNIT_VTABLE(u)->reset_failed)
- UNIT_VTABLE(u)->reset_failed(u);
-}
-
-Unit *unit_following(Unit *u) {
- assert(u);
-
- if (UNIT_VTABLE(u)->following)
- return UNIT_VTABLE(u)->following(u);
-
- return NULL;
-}
-
-bool unit_stop_pending(Unit *u) {
- assert(u);
-
- /* This call does check the current state of the unit. It's
- * hence useful to be called from state change calls of the
- * unit itself, where the state isn't updated yet. This is
- * different from unit_inactive_or_pending() which checks both
- * the current state and for a queued job. */
-
- return u->job && u->job->type == JOB_STOP;
-}
-
-bool unit_inactive_or_pending(Unit *u) {
- assert(u);
-
- /* Returns true if the unit is inactive or going down */
-
- if (UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u)))
- return true;
-
- if (unit_stop_pending(u))
- return true;
-
- return false;
-}
-
-bool unit_active_or_pending(Unit *u) {
- assert(u);
-
- /* Returns true if the unit is active or going up */
-
- if (UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)))
- return true;
-
- if (u->job &&
- (u->job->type == JOB_START ||
- u->job->type == JOB_RELOAD_OR_START ||
- u->job->type == JOB_RESTART))
- return true;
-
- return false;
-}
-
-int unit_kill(Unit *u, KillWho w, int signo, sd_bus_error *error) {
- assert(u);
- assert(w >= 0 && w < _KILL_WHO_MAX);
- assert(signo > 0);
- assert(signo < _NSIG);
-
- if (!UNIT_VTABLE(u)->kill)
- return -EOPNOTSUPP;
-
- return UNIT_VTABLE(u)->kill(u, w, signo, error);
-}
-
-static Set *unit_pid_set(pid_t main_pid, pid_t control_pid) {
- Set *pid_set;
- int r;
-
- pid_set = set_new(NULL);
- if (!pid_set)
- return NULL;
-
- /* Exclude the main/control pids from being killed via the cgroup */
- if (main_pid > 0) {
- r = set_put(pid_set, LONG_TO_PTR(main_pid));
- if (r < 0)
- goto fail;
- }
-
- if (control_pid > 0) {
- r = set_put(pid_set, LONG_TO_PTR(control_pid));
- if (r < 0)
- goto fail;
- }
-
- return pid_set;
-
-fail:
- set_free(pid_set);
- return NULL;
-}
-
-int unit_kill_common(
- Unit *u,
- KillWho who,
- int signo,
- pid_t main_pid,
- pid_t control_pid,
- sd_bus_error *error) {
-
- int r = 0;
-
- if (who == KILL_MAIN && main_pid <= 0) {
- if (main_pid < 0)
- return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no main processes", unit_type_to_string(u->type));
- else
- return sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No main process to kill");
- }
-
- if (who == KILL_CONTROL && control_pid <= 0) {
- if (control_pid < 0)
- return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_PROCESS, "%s units have no control processes", unit_type_to_string(u->type));
- else
- return sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
- }
-
- if (who == KILL_CONTROL || who == KILL_ALL)
- if (control_pid > 0)
- if (kill(control_pid, signo) < 0)
- r = -errno;
-
- if (who == KILL_MAIN || who == KILL_ALL)
- if (main_pid > 0)
- if (kill(main_pid, signo) < 0)
- r = -errno;
-
- if (who == KILL_ALL && u->cgroup_path) {
- _cleanup_set_free_ Set *pid_set = NULL;
- int q;
-
- /* Exclude the main/control pids from being killed via the cgroup */
- pid_set = unit_pid_set(main_pid, control_pid);
- if (!pid_set)
- return -ENOMEM;
-
- q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, false, true, false, pid_set);
- if (q < 0 && q != -EAGAIN && q != -ESRCH && q != -ENOENT)
- r = q;
- }
-
- return r;
-}
-
-int unit_following_set(Unit *u, Set **s) {
- assert(u);
- assert(s);
-
- if (UNIT_VTABLE(u)->following_set)
- return UNIT_VTABLE(u)->following_set(u, s);
-
- *s = NULL;
- return 0;
-}
-
-UnitFileState unit_get_unit_file_state(Unit *u) {
- assert(u);
-
- if (u->unit_file_state < 0 && u->fragment_path)
- u->unit_file_state = unit_file_get_state(
- u->manager->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER,
- NULL, basename(u->fragment_path));
-
- return u->unit_file_state;
-}
-
-int unit_get_unit_file_preset(Unit *u) {
- assert(u);
-
- if (u->unit_file_preset < 0 && u->fragment_path)
- u->unit_file_preset = unit_file_query_preset(
- u->manager->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER,
- NULL, basename(u->fragment_path));
-
- return u->unit_file_preset;
-}
-
-Unit* unit_ref_set(UnitRef *ref, Unit *u) {
- assert(ref);
- assert(u);
-
- if (ref->unit)
- unit_ref_unset(ref);
-
- ref->unit = u;
- LIST_PREPEND(refs, u->refs, ref);
- return u;
-}
-
-void unit_ref_unset(UnitRef *ref) {
- assert(ref);
-
- if (!ref->unit)
- return;
-
- LIST_REMOVE(refs, ref->unit->refs, ref);
- ref->unit = NULL;
-}
-
-int unit_patch_contexts(Unit *u) {
- CGroupContext *cc;
- ExecContext *ec;
- unsigned i;
- int r;
-
- assert(u);
-
- /* Patch in the manager defaults into the exec and cgroup
- * contexts, _after_ the rest of the settings have been
- * initialized */
-
- ec = unit_get_exec_context(u);
- if (ec) {
- /* This only copies in the ones that need memory */
- for (i = 0; i < _RLIMIT_MAX; i++)
- if (u->manager->rlimit[i] && !ec->rlimit[i]) {
- ec->rlimit[i] = newdup(struct rlimit, u->manager->rlimit[i], 1);
- if (!ec->rlimit[i])
- return -ENOMEM;
- }
-
- if (u->manager->running_as == SYSTEMD_USER &&
- !ec->working_directory) {
-
- r = get_home_dir(&ec->working_directory);
- if (r < 0)
- return r;
-
- /* Allow user services to run, even if the
- * home directory is missing */
- ec->working_directory_missing_ok = true;
- }
-
- if (u->manager->running_as == SYSTEMD_USER &&
- (ec->syscall_whitelist ||
- !set_isempty(ec->syscall_filter) ||
- !set_isempty(ec->syscall_archs) ||
- ec->address_families_whitelist ||
- !set_isempty(ec->address_families)))
- ec->no_new_privileges = true;
-
- if (ec->private_devices)
- ec->capability_bounding_set_drop |= (uint64_t) 1ULL << (uint64_t) CAP_MKNOD;
- }
-
- cc = unit_get_cgroup_context(u);
- if (cc) {
-
- if (ec &&
- ec->private_devices &&
- cc->device_policy == CGROUP_AUTO)
- cc->device_policy = CGROUP_CLOSED;
- }
-
- return 0;
-}
-
-ExecContext *unit_get_exec_context(Unit *u) {
- size_t offset;
- assert(u);
-
- if (u->type < 0)
- return NULL;
-
- offset = UNIT_VTABLE(u)->exec_context_offset;
- if (offset <= 0)
- return NULL;
-
- return (ExecContext*) ((uint8_t*) u + offset);
-}
-
-KillContext *unit_get_kill_context(Unit *u) {
- size_t offset;
- assert(u);
-
- if (u->type < 0)
- return NULL;
-
- offset = UNIT_VTABLE(u)->kill_context_offset;
- if (offset <= 0)
- return NULL;
-
- return (KillContext*) ((uint8_t*) u + offset);
-}
-
-CGroupContext *unit_get_cgroup_context(Unit *u) {
- size_t offset;
-
- if (u->type < 0)
- return NULL;
-
- offset = UNIT_VTABLE(u)->cgroup_context_offset;
- if (offset <= 0)
- return NULL;
-
- return (CGroupContext*) ((uint8_t*) u + offset);
-}
-
-ExecRuntime *unit_get_exec_runtime(Unit *u) {
- size_t offset;
-
- if (u->type < 0)
- return NULL;
-
- offset = UNIT_VTABLE(u)->exec_runtime_offset;
- if (offset <= 0)
- return NULL;
-
- return *(ExecRuntime**) ((uint8_t*) u + offset);
-}
-
-static int unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode, bool transient, char **dir) {
- if (u->manager->running_as == SYSTEMD_USER) {
- int r;
-
- if (mode == UNIT_PERSISTENT && !transient)
- r = user_config_home(dir);
- else
- r = user_runtime_dir(dir);
-
- if (r == 0)
- return -ENOENT;
- return r;
- }
-
- if (mode == UNIT_PERSISTENT && !transient)
- *dir = strdup("/etc/systemd/system");
- else
- *dir = strdup("/run/systemd/system");
- if (!*dir)
- return -ENOMEM;
-
- return 0;
-}
-
-static int unit_drop_in_file(Unit *u,
- UnitSetPropertiesMode mode, const char *name, char **p, char **q) {
- _cleanup_free_ char *dir = NULL;
- int r;
-
- assert(u);
-
- r = unit_drop_in_dir(u, mode, u->transient, &dir);
- if (r < 0)
- return r;
-
- return drop_in_file(dir, u->id, 50, name, p, q);
-}
-
-int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) {
-
- _cleanup_free_ char *dir = NULL, *p = NULL, *q = NULL;
- int r;
-
- assert(u);
-
- if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME))
- return 0;
-
- r = unit_drop_in_dir(u, mode, u->transient, &dir);
- if (r < 0)
- return r;
-
- r = write_drop_in(dir, u->id, 50, name, data);
- if (r < 0)
- return r;
-
- r = drop_in_file(dir, u->id, 50, name, &p, &q);
- if (r < 0)
- return r;
-
- r = strv_extend(&u->dropin_paths, q);
- if (r < 0)
- return r;
-
- strv_sort(u->dropin_paths);
- strv_uniq(u->dropin_paths);
-
- u->dropin_mtime = now(CLOCK_REALTIME);
-
- return 0;
-}
-
-int unit_write_drop_in_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) {
- _cleanup_free_ char *p = NULL;
- va_list ap;
- int r;
-
- assert(u);
- assert(name);
- assert(format);
-
- if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME))
- return 0;
-
- va_start(ap, format);
- r = vasprintf(&p, format, ap);
- va_end(ap);
-
- if (r < 0)
- return -ENOMEM;
-
- return unit_write_drop_in(u, mode, name, p);
-}
-
-int unit_write_drop_in_private(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) {
- _cleanup_free_ char *ndata = NULL;
-
- assert(u);
- assert(name);
- assert(data);
-
- if (!UNIT_VTABLE(u)->private_section)
- return -EINVAL;
-
- if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME))
- return 0;
-
- ndata = strjoin("[", UNIT_VTABLE(u)->private_section, "]\n", data, NULL);
- if (!ndata)
- return -ENOMEM;
-
- return unit_write_drop_in(u, mode, name, ndata);
-}
-
-int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) {
- _cleanup_free_ char *p = NULL;
- va_list ap;
- int r;
-
- assert(u);
- assert(name);
- assert(format);
-
- if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME))
- return 0;
-
- va_start(ap, format);
- r = vasprintf(&p, format, ap);
- va_end(ap);
-
- if (r < 0)
- return -ENOMEM;
-
- return unit_write_drop_in_private(u, mode, name, p);
-}
-
-int unit_remove_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name) {
- _cleanup_free_ char *p = NULL, *q = NULL;
- int r;
-
- assert(u);
-
- if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME))
- return 0;
-
- r = unit_drop_in_file(u, mode, name, &p, &q);
- if (r < 0)
- return r;
-
- if (unlink(q) < 0)
- r = errno == ENOENT ? 0 : -errno;
- else
- r = 1;
-
- rmdir(p);
- return r;
-}
-
-int unit_make_transient(Unit *u) {
- int r;
-
- assert(u);
-
- u->load_state = UNIT_STUB;
- u->load_error = 0;
- u->transient = true;
-
- free(u->fragment_path);
- u->fragment_path = NULL;
-
- if (u->manager->running_as == SYSTEMD_USER) {
- _cleanup_free_ char *c = NULL;
-
- r = user_runtime_dir(&c);
- if (r < 0)
- return r;
- if (r == 0)
- return -ENOENT;
-
- u->fragment_path = strjoin(c, "/", u->id, NULL);
- if (!u->fragment_path)
- return -ENOMEM;
-
- mkdir_p(c, 0755);
- } else {
- u->fragment_path = strappend("/run/systemd/system/", u->id);
- if (!u->fragment_path)
- return -ENOMEM;
-
- mkdir_p("/run/systemd/system", 0755);
- }
-
- return write_string_file_atomic_label(u->fragment_path, "# Transient stub");
-}
-
-int unit_kill_context(
- Unit *u,
- KillContext *c,
- KillOperation k,
- pid_t main_pid,
- pid_t control_pid,
- bool main_pid_alien) {
-
- int sig, wait_for_exit = false, r;
-
- assert(u);
- assert(c);
-
- if (c->kill_mode == KILL_NONE)
- return 0;
-
- switch (k) {
- case KILL_KILL:
- sig = SIGKILL;
- break;
- case KILL_ABORT:
- sig = SIGABRT;
- break;
- case KILL_TERMINATE:
- sig = c->kill_signal;
- break;
- default:
- assert_not_reached("KillOperation unknown");
- }
-
- if (main_pid > 0) {
- r = kill_and_sigcont(main_pid, sig);
-
- if (r < 0 && r != -ESRCH) {
- _cleanup_free_ char *comm = NULL;
- get_process_comm(main_pid, &comm);
-
- log_unit_warning_errno(u->id, r, "Failed to kill main process " PID_FMT " (%s): %m", main_pid, strna(comm));
- } else {
- if (!main_pid_alien)
- wait_for_exit = true;
-
- if (c->send_sighup && k != KILL_KILL)
- kill(main_pid, SIGHUP);
- }
- }
-
- if (control_pid > 0) {
- r = kill_and_sigcont(control_pid, sig);
-
- if (r < 0 && r != -ESRCH) {
- _cleanup_free_ char *comm = NULL;
- get_process_comm(control_pid, &comm);
-
- log_unit_warning_errno(u->id, r, "Failed to kill control process " PID_FMT " (%s): %m", control_pid, strna(comm));
- } else {
- wait_for_exit = true;
-
- if (c->send_sighup && k != KILL_KILL)
- kill(control_pid, SIGHUP);
- }
- }
-
- if ((c->kill_mode == KILL_CONTROL_GROUP || (c->kill_mode == KILL_MIXED && k == KILL_KILL)) && u->cgroup_path) {
- _cleanup_set_free_ Set *pid_set = NULL;
-
- /* Exclude the main/control pids from being killed via the cgroup */
- pid_set = unit_pid_set(main_pid, control_pid);
- if (!pid_set)
- return -ENOMEM;
-
- r = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, sig, true, true, false, pid_set);
- if (r < 0) {
- if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
- log_unit_warning_errno(u->id, r, "Failed to kill control group: %m");
- } else if (r > 0) {
-
- /* FIXME: For now, we will not wait for the
- * cgroup members to die, simply because
- * cgroup notification is unreliable. It
- * doesn't work at all in containers, and
- * outside of containers it can be confused
- * easily by leaving directories in the
- * cgroup. */
-
- /* wait_for_exit = true; */
-
- if (c->send_sighup && k != KILL_KILL) {
- set_free(pid_set);
-
- pid_set = unit_pid_set(main_pid, control_pid);
- if (!pid_set)
- return -ENOMEM;
-
- cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, SIGHUP, false, true, false, pid_set);
- }
- }
- }
-
- return wait_for_exit;
-}
-
-int unit_require_mounts_for(Unit *u, const char *path) {
- char prefix[strlen(path) + 1], *p;
- int r;
-
- assert(u);
- assert(path);
-
- /* Registers a unit for requiring a certain path and all its
- * prefixes. We keep a simple array of these paths in the
- * unit, since its usually short. However, we build a prefix
- * table for all possible prefixes so that new appearing mount
- * units can easily determine which units to make themselves a
- * dependency of. */
-
- if (!path_is_absolute(path))
- return -EINVAL;
-
- p = strdup(path);
- if (!p)
- return -ENOMEM;
-
- path_kill_slashes(p);
-
- if (!path_is_safe(p)) {
- free(p);
- return -EPERM;
- }
-
- if (strv_contains(u->requires_mounts_for, p)) {
- free(p);
- return 0;
- }
-
- r = strv_consume(&u->requires_mounts_for, p);
- if (r < 0)
- return r;
-
- PATH_FOREACH_PREFIX_MORE(prefix, p) {
- Set *x;
-
- x = hashmap_get(u->manager->units_requiring_mounts_for, prefix);
- if (!x) {
- char *q;
-
- if (!u->manager->units_requiring_mounts_for) {
- u->manager->units_requiring_mounts_for = hashmap_new(&string_hash_ops);
- if (!u->manager->units_requiring_mounts_for)
- return -ENOMEM;
- }
-
- q = strdup(prefix);
- if (!q)
- return -ENOMEM;
-
- x = set_new(NULL);
- if (!x) {
- free(q);
- return -ENOMEM;
- }
-
- r = hashmap_put(u->manager->units_requiring_mounts_for, q, x);
- if (r < 0) {
- free(q);
- set_free(x);
- return r;
- }
- }
-
- r = set_put(x, u);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-int unit_setup_exec_runtime(Unit *u) {
- ExecRuntime **rt;
- size_t offset;
- Iterator i;
- Unit *other;
-
- offset = UNIT_VTABLE(u)->exec_runtime_offset;
- assert(offset > 0);
-
- /* Check if there already is an ExecRuntime for this unit? */
- rt = (ExecRuntime**) ((uint8_t*) u + offset);
- if (*rt)
- return 0;
-
- /* Try to get it from somebody else */
- SET_FOREACH(other, u->dependencies[UNIT_JOINS_NAMESPACE_OF], i) {
-
- *rt = unit_get_exec_runtime(other);
- if (*rt) {
- exec_runtime_ref(*rt);
- return 0;
- }
- }
-
- return exec_runtime_make(rt, unit_get_exec_context(u), u->id);
-}
-
-static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = {
- [UNIT_ACTIVE] = "active",
- [UNIT_RELOADING] = "reloading",
- [UNIT_INACTIVE] = "inactive",
- [UNIT_FAILED] = "failed",
- [UNIT_ACTIVATING] = "activating",
- [UNIT_DEACTIVATING] = "deactivating"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(unit_active_state, UnitActiveState);
diff --git a/src/core/unit.h b/src/core/unit.h
deleted file mode 100644
index 11242c2a0..000000000
--- a/src/core/unit.h
+++ /dev/null
@@ -1,625 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#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 enum UnitActiveState UnitActiveState;
-typedef struct UnitRef UnitRef;
-typedef struct UnitStatusMessageFormats UnitStatusMessageFormats;
-
-#include "list.h"
-#include "condition.h"
-#include "install.h"
-#include "unit-name.h"
-#include "failure-action.h"
-
-enum UnitActiveState {
- UNIT_ACTIVE,
- UNIT_RELOADING,
- UNIT_INACTIVE,
- UNIT_FAILED,
- UNIT_ACTIVATING,
- UNIT_DEACTIVATING,
- _UNIT_ACTIVE_STATE_MAX,
- _UNIT_ACTIVE_STATE_INVALID = -1
-};
-
-typedef enum KillOperation {
- KILL_TERMINATE,
- KILL_KILL,
- KILL_ABORT,
-} KillOperation;
-
-static inline bool UNIT_IS_ACTIVE_OR_RELOADING(UnitActiveState t) {
- return t == UNIT_ACTIVE || t == UNIT_RELOADING;
-}
-
-static inline bool UNIT_IS_ACTIVE_OR_ACTIVATING(UnitActiveState t) {
- return t == UNIT_ACTIVE || t == UNIT_ACTIVATING || t == UNIT_RELOADING;
-}
-
-static inline bool UNIT_IS_INACTIVE_OR_DEACTIVATING(UnitActiveState t) {
- return t == UNIT_INACTIVE || t == UNIT_FAILED || t == UNIT_DEACTIVATING;
-}
-
-static inline bool UNIT_IS_INACTIVE_OR_FAILED(UnitActiveState t) {
- return t == UNIT_INACTIVE || t == UNIT_FAILED;
-}
-
-#include "job.h"
-
-struct UnitRef {
- /* Keeps tracks of references to a unit. This is useful so
- * that we can merge two units if necessary and correct all
- * references to them */
-
- Unit* unit;
- LIST_FIELDS(UnitRef, refs);
-};
-
-struct Unit {
- Manager *manager;
-
- UnitType type;
- UnitLoadState load_state;
- Unit *merged_into;
-
- char *id; /* One name is special because we use it for identification. Points to an entry in the names set */
- char *instance;
-
- Set *names;
- Set *dependencies[_UNIT_DEPENDENCY_MAX];
-
- char **requires_mounts_for;
-
- char *description;
- char **documentation;
-
- char *fragment_path; /* if loaded from a config file this is the primary path to it */
- char *source_path; /* if converted, the source file */
- char **dropin_paths;
- usec_t fragment_mtime;
- usec_t source_mtime;
- usec_t dropin_mtime;
-
- /* If there is something to do with this unit, then this is the installed job for it */
- Job *job;
-
- /* JOB_NOP jobs are special and can be installed without disturbing the real job. */
- Job *nop_job;
-
- /* Job timeout and action to take */
- usec_t job_timeout;
- FailureAction job_timeout_action;
- char *job_timeout_reboot_arg;
-
- /* References to this */
- LIST_HEAD(UnitRef, refs);
-
- /* Conditions to check */
- LIST_HEAD(Condition, conditions);
- LIST_HEAD(Condition, asserts);
-
- dual_timestamp condition_timestamp;
- dual_timestamp assert_timestamp;
-
- dual_timestamp inactive_exit_timestamp;
- dual_timestamp active_enter_timestamp;
- dual_timestamp active_exit_timestamp;
- dual_timestamp inactive_enter_timestamp;
-
- UnitRef slice;
-
- /* Per type list */
- LIST_FIELDS(Unit, units_by_type);
-
- /* All units which have requires_mounts_for set */
- LIST_FIELDS(Unit, has_requires_mounts_for);
-
- /* Load queue */
- LIST_FIELDS(Unit, load_queue);
-
- /* D-Bus queue */
- LIST_FIELDS(Unit, dbus_queue);
-
- /* Cleanup queue */
- LIST_FIELDS(Unit, cleanup_queue);
-
- /* GC queue */
- LIST_FIELDS(Unit, gc_queue);
-
- /* CGroup realize members queue */
- LIST_FIELDS(Unit, cgroup_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 */
- Set *pids;
-
- /* Used during GC sweeps */
- unsigned gc_marker;
-
- /* When deserializing, temporarily store the job type for this
- * unit here, if there was a job scheduled.
- * Only for deserializing from a legacy version. New style uses full
- * serialized jobs. */
- int deserialized_job; /* This is actually of type JobType */
-
- /* Error code when we didn't manage to load the unit (negative) */
- int load_error;
-
- /* Cached unit file state and preset */
- UnitFileState unit_file_state;
- int unit_file_preset;
-
- /* Where the cpuacct.usage cgroup counter was at the time the unit was started */
- nsec_t cpuacct_usage_base;
-
- /* Counterparts in the cgroup filesystem */
- char *cgroup_path;
- CGroupControllerMask cgroup_realized_mask;
- CGroupControllerMask cgroup_subtree_mask;
- CGroupControllerMask cgroup_members_mask;
-
- /* How to start OnFailure units */
- JobMode on_failure_job_mode;
-
- /* Garbage collect us we nobody wants or requires us anymore */
- bool stop_when_unneeded;
-
- /* Create default dependencies */
- bool default_dependencies;
-
- /* Refuse manual starting, allow starting only indirectly via dependency. */
- bool refuse_manual_start;
-
- /* Don't allow the user to stop this unit manually, allow stopping only indirectly via dependency. */
- bool refuse_manual_stop;
-
- /* Allow isolation requests */
- bool allow_isolate;
-
- /* Ignore this unit when isolating */
- bool ignore_on_isolate;
-
- /* Ignore this unit when snapshotting */
- bool ignore_on_snapshot;
-
- /* Did the last condition check succeed? */
- bool condition_result;
- bool assert_result;
-
- /* Is this a transient unit? */
- bool transient;
-
- bool in_load_queue:1;
- bool in_dbus_queue:1;
- bool in_cleanup_queue:1;
- bool in_gc_queue:1;
- bool in_cgroup_queue:1;
-
- bool sent_dbus_new_signal:1;
-
- bool no_gc:1;
-
- bool in_audit:1;
-
- bool cgroup_realized:1;
- bool cgroup_members_mask_valid:1;
- bool cgroup_subtree_mask_valid:1;
-};
-
-struct UnitStatusMessageFormats {
- const char *starting_stopping[2];
- const char *finished_start_job[_JOB_RESULT_MAX];
- const char *finished_stop_job[_JOB_RESULT_MAX];
-};
-
-typedef enum UnitSetPropertiesMode {
- UNIT_CHECK = 0,
- UNIT_RUNTIME = 1,
- UNIT_PERSISTENT = 2,
-} UnitSetPropertiesMode;
-
-#include "socket.h"
-#include "busname.h"
-#include "target.h"
-#include "snapshot.h"
-#include "device.h"
-#include "automount.h"
-#include "swap.h"
-#include "timer.h"
-#include "slice.h"
-#include "path.h"
-#include "scope.h"
-
-struct UnitVTable {
- /* How much memory does an object of this unit type need */
- size_t object_size;
-
- /* If greater than 0, the offset into the object where
- * ExecContext is found, if the unit type has that */
- size_t exec_context_offset;
-
- /* If greater than 0, the offset into the object where
- * CGroupContext is found, if the unit type has that */
- size_t cgroup_context_offset;
-
- /* If greater than 0, the offset into the object where
- * KillContext is found, if the unit type has that */
- size_t kill_context_offset;
-
- /* If greater than 0, the offset into the object where the
- * pointer to ExecRuntime is found, if the unit type has
- * that */
- size_t exec_runtime_offset;
-
- /* The name of the configuration file section with the private settings of this unit */
- const char *private_section;
-
- /* Config file sections this unit type understands, separated
- * by NUL chars */
- const char *sections;
-
- /* This should reset all type-specific variables. This should
- * not allocate memory, and is called with zero-initialized
- * data. It should hence only initialize variables that need
- * to be set != 0. */
- void (*init)(Unit *u);
-
- /* This should free all type-specific variables. It should be
- * idempotent. */
- void (*done)(Unit *u);
-
- /* Actually load data from disk. This may fail, and should set
- * load_state to UNIT_LOADED, UNIT_MERGED or leave it at
- * 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().
- *
- * This must not reference other units (maybe implicitly through spawning
- * jobs), because it is possible that they are not yet coldplugged.
- * Such actions must be deferred until the end of coldplug bу adding
- * a "Unit* -> int(*)(Unit*)" entry into the hashmap.
- */
- int (*coldplug)(Unit *u, Hashmap *deferred_work);
-
- void (*dump)(Unit *u, FILE *f, const char *prefix);
-
- int (*start)(Unit *u);
- int (*stop)(Unit *u);
- int (*reload)(Unit *u);
-
- int (*kill)(Unit *u, KillWho w, int signo, sd_bus_error *error);
-
- bool (*can_reload)(Unit *u);
-
- /* Write all data that cannot be restored from other sources
- * away using unit_serialize_item() */
- int (*serialize)(Unit *u, FILE *f, FDSet *fds);
-
- /* Restore one item from the serialization */
- int (*deserialize_item)(Unit *u, const char *key, const char *data, FDSet *fds);
-
- /* Try to match up fds with what we need for this unit */
- int (*distribute_fds)(Unit *u, FDSet *fds);
-
- /* Boils down the more complex internal state of this unit to
- * a simpler one that the engine can understand */
- UnitActiveState (*active_state)(Unit *u);
-
- /* Returns the substate specific to this unit type as
- * string. This is purely information so that we can give the
- * user a more fine grained explanation in which actual state a
- * unit is in. */
- const char* (*sub_state_to_string)(Unit *u);
-
- /* Return true when there is reason to keep this entry around
- * even nothing references it and it isn't active in any
- * way */
- bool (*check_gc)(Unit *u);
-
- /* When the unit is not running and no job for it queued we
- * shall release its runtime resources */
- void (*release_resources)(Unit *u);
-
- /* Return true when this unit is suitable for snapshotting */
- bool (*check_snapshot)(Unit *u);
-
- /* Invoked on every child that died */
- void (*sigchld_event)(Unit *u, pid_t pid, int code, int status);
-
- /* Reset failed state if we are in failed state */
- void (*reset_failed)(Unit *u);
-
- /* Called whenever any of the cgroups this unit watches for
- * ran empty */
- void (*notify_cgroup_empty)(Unit *u);
-
- /* Called whenever a process of this unit sends us a message */
- void (*notify_message)(Unit *u, pid_t pid, char **tags, FDSet *fds);
-
- /* Called whenever a name this Unit registered for comes or
- * goes away. */
- void (*bus_name_owner_change)(Unit *u, const char *name, const char *old_owner, const char *new_owner);
-
- /* Called for each property that is being set */
- int (*bus_set_property)(Unit *u, const char *name, sd_bus_message *message, UnitSetPropertiesMode mode, sd_bus_error *error);
-
- /* Called after at least one property got changed to apply the necessary change */
- int (*bus_commit_properties)(Unit *u);
-
- /* Return the unit this unit is following */
- Unit *(*following)(Unit *u);
-
- /* Return the set of units that are following each other */
- int (*following_set)(Unit *u, Set **s);
-
- /* Invoked each time a unit this unit is triggering changes
- * state or gains/loses a job */
- void (*trigger_notify)(Unit *u, Unit *trigger);
-
- /* Called whenever CLOCK_REALTIME made a jump */
- void (*time_change)(Unit *u);
-
- int (*get_timeout)(Unit *u, uint64_t *timeout);
-
- /* 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. */
- int (*enumerate)(Manager *m);
-
- /* Type specific cleanups. */
- void (*shutdown)(Manager *m);
-
- /* If this function is set and return false all jobs for units
- * of this type will immediately fail. */
- bool (*supported)(Manager *m);
-
- /* The interface name */
- const char *bus_interface;
-
- /* The bus vtable */
- const sd_bus_vtable *bus_vtable;
-
- /* The strings to print in status messages */
- UnitStatusMessageFormats status_message_formats;
-
- /* Can units of this type have multiple names? */
- bool no_alias:1;
-
- /* Instances make no sense for this type */
- bool no_instances:1;
-
- /* Exclude from automatic gc */
- bool no_gc:1;
-
- /* True if transient units of this type are OK */
- bool can_transient:1;
-};
-
-extern const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX];
-
-#define UNIT_VTABLE(u) unit_vtable[(u)->type]
-
-/* For casting a unit into the various unit types */
-#define DEFINE_CAST(UPPERCASE, MixedCase) \
- static inline MixedCase* UPPERCASE(Unit *u) { \
- if (_unlikely_(!u || u->type != UNIT_##UPPERCASE)) \
- return NULL; \
- \
- return (MixedCase*) u; \
- }
-
-/* For casting the various unit types into a unit */
-#define UNIT(u) (&(u)->meta)
-
-#define UNIT_TRIGGER(u) ((Unit*) set_first((u)->dependencies[UNIT_TRIGGERS]))
-
-DEFINE_CAST(SERVICE, Service);
-DEFINE_CAST(SOCKET, Socket);
-DEFINE_CAST(BUSNAME, BusName);
-DEFINE_CAST(TARGET, Target);
-DEFINE_CAST(SNAPSHOT, Snapshot);
-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);
-
-int unit_add_name(Unit *u, const char *name);
-
-int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_reference);
-int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit *other, bool add_reference);
-
-int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference);
-int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference);
-
-int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference);
-int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference);
-
-int unit_add_exec_dependencies(Unit *u, ExecContext *c);
-
-int unit_choose_id(Unit *u, const char *name);
-int unit_set_description(Unit *u, const char *description);
-
-bool unit_check_gc(Unit *u);
-
-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);
-
-int unit_merge(Unit *u, Unit *other);
-int unit_merge_by_name(Unit *u, const char *other);
-
-Unit *unit_follow_merge(Unit *u) _pure_;
-
-int unit_load_fragment_and_dropin(Unit *u);
-int unit_load_fragment_and_dropin_optional(Unit *u);
-int unit_load(Unit *unit);
-
-int unit_add_default_slice(Unit *u, CGroupContext *c);
-
-const char *unit_description(Unit *u) _pure_;
-
-bool unit_has_name(Unit *u, const char *name);
-
-UnitActiveState unit_active_state(Unit *u);
-
-const char* unit_sub_state_to_string(Unit *u);
-
-void unit_dump(Unit *u, FILE *f, const char *prefix);
-
-bool unit_can_reload(Unit *u) _pure_;
-bool unit_can_start(Unit *u) _pure_;
-bool unit_can_isolate(Unit *u) _pure_;
-
-int unit_start(Unit *u);
-int unit_stop(Unit *u);
-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);
-
-int unit_watch_pid(Unit *u, pid_t pid);
-void unit_unwatch_pid(Unit *u, pid_t pid);
-int unit_watch_all_pids(Unit *u);
-void unit_unwatch_all_pids(Unit *u);
-
-void unit_tidy_watch_pids(Unit *u, pid_t except1, pid_t except2);
-
-int unit_watch_bus_name(Unit *u, const char *name);
-void unit_unwatch_bus_name(Unit *u, const char *name);
-
-bool unit_job_is_applicable(Unit *u, JobType j);
-
-int set_unit_path(const char *p);
-
-char *unit_dbus_path(Unit *u);
-
-int unit_load_related_unit(Unit *u, const char *type, Unit **_found);
-
-bool unit_can_serialize(Unit *u) _pure_;
-int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs);
-void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_(4,5);
-void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value);
-int unit_deserialize(Unit *u, FILE *f, FDSet *fds);
-
-int unit_add_node_link(Unit *u, const char *what, bool wants);
-
-int unit_coldplug(Unit *u, Hashmap *deferred_work);
-
-void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) _printf_(3, 0);
-
-bool unit_need_daemon_reload(Unit *u);
-
-void unit_reset_failed(Unit *u);
-
-Unit *unit_following(Unit *u);
-int unit_following_set(Unit *u, Set **s);
-
-const char *unit_slice_name(Unit *u);
-
-bool unit_stop_pending(Unit *u) _pure_;
-bool unit_inactive_or_pending(Unit *u) _pure_;
-bool unit_active_or_pending(Unit *u);
-
-int unit_add_default_target_dependency(Unit *u, Unit *target);
-
-char *unit_default_cgroup_path(Unit *u);
-
-void unit_start_on_failure(Unit *u);
-void unit_trigger_notify(Unit *u);
-
-UnitFileState unit_get_unit_file_state(Unit *u);
-int unit_get_unit_file_preset(Unit *u);
-
-Unit* unit_ref_set(UnitRef *ref, Unit *u);
-void unit_ref_unset(UnitRef *ref);
-
-#define UNIT_DEREF(ref) ((ref).unit)
-#define UNIT_ISSET(ref) (!!(ref).unit)
-
-int unit_patch_contexts(Unit *u);
-
-ExecContext *unit_get_exec_context(Unit *u) _pure_;
-KillContext *unit_get_kill_context(Unit *u) _pure_;
-CGroupContext *unit_get_cgroup_context(Unit *u) _pure_;
-
-ExecRuntime *unit_get_exec_runtime(Unit *u) _pure_;
-
-int unit_setup_exec_runtime(Unit *u);
-
-int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data);
-int unit_write_drop_in_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) _printf_(4,5);
-
-int unit_write_drop_in_private(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data);
-int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) _printf_(4,5);
-
-int unit_remove_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name);
-
-int unit_kill_context(Unit *u, KillContext *c, KillOperation k, pid_t main_pid, pid_t control_pid, bool main_pid_alien);
-
-int unit_make_transient(Unit *u);
-
-int unit_require_mounts_for(Unit *u, const char *path);
-
-const char *unit_active_state_to_string(UnitActiveState i) _const_;
-UnitActiveState unit_active_state_from_string(const char *s) _pure_;
-
-/* Macros which append UNIT= or USER_UNIT= to the message */
-
-#define log_unit_full_errno(unit, level, error, ...) log_object_internal(level, error, __FILE__, __LINE__, __func__, getpid() == 1 ? "UNIT=" : "USER_UNIT=", unit, __VA_ARGS__)
-#define log_unit_full(unit, level, ...) log_unit_full_errno(unit, level, 0, __VA_ARGS__)
-
-#define log_unit_debug(unit, ...) log_unit_full(unit, LOG_DEBUG, __VA_ARGS__)
-#define log_unit_info(unit, ...) log_unit_full(unit, LOG_INFO, __VA_ARGS__)
-#define log_unit_notice(unit, ...) log_unit_full(unit, LOG_NOTICE, __VA_ARGS__)
-#define log_unit_warning(unit, ...) log_unit_full(unit, LOG_WARNING, __VA_ARGS__)
-#define log_unit_error(unit, ...) log_unit_full(unit, LOG_ERR, __VA_ARGS__)
-
-#define log_unit_debug_errno(unit, error, ...) log_unit_full_errno(unit, LOG_DEBUG, error, __VA_ARGS__)
-#define log_unit_info_errno(unit, error, ...) log_unit_full_errno(unit, LOG_INFO, error, __VA_ARGS__)
-#define log_unit_notice_errno(unit, error, ...) log_unit_full_errno(unit, LOG_NOTICE, error, __VA_ARGS__)
-#define log_unit_warning_errno(unit, error, ...) log_unit_full_errno(unit, LOG_WARNING, error, __VA_ARGS__)
-#define log_unit_error_errno(unit, error, ...) log_unit_full_errno(unit, LOG_ERR, error, __VA_ARGS__)
-
-#define log_unit_struct(unit, level, ...) log_struct(level, getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s", unit, __VA_ARGS__)
-#define log_unit_struct_errno(unit, level, error, ...) log_struct_errno(level, error, getpid() == 1 ? "UNIT=%s" : "USER_UNIT=%s", unit, __VA_ARGS__)
diff --git a/src/core/user.conf b/src/core/user.conf
deleted file mode 100644
index 87c816437..000000000
--- a/src/core/user.conf
+++ /dev/null
@@ -1,44 +0,0 @@
-# This file is part of systemd.
-#
-# 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.
-#
-# You can override the directives in this file by creating files in
-# /etc/systemd/user.conf.d/*.conf.
-#
-# See systemd-user.conf(5) for details
-
-[Manager]
-#LogLevel=info
-#LogTarget=console
-#LogColor=yes
-#LogLocation=no
-#SystemCallArchitectures=
-#TimerSlackNSec=
-#DefaultTimerAccuracySec=1min
-#DefaultStandardOutput=inherit
-#DefaultStandardError=inherit
-#DefaultTimeoutStartSec=90s
-#DefaultTimeoutStopSec=90s
-#DefaultRestartSec=100ms
-#DefaultStartLimitInterval=10s
-#DefaultStartLimitBurst=5
-#DefaultEnvironment=
-#DefaultLimitCPU=
-#DefaultLimitFSIZE=
-#DefaultLimitDATA=
-#DefaultLimitSTACK=
-#DefaultLimitCORE=
-#DefaultLimitRSS=
-#DefaultLimitNOFILE=
-#DefaultLimitAS=
-#DefaultLimitNPROC=
-#DefaultLimitMEMLOCK=
-#DefaultLimitLOCKS=
-#DefaultLimitSIGPENDING=
-#DefaultLimitMSGQUEUE=
-#DefaultLimitNICE=
-#DefaultLimitRTPRIO=
-#DefaultLimitRTTIME=