summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@sbcglobal.net>2016-05-25 23:32:14 -0400
committerLuke Shumaker <lukeshu@sbcglobal.net>2016-05-25 23:32:14 -0400
commit0629b78d815ce6a0b65aecc02fb18a122226274c (patch)
tree4715d40a85a08ea4f5fcbb30ca70db70d31e23b1 /src/core
parentf5e7d6cf6b513104f051442b01e8b3bca7523709 (diff)
stuff
Diffstat (limited to 'src/core')
-rw-r--r--src/core/.gitignore3
-rw-r--r--src/core/Makefile215
-rw-r--r--src/core/Makefile.mk28
-rw-r--r--src/core/audit-fd.c73
-rw-r--r--src/core/audit-fd.h23
-rw-r--r--src/core/automount.c1092
-rw-r--r--src/core/automount.h59
-rw-r--r--src/core/bus-endpoint.c135
-rw-r--r--src/core/bus-endpoint.h42
-rw-r--r--src/core/bus-policy.c180
-rw-r--r--src/core/bus-policy.h64
-rw-r--r--src/core/busname.c1067
-rw-r--r--src/core/busname.h67
-rw-r--r--src/core/cgroup.c1620
-rw-r--r--src/core/cgroup.h155
-rw-r--r--src/core/dbus-automount.c34
-rw-r--r--src/core/dbus-automount.h23
-rw-r--r--src/core/dbus-busname.c37
-rw-r--r--src/core/dbus-busname.h23
-rw-r--r--src/core/dbus-cgroup.c699
-rw-r--r--src/core/dbus-cgroup.h28
-rw-r--r--src/core/dbus-device.c28
-rw-r--r--src/core/dbus-device.h24
-rw-r--r--src/core/dbus-execute.c1564
-rw-r--r--src/core/dbus-execute.h45
-rw-r--r--src/core/dbus-job.c193
-rw-r--r--src/core/dbus-job.h31
-rw-r--r--src/core/dbus-kill.c122
-rw-r--r--src/core/dbus-kill.h29
-rw-r--r--src/core/dbus-manager.c2137
-rw-r--r--src/core/dbus-manager.h28
-rw-r--r--src/core/dbus-mount.c211
-rw-r--r--src/core/dbus-mount.h29
-rw-r--r--src/core/dbus-path.c86
-rw-r--r--src/core/dbus-path.h24
-rw-r--r--src/core/dbus-scope.c229
-rw-r--r--src/core/dbus-scope.h31
-rw-r--r--src/core/dbus-service.c322
-rw-r--r--src/core/dbus-service.h29
-rw-r--r--src/core/dbus-slice.c52
-rw-r--r--src/core/dbus-slice.h29
-rw-r--r--src/core/dbus-socket.c182
-rw-r--r--src/core/dbus-socket.h29
-rw-r--r--src/core/dbus-swap.c115
-rw-r--r--src/core/dbus-swap.h30
-rw-r--r--src/core/dbus-target.c26
-rw-r--r--src/core/dbus-target.h24
-rw-r--r--src/core/dbus-timer.c352
-rw-r--r--src/core/dbus-timer.h28
-rw-r--r--src/core/dbus-unit.c1276
-rw-r--r--src/core/dbus-unit.h40
-rw-r--r--src/core/dbus.c1258
-rw-r--r--src/core/dbus.h42
-rw-r--r--src/core/device.c878
-rw-r--r--src/core/device.h47
-rw-r--r--src/core/execute.c3165
-rw-r--r--src/core/execute.h297
-rw-r--r--src/core/failure-action.c125
-rw-r--r--src/core/failure-action.h41
-rw-r--r--src/core/hostname-setup.c68
-rw-r--r--src/core/hostname-setup.h22
-rw-r--r--src/core/ima-setup.c80
-rw-r--r--src/core/ima-setup.h24
-rw-r--r--src/core/job.c1249
-rw-r--r--src/core/job.h242
-rw-r--r--src/core/kill.c68
-rw-r--r--src/core/kill.h65
-rw-r--r--src/core/killall.c249
-rw-r--r--src/core/killall.h22
-rw-r--r--src/core/kmod-setup.c131
-rw-r--r--src/core/kmod-setup.h22
-rw-r--r--src/core/load-dropin.c81
-rw-r--r--src/core/load-dropin.h34
-rw-r--r--src/core/load-fragment-gperf.gperf.m4378
-rw-r--r--src/core/load-fragment.c3939
-rw-r--r--src/core/load-fragment.h122
-rw-r--r--src/core/locale-setup.c124
-rw-r--r--src/core/locale-setup.h22
-rw-r--r--src/core/loopback-setup.c90
-rw-r--r--src/core/loopback-setup.h22
-rw-r--r--src/core/machine-id-setup.c375
-rw-r--r--src/core/machine-id-setup.h23
-rw-r--r--src/core/macros.systemd.in105
-rw-r--r--src/core/main.c2142
-rw-r--r--src/core/manager.c3124
-rw-r--r--src/core/manager.h376
-rw-r--r--src/core/mount-setup.c412
-rw-r--r--src/core/mount-setup.h30
-rw-r--r--src/core/mount.c1873
-rw-r--r--src/core/mount.h107
-rw-r--r--src/core/namespace.c727
-rw-r--r--src/core/namespace.h64
-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.c778
-rw-r--r--src/core/path.h92
-rw-r--r--src/core/scope.c610
-rw-r--r--src/core/scope.h55
-rw-r--r--src/core/selinux-access.c280
-rw-r--r--src/core/selinux-access.h45
-rw-r--r--src/core/selinux-setup.c121
-rw-r--r--src/core/selinux-setup.h24
-rw-r--r--src/core/service.c3366
-rw-r--r--src/core/service.h220
-rw-r--r--src/core/show-status.c124
-rw-r--r--src/core/show-status.h39
-rw-r--r--src/core/shutdown.c435
-rw-r--r--src/core/slice.c339
-rw-r--r--src/core/slice.h32
-rw-r--r--src/core/smack-setup.c346
-rw-r--r--src/core/smack-setup.h24
-rw-r--r--src/core/socket.c2866
-rw-r--r--src/core/socket.h181
-rw-r--r--src/core/swap.c1518
-rw-r--r--src/core/swap.h109
-rw-r--r--src/core/system.conf60
-rw-r--r--src/core/systemd.pc.in34
-rw-r--r--src/core/target.c223
-rw-r--r--src/core/target.h30
-rw-r--r--src/core/timer.c851
-rw-r--r--src/core/timer.h88
-rw-r--r--src/core/transaction.c1092
-rw-r--r--src/core/transaction.h51
-rw-r--r--src/core/triggers.systemd.in64
-rw-r--r--src/core/umount.c613
-rw-r--r--src/core/umount.h28
-rw-r--r--src/core/unit-printf.c309
-rw-r--r--src/core/unit-printf.h26
-rw-r--r--src/core/unit.c3756
-rw-r--r--src/core/unit.h630
-rw-r--r--src/core/user.conf44
132 files changed, 0 insertions, 55073 deletions
diff --git a/src/core/.gitignore b/src/core/.gitignore
deleted file mode 100644
index 465b4fcc20..0000000000
--- a/src/core/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-/macros.systemd
-/triggers.systemd
-/systemd.pc
diff --git a/src/core/Makefile b/src/core/Makefile
deleted file mode 100644
index bd8836a0ef..0000000000
--- a/src/core/Makefile
+++ /dev/null
@@ -1,215 +0,0 @@
-# -*- Mode: makefile; indent-tabs-mode: t -*-
-#
-# This file is part of systemd.
-#
-# Copyright 2010-2012 Lennart Poettering
-# Copyright 2010-2012 Kay Sievers
-# Copyright 2013 Zbigniew Jędrzejewski-Szmek
-# Copyright 2013 David Strauss
-# Copyright 2016 Luke Shumaker
-#
-# 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/>.
-noinst_LTLIBRARIES += \
- libcore.la
-
-libcore_la_SOURCES = \
- src/core/unit.c \
- src/core/unit.h \
- src/core/unit-printf.c \
- src/core/unit-printf.h \
- src/core/job.c \
- src/core/job.h \
- src/core/manager.c \
- src/core/manager.h \
- src/core/transaction.c \
- src/core/transaction.h \
- src/core/load-fragment.c \
- src/core/load-fragment.h \
- src/core/service.c \
- src/core/service.h \
- src/core/socket.c \
- src/core/socket.h \
- src/core/busname.c \
- src/core/busname.h \
- src/core/bus-endpoint.c \
- src/core/bus-endpoint.h \
- src/core/bus-policy.c \
- src/core/bus-policy.h \
- src/core/target.c \
- src/core/target.h \
- src/core/device.c \
- src/core/device.h \
- src/core/mount.c \
- src/core/mount.h \
- src/core/automount.c \
- src/core/automount.h \
- src/core/swap.c \
- src/core/swap.h \
- src/core/timer.c \
- src/core/timer.h \
- src/core/path.c \
- src/core/path.h \
- src/core/slice.c \
- src/core/slice.h \
- src/core/scope.c \
- src/core/scope.h \
- src/core/load-dropin.c \
- src/core/load-dropin.h \
- src/core/execute.c \
- src/core/execute.h \
- src/core/kill.c \
- src/core/kill.h \
- src/core/dbus.c \
- src/core/dbus.h \
- src/core/dbus-manager.c \
- src/core/dbus-manager.h \
- src/core/dbus-unit.c \
- src/core/dbus-unit.h \
- src/core/dbus-job.c \
- src/core/dbus-job.h \
- src/core/dbus-service.c \
- src/core/dbus-service.h \
- src/core/dbus-socket.c \
- src/core/dbus-socket.h \
- src/core/dbus-busname.c \
- src/core/dbus-busname.h \
- src/core/dbus-target.c \
- src/core/dbus-target.h \
- src/core/dbus-device.c \
- src/core/dbus-device.h \
- src/core/dbus-mount.c \
- src/core/dbus-mount.h \
- src/core/dbus-automount.c \
- src/core/dbus-automount.h \
- src/core/dbus-swap.c \
- src/core/dbus-swap.h \
- src/core/dbus-timer.c \
- src/core/dbus-timer.h \
- src/core/dbus-path.c \
- src/core/dbus-path.h \
- src/core/dbus-slice.c \
- src/core/dbus-slice.h \
- src/core/dbus-scope.c \
- src/core/dbus-scope.h \
- src/core/dbus-execute.c \
- src/core/dbus-execute.h \
- src/core/dbus-kill.c \
- src/core/dbus-kill.h \
- src/core/dbus-cgroup.c \
- src/core/dbus-cgroup.h \
- src/core/cgroup.c \
- src/core/cgroup.h \
- src/core/selinux-access.c \
- src/core/selinux-access.h \
- src/core/selinux-setup.c \
- src/core/selinux-setup.h \
- src/core/smack-setup.c \
- src/core/smack-setup.h \
- src/core/ima-setup.c \
- src/core/ima-setup.h \
- src/core/locale-setup.h \
- src/core/locale-setup.c \
- src/core/hostname-setup.c \
- src/core/hostname-setup.h \
- src/core/machine-id-setup.c \
- src/core/machine-id-setup.h \
- src/core/mount-setup.c \
- src/core/mount-setup.h \
- src/core/kmod-setup.c \
- src/core/kmod-setup.h \
- src/core/loopback-setup.h \
- src/core/loopback-setup.c \
- src/core/namespace.c \
- src/core/namespace.h \
- src/core/killall.h \
- src/core/killall.c \
- src/core/audit-fd.c \
- src/core/audit-fd.h \
- src/core/show-status.c \
- src/core/show-status.h \
- src/core/failure-action.c \
- src/core/failure-action.h
-
-nodist_libcore_la_SOURCES = \
- src/core/load-fragment-gperf.c \
- src/core/load-fragment-gperf-nulstr.c
-
-libcore_la_CFLAGS = \
- $(AM_CFLAGS) \
- $(PAM_CFLAGS) \
- $(AUDIT_CFLAGS) \
- $(KMOD_CFLAGS) \
- $(APPARMOR_CFLAGS) \
- $(MOUNT_CFLAGS) \
- $(SECCOMP_CFLAGS)
-
-libcore_la_LIBADD = \
- libshared.la \
- $(PAM_LIBS) \
- $(AUDIT_LIBS) \
- $(KMOD_LIBS) \
- $(APPARMOR_LIBS) \
- $(MOUNT_LIBS)
-
-src/core/load-fragment-gperf-nulstr.c: src/core/load-fragment-gperf.gperf
- $(AM_V_at)$(MKDIR_P) $(dir $@)
- $(AM_V_GEN)$(AWK) 'BEGIN{ keywords=0 ; FS="," ; print "extern const char load_fragment_gperf_nulstr[];" ; print "const char load_fragment_gperf_nulstr[] ="} ; keyword==1 { print "\"" $$1 "\\0\"" } ; /%%/ { keyword=1} ; END { print ";" }' < $< > $@
-
-systemd_SOURCES = \
- src/core/main.c
-
-systemd_CFLAGS = \
- $(AM_CFLAGS) \
- $(SECCOMP_CFLAGS) \
- $(MOUNT_CFLAGS)
-
-systemd_LDADD = \
- libcore.la
-
-dist_pkgsysconf_DATA += \
- src/core/system.conf \
- src/core/user.conf
-
-dist_dbuspolicy_DATA += \
- src/core/org.freedesktop.systemd1.conf
-
-dist_dbussystemservice_DATA += \
- src/core/org.freedesktop.systemd1.service
-
-polkitpolicy_in_in_files += \
- src/core/org.freedesktop.systemd1.policy.in.in
-
-pkgconfigdata_DATA += \
- src/core/systemd.pc
-
-nodist_rpmmacros_DATA = \
- src/core/macros.systemd
-
-EXTRA_DIST += \
- src/core/systemd.pc.in \
- src/core/macros.systemd.in \
- src/core/triggers.systemd.in
-
-systemd_shutdown_SOURCES = \
- src/core/umount.c \
- src/core/umount.h \
- src/core/shutdown.c \
- src/core/mount-setup.c \
- src/core/mount-setup.h \
- src/core/killall.h \
- src/core/killall.c
-
-systemd_shutdown_LDADD = \
- libshared.la
-
diff --git a/src/core/Makefile.mk b/src/core/Makefile.mk
deleted file mode 100644
index e8546085de..0000000000
--- a/src/core/Makefile.mk
+++ /dev/null
@@ -1,28 +0,0 @@
-# -*- Mode: makefile; indent-tabs-mode: t -*-
-#
-# This file is part of systemd.
-#
-# Copyright 2010-2012 Lennart Poettering
-# Copyright 2010-2012 Kay Sievers
-# Copyright 2013 Zbigniew Jędrzejewski-Szmek
-# Copyright 2013 David Strauss
-# Copyright 2016 Luke Shumaker
-#
-# 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/>.
-dist_systemunit_DATA_busnames += \
- units/org.freedesktop.systemd1.busname
-
-BUSNAMES_TARGET_WANTS += \
- org.freedesktop.systemd1.busname
-
diff --git a/src/core/audit-fd.c b/src/core/audit-fd.c
deleted file mode 100644
index 76afe3fe15..0000000000
--- a/src/core/audit-fd.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/***
- 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 <libaudit.h>
-#include <stdbool.h>
-
-#include "fd-util.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 0eccb59210..0000000000
--- a/src/core/audit-fd.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#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 5dc6fd98e7..0000000000
--- a/src/core/automount.c
+++ /dev/null
@@ -1,1092 +0,0 @@
-/***
- 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 <limits.h>
-#include <linux/auto_dev-ioctl.h>
-#include <linux/auto_fs4.h>
-#include <sys/epoll.h>
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "alloc-util.h"
-#include "async.h"
-#include "automount.h"
-#include "bus-error.h"
-#include "bus-util.h"
-#include "dbus-automount.h"
-#include "fd-util.h"
-#include "formats-util.h"
-#include "io-util.h"
-#include "label.h"
-#include "mkdir.h"
-#include "mount-util.h"
-#include "mount.h"
-#include "parse-util.h"
-#include "path-util.h"
-#include "process-util.h"
-#include "special.h"
-#include "stdio-util.h"
-#include "string-table.h"
-#include "string-util.h"
-#include "unit-name.h"
-#include "unit.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
-};
-
-struct expire_data {
- int dev_autofs_fd;
- int ioctl_fd;
-};
-
-static inline void expire_data_free(struct expire_data *data) {
- if (!data)
- return;
-
- safe_close(data->dev_autofs_fd);
- safe_close(data->ioctl_fd);
- free(data);
-}
-
-DEFINE_TRIVIAL_CLEANUP_FUNC(struct expire_data*, expire_data_free);
-
-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 int automount_send_ready(Automount *a, Set *tokens, int status);
-
-static void unmount_autofs(Automount *a) {
- int r;
-
- assert(a);
-
- if (a->pipe_fd < 0)
- return;
-
- automount_send_ready(a, a->tokens, -EHOSTDOWN);
- automount_send_ready(a, a->expire_tokens, -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)) {
- r = repeat_unmount(a->where, MNT_DETACH);
- if (r < 0)
- log_error_errno(r, "Failed to unmount: %m");
- }
-}
-
-static void automount_done(Unit *u) {
- Automount *a = AUTOMOUNT(u);
-
- assert(a);
-
- unmount_autofs(a);
-
- a->where = mfree(a->where);
-
- a->tokens = set_free(a->tokens);
- a->expire_tokens = set_free(a->expire_tokens);
-
- a->expire_event_source = sd_event_source_unref(a->expire_event_source);
-}
-
-static int automount_add_mount_links(Automount *a) {
- _cleanup_free_ char *parent = NULL;
-
- assert(a);
-
- parent = dirname_malloc(a->where);
- if (!parent)
- return -ENOMEM;
-
- return unit_require_mounts_for(UNIT(a), parent);
-}
-
-static int automount_add_default_dependencies(Automount *a) {
- int r;
-
- assert(a);
-
- if (!UNIT(a)->default_dependencies)
- return 0;
-
- if (UNIT(a)->manager->running_as != MANAGER_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) {
- _cleanup_free_ char *e = NULL;
- int r;
-
- assert(a);
-
- if (UNIT(a)->load_state != UNIT_LOADED)
- return 0;
-
- if (path_equal(a->where, "/")) {
- log_unit_error(UNIT(a), "Cannot have an automount unit for the root directory. Refusing.");
- return -EINVAL;
- }
-
- r = unit_name_from_path(a->where, ".automount", &e);
- if (r < 0)
- return log_unit_error(UNIT(a), "Failed to generate unit name from path: %m");
-
- if (!unit_has_name(UNIT(a), e)) {
- log_unit_error(UNIT(a), "Where= setting doesn't match unit name. Refusing.");
- 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) {
- r = unit_name_to_path(u->id, &a->where);
- if (r < 0)
- return r;
- }
-
- 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;
-
- 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), "Changed %s -> %s", automount_state_to_string(old_state), automount_state_to_string(state));
-
- unit_notify(UNIT(a), state_translation_table[old_state], state_translation_table[state], true);
-}
-
-static int automount_coldplug(Unit *u) {
- 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;
-
- (void) sd_event_source_set_description(a->pipe_event_source, "automount-io");
- }
-
- automount_set_state(a, a->deserialized_state);
- }
-
- return 0;
-}
-
-static void automount_dump(Unit *u, FILE *f, const char *prefix) {
- char time_string[FORMAT_TIMESPAN_MAX];
- Automount *a = AUTOMOUNT(u);
-
- assert(a);
-
- fprintf(f,
- "%sAutomount State: %s\n"
- "%sResult: %s\n"
- "%sWhere: %s\n"
- "%sDirectoryMode: %04o\n"
- "%sTimeoutIdleUSec: %s\n",
- prefix, automount_state_to_string(a->state),
- prefix, automount_result_to_string(a->result),
- prefix, a->where,
- prefix, a->directory_mode,
- prefix, format_timespan(time_string, FORMAT_TIMESPAN_MAX, a->timeout_idle_usec, USEC_PER_SEC));
-}
-
-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;
-
- (void) 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, usec_t usec) {
- struct autofs_dev_ioctl param;
-
- assert(dev_autofs_fd >= 0);
- assert(ioctl_fd >= 0);
-
- init_autofs_dev_ioctl(&param);
- param.ioctlfd = ioctl_fd;
-
- /* Convert to seconds, rounding up. */
- param.timeout.timeout = (usec + USEC_PER_SEC - 1) / USEC_PER_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;
-}
-
-static int automount_send_ready(Automount *a, Set *tokens, int status) {
- _cleanup_close_ int ioctl_fd = -1;
- unsigned token;
- int r;
-
- assert(a);
- assert(status <= 0);
-
- if (set_isempty(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), status, "Sending failure: %m");
- else
- log_unit_debug(UNIT(a), "Sending success.");
-
- r = 0;
-
- /* Autofs thankfully does not hand out 0 as a token */
- while ((token = PTR_TO_UINT(set_steal_first(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 int automount_start_expire(Automount *a);
-
-int automount_update_mount(Automount *a, MountState old_state, MountState state) {
- int r;
-
- assert(a);
-
- switch (state) {
- case MOUNT_MOUNTED:
- case MOUNT_REMOUNTING:
- automount_send_ready(a, a->tokens, 0);
- r = automount_start_expire(a);
- if (r < 0)
- log_unit_warning_errno(UNIT(a), r, "Failed to start expiration timer, ignoring: %m");
- break;
- case MOUNT_DEAD:
- case MOUNT_UNMOUNTING:
- case MOUNT_MOUNTING_SIGTERM:
- case MOUNT_MOUNTING_SIGKILL:
- case MOUNT_REMOUNTING_SIGTERM:
- case MOUNT_REMOUNTING_SIGKILL:
- case MOUNT_UNMOUNTING_SIGTERM:
- case MOUNT_UNMOUNTING_SIGKILL:
- case MOUNT_FAILED:
- if (old_state != state)
- automount_send_ready(a, a->tokens, -ENODEV);
- (void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF);
- break;
- default:
- break;
- }
-
- switch (state) {
- case MOUNT_DEAD:
- automount_send_ready(a, a->expire_tokens, 0);
- break;
- case MOUNT_MOUNTING:
- case MOUNT_MOUNTING_DONE:
- case MOUNT_MOUNTING_SIGTERM:
- case MOUNT_MOUNTING_SIGKILL:
- case MOUNT_REMOUNTING_SIGTERM:
- case MOUNT_REMOUNTING_SIGKILL:
- case MOUNT_UNMOUNTING_SIGTERM:
- case MOUNT_UNMOUNTING_SIGKILL:
- case MOUNT_FAILED:
- if (old_state != state)
- automount_send_ready(a, a->expire_tokens, -ENODEV);
- break;
- default:
- break;
- }
-
- return 0;
-}
-
-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);
-
- set_clear(a->tokens);
-
- r = unit_fail_if_symlink(UNIT(a), a->where);
- if (r < 0)
- goto fail;
-
- (void) mkdir_p_label(a->where, 0555);
-
- unit_warn_if_dir_nonempty(UNIT(a), a->where);
-
- dev_autofs_fd = open_dev_autofs(UNIT(a)->manager);
- if (dev_autofs_fd < 0) {
- r = dev_autofs_fd;
- goto fail;
- }
-
- 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, a->timeout_idle_usec);
- 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;
-
- (void) sd_event_source_set_description(a->pipe_event_source, "automount-io");
-
- a->pipe_fd = p[0];
- a->dev_id = st.st_dev;
-
- automount_set_state(a, AUTOMOUNT_WAITING);
-
- return;
-
-fail:
- log_unit_error_errno(UNIT(a), r, "Failed to initialize automounter: %m");
-
- safe_close_pair(p);
-
- if (mounted) {
- r = repeat_unmount(a->where, MNT_DETACH);
- if (r < 0)
- log_error_errno(r, "Failed to unmount, ignoring: %m");
- }
-
- automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
-}
-
-static void *expire_thread(void *p) {
- struct autofs_dev_ioctl param;
- _cleanup_(expire_data_freep) struct expire_data *data = (struct expire_data*)p;
- int r;
-
- assert(data->dev_autofs_fd >= 0);
- assert(data->ioctl_fd >= 0);
-
- init_autofs_dev_ioctl(&param);
- param.ioctlfd = data->ioctl_fd;
-
- do {
- r = ioctl(data->dev_autofs_fd, AUTOFS_DEV_IOCTL_EXPIRE, &param);
- } while (r >= 0);
-
- if (errno != EAGAIN)
- log_warning_errno(errno, "Failed to expire automount, ignoring: %m");
-
- return NULL;
-}
-
-static int automount_dispatch_expire(sd_event_source *source, usec_t usec, void *userdata) {
- Automount *a = AUTOMOUNT(userdata);
- _cleanup_(expire_data_freep) struct expire_data *data = NULL;
- int r;
-
- assert(a);
- assert(source == a->expire_event_source);
-
- data = new0(struct expire_data, 1);
- if (!data)
- return log_oom();
-
- data->ioctl_fd = -1;
-
- data->dev_autofs_fd = fcntl(UNIT(a)->manager->dev_autofs_fd, F_DUPFD_CLOEXEC, 3);
- if (data->dev_autofs_fd < 0)
- return log_unit_error_errno(UNIT(a), errno, "Failed to duplicate autofs fd: %m");
-
- data->ioctl_fd = open_ioctl_fd(UNIT(a)->manager->dev_autofs_fd, a->where, a->dev_id);
- if (data->ioctl_fd < 0)
- return log_unit_error_errno(UNIT(a), data->ioctl_fd, "Couldn't open autofs ioctl fd: %m");
-
- r = asynchronous_job(expire_thread, data);
- if (r < 0)
- return log_unit_error_errno(UNIT(a), r, "Failed to start expire job: %m");
-
- data = NULL;
-
- return automount_start_expire(a);
-}
-
-static int automount_start_expire(Automount *a) {
- int r;
- usec_t timeout;
-
- assert(a);
-
- if (a->timeout_idle_usec == 0)
- return 0;
-
- timeout = now(CLOCK_MONOTONIC) + MAX(a->timeout_idle_usec/3, USEC_PER_SEC);
-
- if (a->expire_event_source) {
- r = sd_event_source_set_time(a->expire_event_source, timeout);
- if (r < 0)
- return r;
-
- return sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_ONESHOT);
- }
-
- r = sd_event_add_time(
- UNIT(a)->manager->event,
- &a->expire_event_source,
- CLOCK_MONOTONIC, timeout, 0,
- automount_dispatch_expire, a);
- if (r < 0)
- return r;
-
- (void) sd_event_source_set_description(a->expire_event_source, "automount-expire");
-
- return 0;
-}
-
-static void automount_enter_runnning(Automount *a) {
- _cleanup_(sd_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), "Suppressing automount request since unit stop is scheduled.");
- automount_send_ready(a, a->tokens, -EHOSTDOWN);
- automount_send_ready(a, a->expire_tokens, -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_errno(UNIT(a), errno, "Failed to stat automount point: %m");
- goto fail;
- }
-
- if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id)
- log_unit_info(UNIT(a), "Automount point already active?");
- else {
- Unit *trigger;
-
- trigger = UNIT_TRIGGER(UNIT(a));
- if (!trigger) {
- log_unit_error(UNIT(a), "Unit to trigger vanished.");
- goto fail;
- }
-
- r = manager_add_job(UNIT(a)->manager, JOB_START, trigger, JOB_REPLACE, &error, NULL);
- if (r < 0) {
- log_unit_warning(UNIT(a), "Failed to queue mount startup job: %s", 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);
- Unit *trigger;
-
- assert(a);
- assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_FAILED);
-
- if (path_is_mount_point(a->where, 0) > 0) {
- log_unit_error(u, "Path %s is already a mount point, refusing start.", a->where);
- return -EEXIST;
- }
-
- trigger = UNIT_TRIGGER(u);
- if (!trigger || trigger->load_state != UNIT_LOADED) {
- log_unit_error(u, "Refusing to start, unit to trigger not 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);
- Iterator i;
- void *p;
- int r;
-
- 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));
- SET_FOREACH(p, a->expire_tokens, i)
- unit_serialize_item_format(u, f, "expire-token", "%u", PTR_TO_UINT(p));
-
- r = unit_serialize_item_fd(u, f, fds, "pipe-fd", a->pipe_fd);
- if (r < 0)
- return r;
-
- 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, "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, "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, "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, "Failed to parse token value: %s", value);
- else {
- r = set_ensure_allocated(&a->tokens, NULL);
- if (r < 0) {
- log_oom();
- return 0;
- }
-
- r = set_put(a->tokens, UINT_TO_PTR(token));
- if (r < 0)
- log_unit_error_errno(u, r, "Failed to add token to set: %m");
- }
- } else if (streq(key, "expire-token")) {
- unsigned token;
-
- if (safe_atou(value, &token) < 0)
- log_unit_debug(u, "Failed to parse token value: %s", value);
- else {
- r = set_ensure_allocated(&a->expire_tokens, NULL);
- if (r < 0) {
- log_oom();
- return 0;
- }
-
- r = set_put(a->expire_tokens, UINT_TO_PTR(token));
- if (r < 0)
- log_unit_error_errno(u, r, "Failed to add expire token to set: %m");
- }
- } else if (streq(key, "pipe-fd")) {
- int fd;
-
- if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u, "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, "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) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- union autofs_v5_packet_union packet;
- Automount *a = AUTOMOUNT(userdata);
- struct stat st;
- Unit *trigger;
- int r;
-
- assert(a);
- assert(fd == a->pipe_fd);
-
- if (events != EPOLLIN) {
- log_unit_error(UNIT(a), "Got invalid poll event %"PRIu32" on pipe (fd=%d)", events, fd);
- goto fail;
- }
-
- r = loop_read_exact(a->pipe_fd, &packet, sizeof(packet), true);
- if (r < 0) {
- log_unit_error_errno(UNIT(a), 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), "Got automount request for %s, triggered by %"PRIu32" (%s)", a->where, packet.v5_packet.pid, strna(p));
- } else
- log_unit_debug(UNIT(a), "Got direct mount request on %s", a->where);
-
- r = set_ensure_allocated(&a->tokens, NULL);
- if (r < 0) {
- log_unit_error(UNIT(a), "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), r, "Failed to remember token: %m");
- goto fail;
- }
-
- automount_enter_runnning(a);
- break;
-
- case autofs_ptype_expire_direct:
- log_unit_debug(UNIT(a), "Got direct umount request on %s", a->where);
-
- (void) sd_event_source_set_enabled(a->expire_event_source, SD_EVENT_OFF);
-
- r = set_ensure_allocated(&a->expire_tokens, NULL);
- if (r < 0) {
- log_unit_error(UNIT(a), "Failed to allocate token set.");
- goto fail;
- }
-
- r = set_put(a->expire_tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token));
- if (r < 0) {
- log_unit_error_errno(UNIT(a), r, "Failed to remember token: %m");
- goto fail;
- }
-
- /* Before we do anything, let's see if somebody is playing games with us? */
- if (lstat(a->where, &st) < 0) {
- log_unit_warning_errno(UNIT(a), errno, "Failed to stat automount point: %m");
- goto fail;
- }
-
- if (!S_ISDIR(st.st_mode) || st.st_dev == a->dev_id) {
- log_unit_info(UNIT(a), "Automount point already unmounted?");
- automount_send_ready(a, a->expire_tokens, 0);
- break;
- }
-
- trigger = UNIT_TRIGGER(UNIT(a));
- if (!trigger) {
- log_unit_error(UNIT(a), "Unit to trigger vanished.");
- goto fail;
- }
-
- r = manager_add_job(UNIT(a)->manager, JOB_STOP, trigger, JOB_REPLACE, &error, NULL);
- if (r < 0) {
- log_unit_warning(UNIT(a), "Failed to queue umount startup job: %s", bus_error_message(&error, r));
- goto fail;
- }
- break;
-
- default:
- log_unit_error(UNIT(a), "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(void) {
- static int supported = -1;
-
- if (supported < 0)
- supported = access("/dev/autofs", F_OK) >= 0;
-
- return supported;
-}
-
-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_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.",
- },
- .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 cf5b1cf994..0000000000
--- a/src/core/automount.h
+++ /dev/null
@@ -1,59 +0,0 @@
-#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 AutomountResult {
- AUTOMOUNT_SUCCESS,
- AUTOMOUNT_FAILURE_RESOURCES,
- _AUTOMOUNT_RESULT_MAX,
- _AUTOMOUNT_RESULT_INVALID = -1
-} AutomountResult;
-
-struct Automount {
- Unit meta;
-
- AutomountState state, deserialized_state;
-
- char *where;
- usec_t timeout_idle_usec;
-
- int pipe_fd;
- sd_event_source *pipe_event_source;
- mode_t directory_mode;
- dev_t dev_id;
-
- Set *tokens;
- Set *expire_tokens;
-
- sd_event_source *expire_event_source;
-
- AutomountResult result;
-};
-
-extern const UnitVTable automount_vtable;
-
-int automount_update_mount(Automount *a, MountState old_state, MountState state);
-
-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 d22a80c91f..0000000000
--- a/src/core/bus-endpoint.c
+++ /dev/null
@@ -1,135 +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 "alloc-util.h"
-#include "bus-endpoint.h"
-#include "bus-kernel.h"
-#include "bus-policy.h"
-#include "kdbus.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 f2fbc4701c..0000000000
--- a/src/core/bus-endpoint.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#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 "bus-policy.h"
-#include "hashmap.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 4907c268e8..0000000000
--- a/src/core/bus-policy.c
+++ /dev/null
@@ -1,180 +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 "alloc-util.h"
-#include "bus-kernel.h"
-#include "bus-policy.h"
-#include "kdbus.h"
-#include "string-table.h"
-#include "user-util.h"
-#include "util.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) {
- if (errno == ENOTTY) /* Major API change */
- return -ESOCKTNOSUPPORT;
- 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 -ESOCKTNOSUPPORT;
-
- 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 5b2c4d5953..0000000000
--- a/src/core/bus-policy.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#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 "kdbus.h"
-#include "list.h"
-#include "macro.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 de2a21ccde..0000000000
--- a/src/core/busname.c
+++ /dev/null
@@ -1,1067 +0,0 @@
-/***
- 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 "alloc-util.h"
-#include "bus-internal.h"
-#include "bus-kernel.h"
-#include "bus-policy.h"
-#include "bus-util.h"
-#include "busname.h"
-#include "dbus-busname.h"
-#include "fd-util.h"
-#include "formats-util.h"
-#include "kdbus.h"
-#include "parse-util.h"
-#include "process-util.h"
-#include "service.h"
-#include "signal-util.h"
-#include "special.h"
-#include "string-table.h"
-#include "string-util.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);
-
- n->name = mfree(n->name);
-
- 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, usec_t usec) {
- int r;
-
- assert(n);
-
- if (n->timer_event_source) {
- r = sd_event_source_set_time(n->timer_event_source, usec);
- if (r < 0)
- return r;
-
- return sd_event_source_set_enabled(n->timer_event_source, SD_EVENT_ONESHOT);
- }
-
- if (usec == USEC_INFINITY)
- return 0;
-
- r = sd_event_add_time(
- UNIT(n)->manager->event,
- &n->timer_event_source,
- CLOCK_MONOTONIC,
- usec, 0,
- busname_dispatch_timer, n);
- if (r < 0)
- return r;
-
- (void) sd_event_source_set_description(n->timer_event_source, "busname-timer");
-
- return 0;
-}
-
-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 == MANAGER_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) {
- r = unit_name_to_prefix(u->id, &n->name);
- if (r < 0)
- return r;
- }
-
- 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), "Name= setting is not a valid service name Refusing.");
- return -EINVAL;
- }
-
- e = strjoina(n->name, ".busname");
- if (!unit_has_name(UNIT(n), e)) {
- log_unit_error(UNIT(n), "Name= setting doesn't match unit name. Refusing.");
- 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_errno(UNIT(n), r, "Failed to disable event source: %m");
-}
-
-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);
- if (r < 0)
- goto fail;
- } 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)
- goto fail;
-
- (void) sd_event_source_set_description(n->starter_event_source, "busname-starter");
- }
-
- return 0;
-
-fail:
- log_unit_warning_errno(UNIT(n), r, "Failed to watch starter fd: %m");
- busname_unwatch_fd(n);
- return r;
-}
-
-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 == MANAGER_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), 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), "Changed %s -> %s", 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) {
- BusName *n = BUSNAME(u);
- int r;
-
- assert(n);
- assert(n->state == BUSNAME_DEAD);
-
- if (n->deserialized_state == n->state)
- return 0;
-
- if (n->control_pid > 0 &&
- pid_is_unwaited(n->control_pid) &&
- IN_SET(n->deserialized_state, BUSNAME_MAKING, BUSNAME_SIGTERM, BUSNAME_SIGKILL)) {
-
- r = unit_watch_pid(UNIT(n), n->control_pid);
- if (r < 0)
- return r;
-
- r = busname_arm_timer(n, usec_add(u->state_change_timestamp.monotonic, n->timeout_usec));
- 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, usec_add(now(CLOCK_MONOTONIC), n->timeout_usec));
- 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;
-
- (void) default_signals(SIGNALS_CRASH_HANDLER, SIGNALS_IGNORE, -1);
- (void) 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), r, "Failed to kill control process: %m");
- goto fail;
- }
-
- if (r > 0) {
- r = busname_arm_timer(n, usec_add(now(CLOCK_MONOTONIC), n->timeout_usec));
- if (r < 0) {
- log_unit_warning_errno(UNIT(n), r, "Failed to arm timer: %m");
- 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), r, "Failed to watch names: %m");
- 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), r, "Failed to fork 'making' task: %m");
- 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), r, "Failed to make starter: %m");
- goto fail;
- }
-
- busname_enter_listening(n);
- }
-
- return;
-
-fail:
- busname_enter_dead(n, BUSNAME_FAILURE_RESOURCES);
-}
-
-static void busname_enter_running(BusName *n) {
- _cleanup_(sd_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 connections anymore if we are supposed to
- * shut down anyway */
-
- if (unit_stop_pending(UNIT(n))) {
- log_unit_debug(UNIT(n), "Suppressing activation request since unit stop is scheduled.");
-
- /* 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) {
- if (!UNIT_ISSET(n->service)) {
- log_unit_error(UNIT(n), "Service to activate vanished, refusing activation.");
- r = -ENOENT;
- goto fail;
- }
-
- r = manager_add_job(UNIT(n)->manager, JOB_START, UNIT_DEREF(n->service), JOB_REPLACE, &error, NULL);
- if (r < 0)
- goto fail;
- }
-
- busname_set_state(n, BUSNAME_RUNNING);
- return;
-
-fail:
- log_unit_warning(UNIT(n), "Failed to queue service startup job: %s", 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, "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);
- int r;
-
- 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);
-
- r = unit_serialize_item_fd(u, f, fds, "starter-fd", n->starter_fd);
- if (r < 0)
- return r;
-
- 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, "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, "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, "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, "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, "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;
-
- return log_unit_error_errno(UNIT(n), errno, "Failed to query activation message: %m");
- }
-
- /* 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) {
- r = log_unit_error_errno(UNIT(n), errno, "Failed to map activation message: %m");
- 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), "Activation triggered by process " PID_FMT " (%s)", 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), "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), "Activation request");
-
- if (revents != EPOLLIN) {
- log_unit_error(UNIT(n), "Got unexpected poll event (0x%x) on starter fd.", 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, f == BUSNAME_SUCCESS ? LOG_DEBUG : LOG_NOTICE, 0,
- "Control process exited, code=%s status=%i", 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), "Making timed out. Terminating.");
- busname_enter_signal(n, BUSNAME_SIGTERM, BUSNAME_FAILURE_TIMEOUT);
- break;
-
- case BUSNAME_SIGTERM:
- log_unit_warning(UNIT(n), "Stopping timed out. Killing.");
- busname_enter_signal(n, BUSNAME_SIGKILL, BUSNAME_FAILURE_TIMEOUT);
- break;
-
- case BUSNAME_SIGKILL:
- log_unit_warning(UNIT(n), "Processes still around after SIGKILL. Ignoring.");
- 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);
-
- assert(n);
- assert(other);
-
- if (!IN_SET(n->state, BUSNAME_RUNNING, BUSNAME_LISTENING))
- return;
-
- if (other->start_limit_hit) {
- busname_enter_dead(n, BUSNAME_FAILURE_SERVICE_START_LIMIT_HIT);
- return;
- }
-
- if (other->load_state != UNIT_LOADED || other->type != UNIT_SERVICE)
- return;
-
- if (IN_SET(SERVICE(other)->state,
- SERVICE_DEAD, SERVICE_FAILED,
- SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
- SERVICE_AUTO_RESTART))
- busname_enter_listening(n);
-
- if (SERVICE(other)->state == SERVICE_RUNNING)
- busname_set_state(n, BUSNAME_RUNNING);
-}
-
-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, usec_t *timeout) {
- BusName *n = BUSNAME(u);
- usec_t t;
- int r;
-
- if (!n->timer_event_source)
- return 0;
-
- r = sd_event_source_get_time(n->timer_event_source, &t);
- if (r < 0)
- return r;
- if (t == USEC_INFINITY)
- return 0;
-
- *timeout = t;
- return 1;
-}
-
-static bool busname_supported(void) {
- static int supported = -1;
-
- if (supported < 0)
- supported = is_kdbus_available();
-
- return supported;
-}
-
-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_START_LIMIT_HIT] = "service-start-limit-hit",
-};
-
-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",
-
- .no_alias = true,
- .no_instances = true,
-
- .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_vtable = bus_busname_vtable,
-
- .status_message_formats = {
- .finished_start_job = {
- [JOB_DONE] = "Listening on %s.",
- [JOB_FAILED] = "Failed to listen on %s.",
- },
- .finished_stop_job = {
- [JOB_DONE] = "Closed %s.",
- [JOB_FAILED] = "Failed stopping %s.",
- },
- },
-};
diff --git a/src/core/busname.h b/src/core/busname.h
deleted file mode 100644
index 6b6f6c62d4..0000000000
--- a/src/core/busname.h
+++ /dev/null
@@ -1,67 +0,0 @@
-#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;
-
-#include "unit.h"
-
-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_START_LIMIT_HIT,
- _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_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 39235a95f6..0000000000
--- a/src/core/cgroup.c
+++ /dev/null
@@ -1,1620 +0,0 @@
-/***
- 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 "alloc-util.h"
-#include "cgroup-util.h"
-#include "cgroup.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "fs-util.h"
-#include "parse-util.h"
-#include "path-util.h"
-#include "process-util.h"
-#include "special.h"
-#include "string-table.h"
-#include "string-util.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 = CGROUP_CPU_SHARES_INVALID;
- c->startup_cpu_shares = CGROUP_CPU_SHARES_INVALID;
- c->cpu_quota_per_sec_usec = USEC_INFINITY;
-
- c->memory_limit = (uint64_t) -1;
-
- c->blockio_weight = CGROUP_BLKIO_WEIGHT_INVALID;
- c->startup_blockio_weight = CGROUP_BLKIO_WEIGHT_INVALID;
-
- c->tasks_max = (uint64_t) -1;
-}
-
-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"
- "%sTasksAccounting=%s\n"
- "%sCPUShares=%" PRIu64 "\n"
- "%sStartupCPUShares=%" PRIu64 "\n"
- "%sCPUQuotaPerSecSec=%s\n"
- "%sBlockIOWeight=%" PRIu64 "\n"
- "%sStartupBlockIOWeight=%" PRIu64 "\n"
- "%sMemoryLimit=%" PRIu64 "\n"
- "%sTasksMax=%" 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, yes_no(c->tasks_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, c->tasks_max,
- 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 %" PRIu64,
- 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, -EACCES) ? 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, -EACCES) ? 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, CGroupMask 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_MASK_CPU) && !is_root) {
- char buf[MAX(DECIMAL_STR_MAX(uint64_t), DECIMAL_STR_MAX(usec_t)) + 1];
-
- sprintf(buf, "%" PRIu64 "\n",
- IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_cpu_shares != CGROUP_CPU_SHARES_INVALID ? c->startup_cpu_shares :
- c->cpu_shares != CGROUP_CPU_SHARES_INVALID ? c->cpu_shares : CGROUP_CPU_SHARES_DEFAULT);
- r = cg_set_attribute("cpu", path, "cpu.shares", buf);
- if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? 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, -EACCES) ? 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, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set cpu.cfs_quota_us on %s: %m", path);
- }
-
- if (mask & CGROUP_MASK_BLKIO) {
- char buf[MAX(DECIMAL_STR_MAX(uint64_t)+1,
- DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1)];
- CGroupBlockIODeviceWeight *w;
- CGroupBlockIODeviceBandwidth *b;
-
- if (!is_root) {
- sprintf(buf, "%" PRIu64 "\n",
- IN_SET(state, MANAGER_STARTING, MANAGER_INITIALIZING) && c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ? c->startup_blockio_weight :
- c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ? c->blockio_weight : CGROUP_BLKIO_WEIGHT_DEFAULT);
- r = cg_set_attribute("blkio", path, "blkio.weight", buf);
- if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? 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 %" PRIu64 "\n", 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, -EACCES) ? 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, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set %s on %s: %m", a, path);
- }
- }
-
- if ((mask & CGROUP_MASK_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);
-
- if (cg_unified() <= 0)
- r = cg_set_attribute("memory", path, "memory.limit_in_bytes", buf);
- else
- r = cg_set_attribute("memory", path, "memory.max", buf);
-
- } else {
- if (cg_unified() <= 0)
- r = cg_set_attribute("memory", path, "memory.limit_in_bytes", "-1");
- else
- r = cg_set_attribute("memory", path, "memory.max", "max");
- }
-
- if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set memory.limit_in_bytes/memory.max on %s: %m", path);
- }
-
- if ((mask & CGROUP_MASK_DEVICES) && !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, -EACCES) ? 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);
- }
- }
-
- if ((mask & CGROUP_MASK_PIDS) && !is_root) {
-
- if (c->tasks_max != (uint64_t) -1) {
- char buf[DECIMAL_STR_MAX(uint64_t) + 2];
-
- sprintf(buf, "%" PRIu64 "\n", c->tasks_max);
- r = cg_set_attribute("pids", path, "pids.max", buf);
- } else
- r = cg_set_attribute("pids", path, "pids.max", "max");
-
- if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set pids.max on %s: %m", path);
- }
-}
-
-CGroupMask cgroup_context_get_mask(CGroupContext *c) {
- CGroupMask mask = 0;
-
- /* Figure out which controllers we need */
-
- if (c->cpu_accounting ||
- c->cpu_shares != CGROUP_CPU_SHARES_INVALID ||
- c->startup_cpu_shares != CGROUP_CPU_SHARES_INVALID ||
- c->cpu_quota_per_sec_usec != USEC_INFINITY)
- mask |= CGROUP_MASK_CPUACCT | CGROUP_MASK_CPU;
-
- if (c->blockio_accounting ||
- c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ||
- c->startup_blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ||
- c->blockio_device_weights ||
- c->blockio_device_bandwidths)
- mask |= CGROUP_MASK_BLKIO;
-
- if (c->memory_accounting ||
- c->memory_limit != (uint64_t) -1)
- mask |= CGROUP_MASK_MEMORY;
-
- if (c->device_allow ||
- c->device_policy != CGROUP_AUTO)
- mask |= CGROUP_MASK_DEVICES;
-
- if (c->tasks_accounting ||
- c->tasks_max != (uint64_t) -1)
- mask |= CGROUP_MASK_PIDS;
-
- return mask;
-}
-
-CGroupMask unit_get_own_mask(Unit *u) {
- CGroupContext *c;
-
- /* Returns the mask of controllers the unit needs for itself */
-
- c = unit_get_cgroup_context(u);
- if (!c)
- return 0;
-
- /* If delegation is turned on, then turn on all cgroups,
- * unless we are on the legacy hierarchy and the process we
- * fork into it is known to drop privileges, and hence
- * shouldn't get access to the controllers.
- *
- * Note that on the unified hierarchy it is safe to delegate
- * controllers to unprivileged services. */
-
- if (c->delegate) {
- ExecContext *e;
-
- e = unit_get_exec_context(u);
- if (!e ||
- exec_context_maintains_privileges(e) ||
- cg_unified() > 0)
- return _CGROUP_MASK_ALL;
- }
-
- return cgroup_context_get_mask(c);
-}
-
-CGroupMask unit_get_members_mask(Unit *u) {
- assert(u);
-
- /* Returns the mask of controllers all of the unit's children
- * require, merged */
-
- 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_own_mask(member) |
- unit_get_members_mask(member);
- }
- }
-
- u->cgroup_members_mask_valid = true;
- return u->cgroup_members_mask;
-}
-
-CGroupMask unit_get_siblings_mask(Unit *u) {
- assert(u);
-
- /* Returns the mask of controllers all of the unit's siblings
- * require, i.e. the members mask of the unit's parent slice
- * if there is one. */
-
- if (UNIT_ISSET(u->slice))
- return unit_get_members_mask(UNIT_DEREF(u->slice));
-
- return unit_get_own_mask(u) | unit_get_members_mask(u);
-}
-
-CGroupMask unit_get_subtree_mask(Unit *u) {
-
- /* Returns the mask of this subtree, meaning of the group
- * itself and its children. */
-
- return unit_get_own_mask(u) | unit_get_members_mask(u);
-}
-
-CGroupMask unit_get_target_mask(Unit *u) {
- CGroupMask mask;
-
- /* This returns the cgroup mask of all controllers to enable
- * for a specific cgroup, i.e. everything it needs itself,
- * plus all that its children need, plus all that its siblings
- * need. This is primarily useful on the legacy cgroup
- * hierarchy, where we need to duplicate each cgroup in each
- * hierarchy that shall be enabled for it. */
-
- mask = unit_get_own_mask(u) | unit_get_members_mask(u) | unit_get_siblings_mask(u);
- mask &= u->manager->cgroup_supported;
-
- return mask;
-}
-
-CGroupMask unit_get_enable_mask(Unit *u) {
- CGroupMask mask;
-
- /* This returns the cgroup mask of all controllers to enable
- * for the children of a specific cgroup. This is primarily
- * useful for the unified cgroup hierarchy, where each cgroup
- * controls which controllers are enabled for its children. */
-
- mask = unit_get_members_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) {
- CGroupMask m;
- bool more;
-
- assert(u);
-
- /* Calculate subtree mask */
- m = unit_get_subtree_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(CGroupMask 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;
-}
-
-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_set_cgroup_path(Unit *u, const char *path) {
- _cleanup_free_ char *p = NULL;
- int r;
-
- assert(u);
-
- if (path) {
- p = strdup(path);
- if (!p)
- return -ENOMEM;
- } else
- p = NULL;
-
- if (streq_ptr(u->cgroup_path, p))
- return 0;
-
- if (p) {
- r = hashmap_put(u->manager->cgroup_unit, p, u);
- if (r < 0)
- return r;
- }
-
- unit_release_cgroup(u);
-
- u->cgroup_path = p;
- p = NULL;
-
- return 1;
-}
-
-int unit_watch_cgroup(Unit *u) {
- _cleanup_free_ char *populated = NULL;
- int r;
-
- assert(u);
-
- if (!u->cgroup_path)
- return 0;
-
- if (u->cgroup_inotify_wd >= 0)
- return 0;
-
- /* Only applies to the unified hierarchy */
- r = cg_unified();
- if (r < 0)
- return log_unit_error_errno(u, r, "Failed detect wether the unified hierarchy is used: %m");
- if (r == 0)
- return 0;
-
- /* Don't watch the root slice, it's pointless. */
- if (unit_has_name(u, SPECIAL_ROOT_SLICE))
- return 0;
-
- r = hashmap_ensure_allocated(&u->manager->cgroup_inotify_wd_unit, &trivial_hash_ops);
- if (r < 0)
- return log_oom();
-
- r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, "cgroup.populated", &populated);
- if (r < 0)
- return log_oom();
-
- u->cgroup_inotify_wd = inotify_add_watch(u->manager->cgroup_inotify_fd, populated, IN_MODIFY);
- if (u->cgroup_inotify_wd < 0) {
-
- if (errno == ENOENT) /* If the directory is already
- * gone we don't need to track
- * it, so this is not an error */
- return 0;
-
- return log_unit_error_errno(u, errno, "Failed to add inotify watch descriptor for control group %s: %m", u->cgroup_path);
- }
-
- r = hashmap_put(u->manager->cgroup_inotify_wd_unit, INT_TO_PTR(u->cgroup_inotify_wd), u);
- if (r < 0)
- return log_unit_error_errno(u, r, "Failed to add inotify watch descriptor to hash map: %m");
-
- return 0;
-}
-
-static int unit_create_cgroup(
- Unit *u,
- CGroupMask target_mask,
- CGroupMask enable_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 = unit_set_cgroup_path(u, path);
- if (r == -EEXIST)
- return log_unit_error_errno(u, r, "Control group %s exists already.", path);
- if (r < 0)
- return log_unit_error_errno(u, r, "Failed to set unit's control group path to %s: %m", path);
- }
-
- /* First, create our own group */
- r = cg_create_everywhere(u->manager->cgroup_supported, target_mask, u->cgroup_path);
- if (r < 0)
- return log_unit_error_errno(u, r, "Failed to create cgroup %s: %m", u->cgroup_path);
-
- /* Start watching it */
- (void) unit_watch_cgroup(u);
-
- /* Enable all controllers we need */
- r = cg_enable_everywhere(u->manager->cgroup_supported, enable_mask, u->cgroup_path);
- if (r < 0)
- log_unit_warning_errno(u, r, "Failed to enable controllers on cgroup %s, ignoring: %m", u->cgroup_path);
-
- /* Keep track that this is now realized */
- u->cgroup_realized = true;
- u->cgroup_realized_mask = target_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_unit_warning_errno(u, r, "Failed to migrate cgroup from to %s, ignoring: %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, CGroupMask target_mask) {
- assert(u);
-
- return u->cgroup_realized && u->cgroup_realized_mask == target_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) {
- CGroupMask target_mask, enable_mask;
- int r;
-
- assert(u);
-
- if (u->in_cgroup_queue) {
- LIST_REMOVE(cgroup_queue, u->manager->cgroup_queue, u);
- u->in_cgroup_queue = false;
- }
-
- target_mask = unit_get_target_mask(u);
- if (unit_has_mask_realized(u, target_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 */
- enable_mask = unit_get_enable_mask(u);
- r = unit_create_cgroup(u, target_mask, enable_mask);
- if (r < 0)
- return r;
-
- /* Finally, apply the necessary attributes. */
- cgroup_context_apply(unit_get_cgroup_context(u), target_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, ignoring: %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) {
- assert(u);
-
- if (!UNIT_HAS_CGROUP_CONTEXT(u))
- 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_release_cgroup(Unit *u) {
- assert(u);
-
- /* Forgets all cgroup details for this cgroup */
-
- if (u->cgroup_path) {
- (void) hashmap_remove(u->manager->cgroup_unit, u->cgroup_path);
- u->cgroup_path = mfree(u->cgroup_path);
- }
-
- if (u->cgroup_inotify_wd >= 0) {
- if (inotify_rm_watch(u->manager->cgroup_inotify_fd, u->cgroup_inotify_wd) < 0)
- log_unit_debug_errno(u, errno, "Failed to remove cgroup inotify watch %i for %s, ignoring", u->cgroup_inotify_wd, u->id);
-
- (void) hashmap_remove(u->manager->cgroup_inotify_wd_unit, INT_TO_PTR(u->cgroup_inotify_wd));
- u->cgroup_inotify_wd = -1;
- }
-}
-
-void unit_prune_cgroup(Unit *u) {
- int r;
- bool is_root_slice;
-
- assert(u);
-
- /* Removes the cgroup, if empty and possible, and stops watching it. */
-
- if (!u->cgroup_path)
- return;
-
- is_root_slice = unit_has_name(u, SPECIAL_ROOT_SLICE);
-
- r = cg_trim_everywhere(u->manager->cgroup_supported, u->cgroup_path, !is_root_slice);
- if (r < 0) {
- log_debug_errno(r, "Failed to destroy cgroup %s, ignoring: %m", u->cgroup_path);
- return;
- }
-
- if (is_root_slice)
- return;
-
- unit_release_cgroup(u);
-
- u->cgroup_realized = false;
- u->cgroup_realized_mask = 0;
-}
-
-int unit_search_main_pid(Unit *u, pid_t *ret) {
- _cleanup_fclose_ FILE *f = NULL;
- pid_t pid = 0, npid, mypid;
- int r;
-
- assert(u);
- assert(ret);
-
- if (!u->cgroup_path)
- return -ENXIO;
-
- r = cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, &f);
- if (r < 0)
- return r;
-
- 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_process_ppid(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. */
-
- return -ENODATA;
-
- pid = npid;
- }
-
- *ret = pid;
- return 0;
-}
-
-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);
-
- r = cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, path, &f);
- if (r < 0)
- ret = r;
- else {
- 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;
- }
-
- r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, path, &d);
- if (r < 0) {
- if (ret >= 0)
- ret = r;
- } else {
- 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;
- }
-
- return ret;
-}
-
-int unit_watch_all_pids(Unit *u) {
- assert(u);
-
- /* Adds all PIDs from our cgroup to the set of PIDs we
- * watch. This is a fallback logic for cases where we do not
- * get reliable cgroup empty notifications: we try to use
- * SIGCHLD as replacement. */
-
- if (!u->cgroup_path)
- return -ENOENT;
-
- if (cg_unified() > 0) /* On unified we can use proper notifications */
- return 0;
-
- return unit_watch_pids_in_path(u, u->cgroup_path);
-}
-
-int unit_notify_cgroup_empty(Unit *u) {
- int r;
-
- assert(u);
-
- if (!u->cgroup_path)
- return 0;
-
- r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path);
- if (r <= 0)
- return r;
-
- unit_add_to_gc_queue(u);
-
- if (UNIT_VTABLE(u)->notify_cgroup_empty)
- UNIT_VTABLE(u)->notify_cgroup_empty(u);
-
- return 0;
-}
-
-static int on_cgroup_inotify_event(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
- Manager *m = userdata;
-
- assert(s);
- assert(fd >= 0);
- assert(m);
-
- for (;;) {
- union inotify_event_buffer buffer;
- struct inotify_event *e;
- ssize_t l;
-
- l = read(fd, &buffer, sizeof(buffer));
- if (l < 0) {
- if (errno == EINTR || errno == EAGAIN)
- return 0;
-
- return log_error_errno(errno, "Failed to read control group inotify events: %m");
- }
-
- FOREACH_INOTIFY_EVENT(e, buffer, l) {
- Unit *u;
-
- if (e->wd < 0)
- /* Queue overflow has no watch descriptor */
- continue;
-
- if (e->mask & IN_IGNORED)
- /* The watch was just removed */
- continue;
-
- u = hashmap_get(m->cgroup_inotify_wd_unit, INT_TO_PTR(e->wd));
- if (!u) /* Not that inotify might deliver
- * events for a watch even after it
- * was removed, because it was queued
- * before the removal. Let's ignore
- * this here safely. */
- continue;
-
- (void) unit_notify_cgroup_empty(u);
- }
- }
-}
-
-int manager_setup_cgroup(Manager *m) {
- _cleanup_free_ char *path = NULL;
- CGroupController c;
- int r, unified;
- char *e;
-
- assert(m);
-
- /* 1. Determine hierarchy */
- m->cgroup_root = mfree(m->cgroup_root);
- 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");
-
- /* Chop off the init scope, if we are already located in it */
- e = endswith(m->cgroup_root, "/" SPECIAL_INIT_SCOPE);
-
- /* LEGACY: Also chop off the system slice if we are in
- * it. This is to support live upgrades from older systemd
- * versions where PID 1 was moved there. Also see
- * cg_get_root_path(). */
- if (!e && m->running_as == MANAGER_SYSTEM) {
- e = endswith(m->cgroup_root, "/" SPECIAL_SYSTEM_SLICE);
- if (!e)
- e = endswith(m->cgroup_root, "/system"); /* even more legacy */
- }
- 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. */
- while ((e = endswith(m->cgroup_root, "/")))
- *e = 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");
-
- unified = cg_unified();
- if (unified < 0)
- return log_error_errno(r, "Couldn't determine if we are running in the unified hierarchy: %m");
- if (unified > 0)
- log_debug("Unified cgroup hierarchy is located at %s.", path);
- else
- log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
-
- if (!m->test_run) {
- const char *scope_path;
-
- /* 3. Install agent */
- if (unified) {
-
- /* In the unified hierarchy we can can get
- * cgroup empty notifications via inotify. */
-
- m->cgroup_inotify_event_source = sd_event_source_unref(m->cgroup_inotify_event_source);
- safe_close(m->cgroup_inotify_fd);
-
- m->cgroup_inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
- if (m->cgroup_inotify_fd < 0)
- return log_error_errno(errno, "Failed to create control group inotify object: %m");
-
- r = sd_event_add_io(m->event, &m->cgroup_inotify_event_source, m->cgroup_inotify_fd, EPOLLIN, on_cgroup_inotify_event, m);
- if (r < 0)
- return log_error_errno(r, "Failed to watch control group inotify object: %m");
-
- r = sd_event_source_set_priority(m->cgroup_inotify_event_source, SD_EVENT_PRIORITY_IDLE - 5);
- if (r < 0)
- return log_error_errno(r, "Failed to set priority of inotify event source: %m");
-
- (void) sd_event_source_set_description(m->cgroup_inotify_event_source, "cgroup-inotify");
-
- } else if (m->running_as == MANAGER_SYSTEM) {
-
- /* On the legacy hierarchy we only get
- * notifications via cgroup agents. (Which
- * isn't really reliable, since it does not
- * generate events when control groups with
- * children run empty. */
-
- r = 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 if (r == 0)
- log_debug("Release agent already installed.");
- }
-
- /* 4. Make sure we are in the special "init.scope" unit in the root slice. */
- scope_path = strjoina(m->cgroup_root, "/" SPECIAL_INIT_SCOPE);
- r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, scope_path, 0);
- if (r < 0)
- return log_error_errno(r, "Failed to create %s control group: %m", scope_path);
-
- /* also, move all other userspace processes remaining
- * in the root cgroup into that scope. */
- r = cg_migrate(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, SYSTEMD_CGROUP_CONTROLLER, scope_path, false);
- if (r < 0)
- log_warning_errno(r, "Couldn't move remaining userspace processes, ignoring: %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... */
- if (!unified)
- (void) cg_set_attribute("memory", "/", "memory.use_hierarchy", "1");
- }
-
- /* 7. Figure out which controllers are supported */
- r = cg_mask_supported(&m->cgroup_supported);
- if (r < 0)
- return log_error_errno(r, "Failed to determine supported controllers: %m");
-
- for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++)
- log_debug("Controller '%s' supported: %s", cgroup_controller_to_string(c), yes_no(m->cgroup_supported & c));
-
- 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)
- (void) cg_trim(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, false);
-
- m->cgroup_inotify_wd_unit = hashmap_free(m->cgroup_inotify_wd_unit);
-
- m->cgroup_inotify_event_source = sd_event_source_unref(m->cgroup_inotify_event_source);
- m->cgroup_inotify_fd = safe_close(m->cgroup_inotify_fd);
-
- m->pin_cgroupfs_fd = safe_close(m->pin_cgroupfs_fd);
-
- m->cgroup_root = mfree(m->cgroup_root);
-}
-
-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 || e == p)
- return hashmap_get(m->cgroup_unit, SPECIAL_ROOT_SLICE);
-
- *e = 0;
-
- u = hashmap_get(m->cgroup_unit, p);
- if (u)
- return u;
- }
-}
-
-Unit *manager_get_unit_by_pid_cgroup(Manager *m, pid_t pid) {
- _cleanup_free_ char *cgroup = NULL;
- int r;
-
- assert(m);
-
- if (pid <= 0)
- 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);
-}
-
-Unit *manager_get_unit_by_pid(Manager *m, pid_t pid) {
- Unit *u;
-
- assert(m);
-
- if (pid <= 0)
- return NULL;
-
- if (pid == 1)
- return hashmap_get(m->units, SPECIAL_INIT_SCOPE);
-
- u = hashmap_get(m->watch_pids1, PID_TO_PTR(pid));
- if (u)
- return u;
-
- u = hashmap_get(m->watch_pids2, PID_TO_PTR(pid));
- if (u)
- return u;
-
- return manager_get_unit_by_pid_cgroup(m, pid);
-}
-
-int manager_notify_cgroup_empty(Manager *m, const char *cgroup) {
- Unit *u;
-
- assert(m);
- assert(cgroup);
-
- u = manager_get_unit_by_cgroup(m, cgroup);
- if (!u)
- return 0;
-
- return unit_notify_cgroup_empty(u);
-}
-
-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_MASK_MEMORY) == 0)
- return -ENODATA;
-
- if (cg_unified() <= 0)
- r = cg_get_attribute("memory", u->cgroup_path, "memory.usage_in_bytes", &v);
- else
- r = cg_get_attribute("memory", u->cgroup_path, "memory.current", &v);
- if (r == -ENOENT)
- return -ENODATA;
- if (r < 0)
- return r;
-
- return safe_atou64(v, ret);
-}
-
-int unit_get_tasks_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_MASK_PIDS) == 0)
- return -ENODATA;
-
- r = cg_get_attribute("pids", u->cgroup_path, "pids.current", &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_MASK_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;
-}
-
-bool unit_cgroup_delegate(Unit *u) {
- CGroupContext *c;
-
- assert(u);
-
- c = unit_get_cgroup_context(u);
- if (!c)
- return false;
-
- return c->delegate;
-}
-
-void unit_invalidate_cgroup(Unit *u, CGroupMask m) {
- assert(u);
-
- if (!UNIT_HAS_CGROUP_CONTEXT(u))
- return;
-
- if (m == 0)
- return;
-
- if ((u->cgroup_realized_mask & m) == 0)
- return;
-
- u->cgroup_realized_mask &= ~m;
- unit_add_to_cgroup_queue(u);
-}
-
-void manager_invalidate_startup_units(Manager *m) {
- Iterator i;
- Unit *u;
-
- assert(m);
-
- SET_FOREACH(u, m->startup_units, i)
- unit_invalidate_cgroup(u, CGROUP_MASK_CPU|CGROUP_MASK_BLKIO);
-}
-
-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 360bbca30f..0000000000
--- a/src/core/cgroup.h
+++ /dev/null
@@ -1,155 +0,0 @@
-#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;
- uint64_t 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;
- bool tasks_accounting;
-
- uint64_t cpu_shares;
- uint64_t startup_cpu_shares;
- usec_t cpu_quota_per_sec_usec;
-
- uint64_t blockio_weight;
- uint64_t 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);
-
- uint64_t tasks_max;
-
- bool delegate;
-};
-
-#include "cgroup-util.h"
-#include "unit.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, CGroupMask mask, const char *path, ManagerState state);
-
-CGroupMask 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);
-
-CGroupMask unit_get_own_mask(Unit *u);
-CGroupMask unit_get_siblings_mask(Unit *u);
-CGroupMask unit_get_members_mask(Unit *u);
-CGroupMask unit_get_subtree_mask(Unit *u);
-
-CGroupMask unit_get_target_mask(Unit *u);
-CGroupMask unit_get_enable_mask(Unit *u);
-
-void unit_update_cgroup_members_masks(Unit *u);
-
-char *unit_default_cgroup_path(Unit *u);
-int unit_set_cgroup_path(Unit *u, const char *path);
-
-int unit_realize_cgroup(Unit *u);
-void unit_release_cgroup(Unit *u);
-void unit_prune_cgroup(Unit *u);
-int unit_watch_cgroup(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_cgroup(Manager *m, pid_t pid);
-Unit* manager_get_unit_by_pid(Manager *m, pid_t pid);
-
-int unit_search_main_pid(Unit *u, pid_t *ret);
-int unit_watch_all_pids(Unit *u);
-
-int unit_get_memory_current(Unit *u, uint64_t *ret);
-int unit_get_tasks_current(Unit *u, uint64_t *ret);
-int unit_get_cpu_usage(Unit *u, nsec_t *ret);
-int unit_reset_cpu_usage(Unit *u);
-
-bool unit_cgroup_delegate(Unit *u);
-
-int unit_notify_cgroup_empty(Unit *u);
-int manager_notify_cgroup_empty(Manager *m, const char *group);
-
-void unit_invalidate_cgroup(Unit *u, CGroupMask m);
-
-void manager_invalidate_startup_units(Manager *m);
-
-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 b2806ad86f..0000000000
--- a/src/core/dbus-automount.c
+++ /dev/null
@@ -1,34 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "automount.h"
-#include "bus-util.h"
-#include "dbus-automount.h"
-#include "string-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_PROPERTY("TimeoutIdleUSec", "t", bus_property_get_usec, offsetof(Automount, timeout_idle_usec), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_VTABLE_END
-};
diff --git a/src/core/dbus-automount.h b/src/core/dbus-automount.h
deleted file mode 100644
index 7b51eb973a..0000000000
--- a/src/core/dbus-automount.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#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 cf816ba15b..0000000000
--- a/src/core/dbus-busname.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/***
- 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 "busname.h"
-#include "dbus-busname.h"
-#include "string-util.h"
-#include "unit.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 8643d1a404..0000000000
--- a/src/core/dbus-busname.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#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 859d155ec1..0000000000
--- a/src/core/dbus-cgroup.c
+++ /dev/null
@@ -1,699 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "alloc-util.h"
-#include "bus-util.h"
-#include "cgroup-util.h"
-#include "cgroup.h"
-#include "dbus-cgroup.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "path-util.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);
-}
-
-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", NULL, offsetof(CGroupContext, cpu_shares), 0),
- SD_BUS_PROPERTY("StartupCPUShares", "t", NULL, 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", NULL, offsetof(CGroupContext, blockio_weight), 0),
- SD_BUS_PROPERTY("StartupBlockIOWeight", "t", NULL, 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_PROPERTY("TasksAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, tasks_accounting), 0),
- SD_BUS_PROPERTY("TasksMax", "t", NULL, offsetof(CGroupContext, tasks_max), 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;
- unit_invalidate_cgroup(u, CGROUP_MASK_CPUACCT|CGROUP_MASK_CPU);
- unit_write_drop_in_private(u, mode, name, b ? "CPUAccounting=yes" : "CPUAccounting=no");
- }
-
- return 1;
-
- } else if (streq(name, "CPUShares")) {
- uint64_t shares;
-
- r = sd_bus_message_read(message, "t", &shares);
- if (r < 0)
- return r;
-
- if (!CGROUP_CPU_SHARES_IS_OK(shares))
- return sd_bus_error_set_errnof(error, EINVAL, "CPUShares value out of range");
-
- if (mode != UNIT_CHECK) {
- c->cpu_shares = shares;
- unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
-
- if (shares == CGROUP_CPU_SHARES_INVALID)
- unit_write_drop_in_private(u, mode, name, "CPUShares=");
- else
- unit_write_drop_in_private_format(u, mode, name, "CPUShares=%" PRIu64, shares);
- }
-
- return 1;
-
- } else if (streq(name, "StartupCPUShares")) {
- uint64_t shares;
-
- r = sd_bus_message_read(message, "t", &shares);
- if (r < 0)
- return r;
-
- if (!CGROUP_CPU_SHARES_IS_OK(shares))
- return sd_bus_error_set_errnof(error, EINVAL, "StartupCPUShares value out of range");
-
- if (mode != UNIT_CHECK) {
- c->startup_cpu_shares = shares;
- unit_invalidate_cgroup(u, CGROUP_MASK_CPU);
-
- if (shares == CGROUP_CPU_SHARES_INVALID)
- unit_write_drop_in_private(u, mode, name, "StartupCPUShares=");
- else
- unit_write_drop_in_private_format(u, mode, name, "StartupCPUShares=%" PRIu64, shares);
- }
-
- 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;
- unit_invalidate_cgroup(u, CGROUP_MASK_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;
- unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
- unit_write_drop_in_private(u, mode, name, b ? "BlockIOAccounting=yes" : "BlockIOAccounting=no");
- }
-
- return 1;
-
- } else if (streq(name, "BlockIOWeight")) {
- uint64_t weight;
-
- r = sd_bus_message_read(message, "t", &weight);
- if (r < 0)
- return r;
-
- if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight))
- return sd_bus_error_set_errnof(error, EINVAL, "BlockIOWeight value out of range");
-
- if (mode != UNIT_CHECK) {
- c->blockio_weight = weight;
- unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
-
- if (weight == CGROUP_BLKIO_WEIGHT_INVALID)
- unit_write_drop_in_private(u, mode, name, "BlockIOWeight=");
- else
- unit_write_drop_in_private_format(u, mode, name, "BlockIOWeight=%" PRIu64, weight);
- }
-
- return 1;
-
- } else if (streq(name, "StartupBlockIOWeight")) {
- uint64_t weight;
-
- r = sd_bus_message_read(message, "t", &weight);
- if (r < 0)
- return r;
-
- if (CGROUP_BLKIO_WEIGHT_IS_OK(weight))
- return sd_bus_error_set_errnof(error, EINVAL, "StartupBlockIOWeight value out of range");
-
- if (mode != UNIT_CHECK) {
- c->startup_blockio_weight = weight;
- unit_invalidate_cgroup(u, CGROUP_MASK_BLKIO);
-
- if (weight == CGROUP_BLKIO_WEIGHT_INVALID)
- unit_write_drop_in_private(u, mode, name, "StartupBlockIOWeight=");
- else
- unit_write_drop_in_private_format(u, mode, name, "StartupBlockIOWeight=%" PRIu64, weight);
- }
-
- 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);
- }
-
- unit_invalidate_cgroup(u, CGROUP_MASK_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);
- }
-
- r = fflush_and_check(f);
- if (r < 0)
- return r;
- unit_write_drop_in_private(u, mode, name, buf);
- }
-
- return 1;
-
- } else if (streq(name, "BlockIODeviceWeight")) {
- const char *path;
- uint64_t weight;
- 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, &weight)) > 0) {
-
- if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight) || weight == CGROUP_BLKIO_WEIGHT_INVALID)
- 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 = weight;
- }
-
- 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);
- }
-
- unit_invalidate_cgroup(u, CGROUP_MASK_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 %" PRIu64 "\n", a->path, a->weight);
-
- r = fflush_and_check(f);
- if (r < 0)
- return r;
- 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;
- unit_invalidate_cgroup(u, CGROUP_MASK_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;
- unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
-
- if (limit == (uint64_t) -1)
- unit_write_drop_in_private(u, mode, name, "MemoryLimit=infinity");
- else
- unit_write_drop_in_private_format(u, mode, name, "MemoryLimit=%" PRIu64, 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;
- unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
-
- 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);
- }
-
- unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
-
- 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" : "");
-
- r = fflush_and_check(f);
- if (r < 0)
- return r;
- unit_write_drop_in_private(u, mode, name, buf);
- }
-
- return 1;
-
- } else if (streq(name, "TasksAccounting")) {
- int b;
-
- r = sd_bus_message_read(message, "b", &b);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- c->tasks_accounting = b;
- unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
- unit_write_drop_in_private(u, mode, name, b ? "TasksAccounting=yes" : "TasksAccounting=no");
- }
-
- return 1;
-
- } else if (streq(name, "TasksMax")) {
- uint64_t limit;
-
- r = sd_bus_message_read(message, "t", &limit);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- c->tasks_max = limit;
- unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
-
- if (limit == (uint64_t) -1)
- unit_write_drop_in_private(u, mode, name, "TasksMax=infinity");
- else
- unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu64, limit);
- }
-
- 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 b2212fe44e..0000000000
--- a/src/core/dbus-cgroup.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#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 e1a12224d3..0000000000
--- a/src/core/dbus-device.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "dbus-device.h"
-#include "device.h"
-#include "unit.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 eb1d8c3278..0000000000
--- a/src/core/dbus-device.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#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 f2fc301f8e..0000000000
--- a/src/core/dbus-execute.c
+++ /dev/null
@@ -1,1564 +0,0 @@
-/***
- 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 "af-list.h"
-#include "alloc-util.h"
-#include "bus-util.h"
-#include "capability-util.h"
-#include "dbus-execute.h"
-#include "env-util.h"
-#include "execute.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "ioprio.h"
-#include "missing.h"
-#include "namespace.h"
-#include "parse-util.h"
-#include "path-util.h"
-#include "process-util.h"
-#include "rlimit-util.h"
-#ifdef HAVE_SECCOMP
-#include "seccomp-util.h"
-#endif
-#include "strv.h"
-#include "syslog-util.h"
-#include "utf8.h"
-
-BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_exec_output, exec_output, ExecOutput);
-
-static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_input, exec_input, ExecInput);
-
-static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_exec_utmp_mode, exec_utmp_mode, ExecUtmpMode);
-
-static BUS_DEFINE_PROPERTY_GET_ENUM(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_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_atoi32(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);
-
- return sd_bus_message_append(reply, "t", c->capability_bounding_set);
-}
-
-static int property_get_ambient_capabilities(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- ExecContext *c = userdata;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- return sd_bus_message_append(reply, "t", c->capability_ambient_set);
-}
-
-static int property_get_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);
-}
-
-static int property_get_working_directory(
- 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;
- const char *wd;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- if (c->working_directory_home)
- wd = "~";
- else
- wd = c->working_directory;
-
- if (c->working_directory_missing_ok)
- wd = strjoina("!", wd);
-
- return sd_bus_message_append(reply, "s", wd);
-}
-
-static int property_get_syslog_level(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- ExecContext *c = userdata;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- return sd_bus_message_append(reply, "i", LOG_PRI(c->syslog_priority));
-}
-
-static int property_get_syslog_facility(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- ExecContext *c = userdata;
-
- assert(bus);
- assert(reply);
- assert(c);
-
- return sd_bus_message_append(reply, "i", LOG_FAC(c->syslog_priority));
-}
-
-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("PassEnvironment", "as", NULL, offsetof(ExecContext, pass_environment), 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", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitCPUSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitFSIZE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitFSIZESoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitDATA", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitDATASoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitSTACK", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitSTACKSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitCORE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitCORESoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitRSS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitRSSSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitNOFILE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitNOFILESoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitAS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitASSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitNPROC", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitNPROCSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitMEMLOCK", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitMEMLOCKSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitLOCKS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitLOCKSSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitSIGPENDING", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitSIGPENDINGSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitMSGQUEUE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitMSGQUEUESoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitNICE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitNICESoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitRTPRIO", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitRTPRIOSoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitRTTIME", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitRTTIMESoft", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("WorkingDirectory", "s", property_get_working_directory, 0, 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("SyslogLevel", "i", property_get_syslog_level, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("SyslogFacility", "i", property_get_syslog_facility, 0, SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("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("AmbientCapabilities", "t", property_get_ambient_capabilities, 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("UtmpMode", "s", property_get_exec_utmp_mode, offsetof(ExecContext, utmp_mode), 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) {
-
- const char *soft = NULL;
- int r, ri;
-
- 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)) {
- c->user = mfree(c->user);
- } 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)) {
- c->group = mfree(c->group);
- } 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, "SyslogIdentifier")) {
- const char *id;
-
- r = sd_bus_message_read(message, "s", &id);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
-
- if (isempty(id)) {
- c->syslog_identifier = mfree(c->syslog_identifier);
- } else {
- char *t;
-
- t = strdup(id);
- if (!t)
- return -ENOMEM;
-
- free(c->syslog_identifier);
- c->syslog_identifier = t;
- }
-
- unit_write_drop_in_private_format(u, mode, name, "SyslogIdentifier=%s\n", id);
- }
-
- return 1;
- } else if (streq(name, "SyslogLevel")) {
- int level;
-
- r = sd_bus_message_read(message, "i", &level);
- if (r < 0)
- return r;
-
- if (!log_level_is_valid(level))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log level value out of range");
-
- if (mode != UNIT_CHECK) {
- c->syslog_priority = (c->syslog_priority & LOG_FACMASK) | level;
- unit_write_drop_in_private_format(u, mode, name, "SyslogLevel=%i\n", level);
- }
-
- return 1;
- } else if (streq(name, "SyslogFacility")) {
- int facility;
-
- r = sd_bus_message_read(message, "i", &facility);
- if (r < 0)
- return r;
-
- if (!log_facility_unshifted_is_valid(facility))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log facility value out of range");
-
- if (mode != UNIT_CHECK) {
- c->syslog_priority = (facility << 3) | LOG_PRI(c->syslog_priority);
- unit_write_drop_in_private_format(u, mode, name, "SyslogFacility=%i\n", facility);
- }
-
- 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 (STR_IN_SET(name, "TTYPath", "RootDirectory")) {
- const char *s;
-
- r = sd_bus_message_read(message, "s", &s);
- if (r < 0)
- return r;
-
- if (!path_is_absolute(s))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "%s takes an absolute path", name);
-
- if (mode != UNIT_CHECK) {
- if (streq(name, "TTYPath"))
- r = free_and_strdup(&c->tty_path, s);
- else {
- assert(streq(name, "RootDirectory"));
- r = free_and_strdup(&c->root_directory, s);
- }
- if (r < 0)
- return r;
-
- unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s);
- }
-
- return 1;
-
- } else if (streq(name, "WorkingDirectory")) {
- const char *s;
- bool missing_ok;
-
- r = sd_bus_message_read(message, "s", &s);
- if (r < 0)
- return r;
-
- if (s[0] == '-') {
- missing_ok = true;
- s++;
- } else
- missing_ok = false;
-
- if (!streq(s, "~") && !path_is_absolute(s))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "WorkingDirectory= expects an absolute path or '~'");
-
- if (mode != UNIT_CHECK) {
- if (streq(s, "~")) {
- c->working_directory = mfree(c->working_directory);
- c->working_directory_home = true;
- } else {
- r = free_and_strdup(&c->working_directory, s);
- if (r < 0)
- return r;
-
- c->working_directory_home = false;
- }
-
- c->working_directory_missing_ok = missing_ok;
- unit_write_drop_in_private_format(u, mode, name, "WorkingDirectory=%s%s", missing_ok ? "-" : "", s);
- }
-
- 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 (STR_IN_SET(name,
- "IgnoreSIGPIPE", "TTYVHangup", "TTYReset",
- "PrivateTmp", "PrivateDevices", "PrivateNetwork",
- "NoNewPrivileges", "SyslogLevelPrefix")) {
- int b;
-
- r = sd_bus_message_read(message, "b", &b);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- if (streq(name, "IgnoreSIGPIPE"))
- c->ignore_sigpipe = b;
- else if (streq(name, "TTYVHangup"))
- c->tty_vhangup = b;
- else if (streq(name, "TTYReset"))
- c->tty_reset = b;
- else if (streq(name, "PrivateTmp"))
- c->private_tmp = b;
- else if (streq(name, "PrivateDevices"))
- c->private_devices = b;
- else if (streq(name, "PrivateNetwork"))
- c->private_network = b;
- else if (streq(name, "NoNewPrivileges"))
- c->no_new_privileges = b;
- else if (streq(name, "SyslogLevelPrefix"))
- c->syslog_level_prefix = b;
-
- unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, yes_no(b));
- }
-
- return 1;
-
- } else if (streq(name, "UtmpIdentifier")) {
- const char *id;
-
- r = sd_bus_message_read(message, "s", &id);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- if (isempty(id))
- c->utmp_id = mfree(c->utmp_id);
- else if (free_and_strdup(&c->utmp_id, id) < 0)
- return -ENOMEM;
-
- unit_write_drop_in_private_format(u, mode, name, "UtmpIdentifier=%s\n", strempty(id));
- }
-
- return 1;
-
- } else if (streq(name, "UtmpMode")) {
- const char *s;
- ExecUtmpMode m;
-
- r = sd_bus_message_read(message, "s", &s);
- if (r < 0)
- return r;
-
- m = exec_utmp_mode_from_string(s);
- if (m < 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid utmp mode");
-
- if (mode != UNIT_CHECK) {
- c->utmp_mode = m;
-
- unit_write_drop_in_private_format(u, mode, name, "UtmpMode=%s\n", exec_utmp_mode_to_string(m));
- }
-
- return 1;
-
- } else if (streq(name, "PAMName")) {
- const char *n;
-
- r = sd_bus_message_read(message, "s", &n);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- if (isempty(n))
- c->pam_name = mfree(c->pam_name);
- else if (free_and_strdup(&c->pam_name, n) < 0)
- return -ENOMEM;
-
- unit_write_drop_in_private_format(u, mode, name, "PAMName=%s\n", strempty(n));
- }
-
- 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;
-
- if (strv_length(l) == 0) {
- c->environment = strv_free(c->environment);
- unit_write_drop_in_private_format(u, mode, name, "Environment=\n");
- } else {
- 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 (streq(name, "TimerSlackNSec")) {
-
- nsec_t n;
-
- r = sd_bus_message_read(message, "t", &n);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- c->timer_slack_nsec = n;
- unit_write_drop_in_private_format(u, mode, name, "TimerSlackNSec=" NSEC_FMT "\n", n);
- }
-
- return 1;
-
- } else if (streq(name, "OOMScoreAdjust")) {
- int oa;
-
- r = sd_bus_message_read(message, "i", &oa);
- if (r < 0)
- return r;
-
- if (!oom_score_adjust_is_valid(oa))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "OOM score adjust value out of range");
-
- if (mode != UNIT_CHECK) {
- c->oom_score_adjust = oa;
- c->oom_score_adjust_set = true;
- unit_write_drop_in_private_format(u, mode, name, "OOMScoreAdjust=%i\n", oa);
- }
-
- return 1;
-
- } else if (streq(name, "EnvironmentFiles")) {
-
- _cleanup_free_ char *joined = NULL;
- _cleanup_fclose_ FILE *f = NULL;
- _cleanup_free_ char **l = NULL;
- size_t size = 0;
- char **i;
-
- r = sd_bus_message_enter_container(message, 'a', "(sb)");
- if (r < 0)
- return r;
-
- f = open_memstream(&joined, &size);
- if (!f)
- return -ENOMEM;
-
- STRV_FOREACH(i, c->environment_files)
- fprintf(f, "EnvironmentFile=%s\n", *i);
-
- while ((r = sd_bus_message_enter_container(message, 'r', "sb")) > 0) {
- const char *path;
- int b;
-
- r = sd_bus_message_read(message, "sb", &path, &b);
- if (r < 0)
- return r;
-
- r = sd_bus_message_exit_container(message);
- if (r < 0)
- return r;
-
- if (!isempty(path) && !path_is_absolute(path))
- return sd_bus_error_set_errnof(error, EINVAL, "Path %s is not absolute.", path);
-
- if (mode != UNIT_CHECK) {
- char *buf = NULL;
-
- buf = strjoin(b ? "-" : "", path, NULL);
- if (!buf)
- return -ENOMEM;
-
- fprintf(f, "EnvironmentFile=%s\n", buf);
-
- r = strv_consume(&l, buf);
- if (r < 0)
- return r;
- }
- }
- if (r < 0)
- return r;
-
- r = sd_bus_message_exit_container(message);
- if (r < 0)
- return r;
-
- r = fflush_and_check(f);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- if (strv_isempty(l)) {
- c->environment_files = strv_free(c->environment_files);
- unit_write_drop_in_private(u, mode, name, "EnvironmentFile=\n");
- } else {
- r = strv_extend_strv(&c->environment_files, l, true);
- if (r < 0)
- return r;
-
- unit_write_drop_in_private(u, mode, name, joined);
- }
- }
-
- return 1;
-
- } else if (streq(name, "PassEnvironment")) {
-
- _cleanup_strv_free_ char **l = NULL;
-
- r = sd_bus_message_read_strv(message, &l);
- if (r < 0)
- return r;
-
- if (!strv_env_name_is_valid(l))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid PassEnvironment block.");
-
- if (mode != UNIT_CHECK) {
- if (strv_isempty(l)) {
- c->pass_environment = strv_free(c->pass_environment);
- unit_write_drop_in_private_format(u, mode, name, "PassEnvironment=\n");
- } else {
- _cleanup_free_ char *joined = NULL;
-
- r = strv_extend_strv(&c->pass_environment, l, true);
- if (r < 0)
- return r;
-
- joined = strv_join_quoted(c->pass_environment);
- if (!joined)
- return -ENOMEM;
-
- unit_write_drop_in_private_format(u, mode, name, "PassEnvironment=%s\n", joined);
- }
- }
-
- return 1;
-
- } else if (STR_IN_SET(name, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) {
-
- _cleanup_strv_free_ char **l = NULL;
- char ***dirs;
- char **p;
-
- r = sd_bus_message_read_strv(message, &l);
- if (r < 0)
- return r;
-
- STRV_FOREACH(p, l) {
- int offset;
- if (!utf8_is_valid(*p))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s", name);
-
- offset = **p == '-';
- if (!path_is_absolute(*p + offset))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s", name);
- }
-
- if (mode != UNIT_CHECK) {
- _cleanup_free_ char *joined = NULL;
-
- if (streq(name, "ReadWriteDirectories"))
- dirs = &c->read_write_dirs;
- else if (streq(name, "ReadOnlyDirectories"))
- dirs = &c->read_only_dirs;
- else /* "InaccessibleDirectories" */
- dirs = &c->inaccessible_dirs;
-
- if (strv_length(l) == 0) {
- *dirs = strv_free(*dirs);
- unit_write_drop_in_private_format(u, mode, name, "%s=\n", name);
- } else {
- r = strv_extend_strv(dirs, l, true);
-
- if (r < 0)
- return -ENOMEM;
-
- joined = strv_join_quoted(*dirs);
- if (!joined)
- return -ENOMEM;
-
- unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, joined);
- }
-
- }
-
- return 1;
-
- } else if (streq(name, "ProtectSystem")) {
- const char *s;
- ProtectSystem ps;
-
- r = sd_bus_message_read(message, "s", &s);
- if (r < 0)
- return r;
-
- r = parse_boolean(s);
- if (r > 0)
- ps = PROTECT_SYSTEM_YES;
- else if (r == 0)
- ps = PROTECT_SYSTEM_NO;
- else {
- ps = protect_system_from_string(s);
- if (ps < 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Failed to parse protect system value");
- }
-
- if (mode != UNIT_CHECK) {
- c->protect_system = ps;
- unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s);
- }
-
- return 1;
-
- } else if (streq(name, "ProtectHome")) {
- const char *s;
- ProtectHome ph;
-
- r = sd_bus_message_read(message, "s", &s);
- if (r < 0)
- return r;
-
- r = parse_boolean(s);
- if (r > 0)
- ph = PROTECT_HOME_YES;
- else if (r == 0)
- ph = PROTECT_HOME_NO;
- else {
- ph = protect_home_from_string(s);
- if (ph < 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Failed to parse protect home value");
- }
-
- if (mode != UNIT_CHECK) {
- c->protect_home = ph;
- unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s);
- }
-
- return 1;
-
- } else if (streq(name, "RuntimeDirectory")) {
- _cleanup_strv_free_ char **l = NULL;
- char **p;
-
- r = sd_bus_message_read_strv(message, &l);
- if (r < 0)
- return r;
-
- STRV_FOREACH(p, l) {
- if (!filename_is_valid(*p))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Runtime directory is not valid %s", *p);
- }
-
- if (mode != UNIT_CHECK) {
- _cleanup_free_ char *joined = NULL;
-
- if (strv_isempty(l)) {
- c->runtime_directory = strv_free(c->runtime_directory);
- unit_write_drop_in_private_format(u, mode, name, "%s=\n", name);
- } else {
- r = strv_extend_strv(&c->runtime_directory, l, true);
-
- if (r < 0)
- return -ENOMEM;
-
- joined = strv_join_quoted(c->runtime_directory);
- if (!joined)
- return -ENOMEM;
-
- unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, joined);
- }
- }
-
- return 1;
-
- }
-
- ri = rlimit_from_string(name);
- if (ri < 0) {
- soft = endswith(name, "Soft");
- if (soft) {
- const char *n;
-
- n = strndupa(name, soft - name);
- ri = rlimit_from_string(n);
- if (ri >= 0)
- name = n;
-
- }
- }
-
- if (ri >= 0) {
- uint64_t rl;
- rlim_t x;
-
- r = sd_bus_message_read(message, "t", &rl);
- if (r < 0)
- return r;
-
- if (rl == (uint64_t) -1)
- x = RLIM_INFINITY;
- else {
- x = (rlim_t) rl;
-
- if ((uint64_t) x != rl)
- return -ERANGE;
- }
-
- if (mode != UNIT_CHECK) {
- _cleanup_free_ char *f = NULL;
- struct rlimit nl;
-
- if (c->rlimit[ri]) {
- nl = *c->rlimit[ri];
-
- if (soft)
- nl.rlim_cur = x;
- else
- nl.rlim_max = x;
- } else
- /* When the resource limit is not initialized yet, then assign the value to both fields */
- nl = (struct rlimit) {
- .rlim_cur = x,
- .rlim_max = x,
- };
-
- r = rlimit_format(&nl, &f);
- if (r < 0)
- return r;
-
- if (c->rlimit[ri])
- *c->rlimit[ri] = nl;
- else {
- c->rlimit[ri] = newdup(struct rlimit, &nl, 1);
- if (!c->rlimit[ri])
- return -ENOMEM;
- }
-
- unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, f);
- }
-
- return 1;
- }
-
- return 0;
-}
diff --git a/src/core/dbus-execute.h b/src/core/dbus-execute.h
deleted file mode 100644
index d0aa8e1dd5..0000000000
--- a/src/core/dbus-execute.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#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 97a93fb2f1..0000000000
--- a/src/core/dbus-job.c
+++ /dev/null
@@ -1,193 +0,0 @@
-/***
- 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 "alloc-util.h"
-#include "dbus-job.h"
-#include "dbus.h"
-#include "job.h"
-#include "log.h"
-#include "selinux-access.h"
-#include "string-util.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_message *message, void *userdata, sd_bus_error *error) {
- Job *j = userdata;
- int r;
-
- 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_(sd_bus_message_unrefp) 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_(sd_bus_message_unrefp) 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 024d06719e..0000000000
--- a/src/core/dbus-job.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#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_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 fc50fafaad..0000000000
--- a/src/core/dbus-kill.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2012 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "bus-util.h"
-#include "dbus-kill.h"
-#include "kill.h"
-#include "signal-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 b9b18811e3..0000000000
--- a/src/core/dbus-kill.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#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 "kill.h"
-#include "unit.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 f939196397..0000000000
--- a/src/core/dbus-manager.c
+++ /dev/null
@@ -1,2137 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <sys/prctl.h>
-#include <unistd.h>
-
-#include "alloc-util.h"
-#include "architecture.h"
-#include "build.h"
-#include "bus-common-errors.h"
-#include "clock-util.h"
-#include "dbus-execute.h"
-#include "dbus-job.h"
-#include "dbus-manager.h"
-#include "dbus-unit.h"
-#include "dbus.h"
-#include "env-util.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "formats-util.h"
-#include "install.h"
-#include "log.h"
-#include "path-util.h"
-#include "selinux-access.h"
-#include "stat-util.h"
-#include "string-util.h"
-#include "strv.h"
-#include "syslog-util.h"
-#include "virt.h"
-#include "watchdog.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) {
-
- int v;
-
- assert(bus);
- assert(reply);
-
- v = detect_virtualization();
-
- /* Make sure to return the empty string when we detect no virtualization, as that is the API.
- *
- * https://github.com/systemd/systemd/issues/1423
- */
-
- return sd_bus_message_append(
- reply, "s",
- v == VIRTUALIZATION_NONE ? "" : virtualization_to_string(v));
-}
-
-static int property_get_architecture(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- assert(bus);
- assert(reply);
-
- return sd_bus_message_append(reply, "s", architecture_to_string(uname_architecture()));
-}
-
-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:cgroups-missing:local-hwclock:")] = "", *e = buf;
- Manager *m = userdata;
-
- assert(bus);
- assert(reply);
- assert(m);
-
- if (m->taint_usr)
- e = stpcpy(e, "split-usr:");
-
- 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;
-
- r = log_set_max_level_from_string(t);
- if (r == 0)
- log_info("Setting log level to %s.", t);
- return r;
-}
-
-static int property_get_n_names(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Manager *m = userdata;
-
- assert(bus);
- assert(reply);
- assert(m);
-
- return sd_bus_message_append(reply, "u", (uint32_t) hashmap_size(m->units));
-}
-
-static int property_get_n_failed_units(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Manager *m = userdata;
-
- assert(bus);
- assert(reply);
- assert(m);
-
- return sd_bus_message_append(reply, "u", (uint32_t) set_size(m->failed_units));
-}
-
-static int property_get_n_jobs(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- 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 property_get_timer_slack_nsec(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- assert(bus);
- assert(reply);
-
- return sd_bus_message_append(reply, "t", (uint64_t) prctl(PR_GET_TIMERSLACK));
-}
-
-static int method_get_unit(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(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_(sd_bus_creds_unrefp) 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_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_free_ char *path = NULL;
- Manager *m = userdata;
- pid_t pid;
- Unit *u;
- int r;
-
- 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_(sd_bus_creds_unrefp) 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_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_free_ char *path = NULL;
- Manager *m = userdata;
- const char *name;
- Unit *u;
- int r;
-
- 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_(sd_bus_creds_unrefp) 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_message *message, Manager *m, JobType job_type, bool reload_if_possible, sd_bus_error *error) {
- const char *name;
- Unit *u;
- int r;
-
- 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(message, u, job_type, reload_if_possible, error);
-}
-
-static int method_start_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_start_unit_generic(message, userdata, JOB_START, false, error);
-}
-
-static int method_stop_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_start_unit_generic(message, userdata, JOB_STOP, false, error);
-}
-
-static int method_reload_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_start_unit_generic(message, userdata, JOB_RELOAD, false, error);
-}
-
-static int method_restart_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_start_unit_generic(message, userdata, JOB_RESTART, false, error);
-}
-
-static int method_try_restart_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_start_unit_generic(message, userdata, JOB_TRY_RESTART, false, error);
-}
-
-static int method_reload_or_restart_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_start_unit_generic(message, userdata, JOB_RESTART, true, error);
-}
-
-static int method_reload_or_try_restart_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_start_unit_generic(message, userdata, JOB_TRY_RESTART, true, error);
-}
-
-static int method_start_unit_replace(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- const char *old_name;
- Unit *u;
- int r;
-
- 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(message, m, JOB_START, false, error);
-}
-
-static int method_kill_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- const char *name;
- Unit *u;
- int r;
-
- 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(message, u, error);
-}
-
-static int method_reset_failed_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- const char *name;
- Unit *u;
- int r;
-
- 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(message, u, error);
-}
-
-static int method_set_unit_properties(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- const char *name;
- Unit *u;
- int r;
-
- 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;
-
- r = bus_unit_check_load_state(u, error);
- if (r < 0)
- return r;
-
- return bus_unit_method_set_properties(message, u, error);
-}
-
-static int transient_unit_from_message(
- Manager *m,
- sd_bus_message *message,
- const char *name,
- Unit **unit,
- sd_bus_error *error) {
-
- UnitType t;
- Unit *u;
- int r;
-
- assert(m);
- assert(message);
- assert(name);
-
- t = unit_name_to_type(name);
- if (t < 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name or 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));
-
- r = manager_load_unit(m, name, NULL, error, &u);
- if (r < 0)
- return r;
-
- if (!unit_is_pristine(u))
- 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;
-
- /* Now load the missing bits of the unit we just created */
- manager_dispatch_load_queue(m);
-
- *unit = u;
-
- return 0;
-}
-
-static int transient_aux_units_from_message(
- Manager *m,
- sd_bus_message *message,
- sd_bus_error *error) {
-
- 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) {
- const char *name = NULL;
- Unit *u;
-
- 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)
- 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_message *message, void *userdata, sd_bus_error *error) {
- const char *name, *smode;
- Manager *m = userdata;
- JobMode mode;
- Unit *u;
- int r;
-
- 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;
-
- 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;
-
- /* Finally, start it */
- return bus_unit_queue_job(message, u, JOB_START, mode, false, error);
-}
-
-static int method_get_job(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(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_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- uint32_t id;
- Job *j;
- int r;
-
- 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(message, j, error);
-}
-
-static int method_clear_jobs(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- int r;
-
- 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_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- int r;
-
- 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_message *message, void *userdata, sd_bus_error *error, char **states) {
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- Manager *m = userdata;
- const char *k;
- Iterator i;
- Unit *u;
- int r;
-
- 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(NULL, reply, NULL);
-}
-
-static int method_list_units(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return list_units_filtered(message, userdata, error, NULL);
-}
-
-static int method_list_units_filtered(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(message, userdata, error, states);
-}
-
-static int method_list_jobs(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- Manager *m = userdata;
- Iterator i;
- Job *j;
- int r;
-
- 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(NULL, reply, NULL);
-}
-
-static int method_subscribe(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- int r;
-
- assert(message);
- assert(m);
-
- /* Anyone can call this method */
-
- r = mac_selinux_access_check(message, "status", error);
- if (r < 0)
- return r;
-
- if (sd_bus_message_get_bus(message) == 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(sd_bus_message_get_bus(message), &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_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- int r;
-
- assert(message);
- assert(m);
-
- /* Anyone can call this method */
-
- r = mac_selinux_access_check(message, "status", error);
- if (r < 0)
- return r;
-
- if (sd_bus_message_get_bus(message) == 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_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(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);
-
- r = fflush_and_check(f);
- if (r < 0)
- return r;
-
- return sd_bus_reply_method_return(message, "s", dump);
-}
-
-static int method_refuse_snapshot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Support for snapshots has been removed.");
-}
-
-static int method_reload(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- int r;
-
- 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->exit_code = MANAGER_RELOAD;
-
- return 1;
-}
-
-static int method_reexecute(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- int r;
-
- 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_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- int r;
-
- assert(message);
- assert(m);
-
- r = mac_selinux_access_check(message, "halt", error);
- if (r < 0)
- return r;
-
- /* Exit() (in contrast to SetExitCode()) is actually allowed even if
- * we are running on the host. It will fall back on reboot() in
- * systemd-shutdown if it cannot do the exit() because it isn't a
- * container. */
-
- m->exit_code = MANAGER_EXIT;
-
- return sd_bus_reply_method_return(message, NULL);
-}
-
-static int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- int r;
-
- assert(message);
- assert(m);
-
- r = mac_selinux_access_check(message, "reboot", error);
- if (r < 0)
- return r;
-
- if (m->running_as != MANAGER_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_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- int r;
-
- assert(message);
- assert(m);
-
- r = mac_selinux_access_check(message, "halt", error);
- if (r < 0)
- return r;
-
- if (m->running_as != MANAGER_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_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- int r;
-
- assert(message);
- assert(m);
-
- r = mac_selinux_access_check(message, "halt", error);
- if (r < 0)
- return r;
-
- if (m->running_as != MANAGER_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_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- int r;
-
- assert(message);
- assert(m);
-
- r = mac_selinux_access_check(message, "reboot", error);
- if (r < 0)
- return r;
-
- if (m->running_as != MANAGER_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_message *message, void *userdata, sd_bus_error *error) {
- char *ri = NULL, *rt = NULL;
- const char *root, *init;
- Manager *m = userdata;
- int r;
-
- assert(message);
- assert(m);
-
- r = mac_selinux_access_check(message, "reboot", error);
- if (r < 0)
- return r;
-
- if (m->running_as != MANAGER_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_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_strv_free_ char **plus = NULL;
- Manager *m = userdata;
- int r;
-
- 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_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_strv_free_ char **minus = NULL;
- Manager *m = userdata;
- int r;
-
- 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_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_strv_free_ char **minus = NULL, **plus = NULL;
- Manager *m = userdata;
- int r;
-
- 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_set_exit_code(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- uint8_t code;
- Manager *m = userdata;
- int r;
-
- assert(message);
- assert(m);
-
- r = mac_selinux_access_check(message, "exit", error);
- if (r < 0)
- return r;
-
- r = sd_bus_message_read_basic(message, 'y', &code);
- if (r < 0)
- return r;
-
- if (m->running_as == MANAGER_SYSTEM && detect_container() <= 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "ExitCode can only be set for user service managers or in containers.");
-
- m->return_value = code;
-
- return sd_bus_reply_method_return(message, NULL);
-}
-
-static int method_list_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- Manager *m = userdata;
- UnitFileList *item;
- Hashmap *h;
- Iterator i;
- int r;
-
- 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 == MANAGER_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(NULL, reply, NULL);
-
-fail:
- unit_file_list_free(h);
- return r;
-}
-
-static int method_get_unit_file_state(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- const char *name;
- UnitFileState state;
- UnitFileScope scope;
- int r;
-
- 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 == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
- r = unit_file_get_state(scope, NULL, name, &state);
- if (r < 0)
- return r;
-
- return sd_bus_reply_method_return(message, "s", unit_file_state_to_string(state));
-}
-
-static int method_get_default_target(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_free_ char *default_target = NULL;
- Manager *m = userdata;
- UnitFileScope scope;
- int r;
-
- 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 == MANAGER_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_(sd_bus_message_unrefp) 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_message *message,
- int carries_install_info,
- UnitFileChange *changes,
- unsigned n_changes) {
-
- _cleanup_(sd_bus_message_unrefp) 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;
-
- unit_file_changes_free(changes, n_changes);
- return sd_bus_send(NULL, reply, NULL);
-
-fail:
- unit_file_changes_free(changes, n_changes);
- return r;
-}
-
-static int method_enable_unit_files_generic(
- 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(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 = 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 == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
- r = call(scope, runtime, NULL, l, force, &changes, &n_changes);
- if (r == -ESHUTDOWN)
- return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked");
- if (r < 0)
- return r;
-
- return reply_unit_file_changes_and_free(m, message, carries_install_info ? r : -1, changes, n_changes);
-}
-
-static int method_enable_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_enable_unit_files_generic(message, userdata, "enable", unit_file_enable, true, error);
-}
-
-static int method_reenable_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_enable_unit_files_generic(message, userdata, "enable", unit_file_reenable, true, error);
-}
-
-static int method_link_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_enable_unit_files_generic(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_message *message, void *userdata, sd_bus_error *error) {
- return method_enable_unit_files_generic(message, userdata, "enable", unit_file_preset_without_mode, true, error);
-}
-
-static int method_mask_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_enable_unit_files_generic(message, userdata, "disable", unit_file_mask, false, error);
-}
-
-static int method_preset_unit_files_with_mode(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(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 = 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 == MANAGER_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, message, r, changes, n_changes);
-}
-
-static int method_disable_unit_files_generic(
- 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(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;
-
- scope = m->running_as == MANAGER_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, message, -1, changes, n_changes);
-}
-
-static int method_disable_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_disable_unit_files_generic(message, userdata, "disable", unit_file_disable, error);
-}
-
-static int method_unmask_unit_files(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return method_disable_unit_files_generic(message, userdata, "enable", unit_file_unmask, error);
-}
-
-static int method_set_default_target(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(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 == MANAGER_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, message, -1, changes, n_changes);
-}
-
-static int method_preset_all_unit_files(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(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 == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
- r = unit_file_preset_all(scope, runtime, NULL, mm, force, &changes, &n_changes);
- if (r < 0) {
- unit_file_changes_free(changes, n_changes);
- return r;
- }
-
- return reply_unit_file_changes_and_free(m, message, -1, changes, n_changes);
-}
-
-static int method_add_dependency_unit_files(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(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;
-
- scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
-
- r = unit_file_add_dependency(scope, runtime, NULL, l, target, dep, force, &changes, &n_changes);
- if (r == -ESHUTDOWN)
- return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked");
- if (r < 0)
- return r;
-
- return reply_unit_file_changes_and_free(m, 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_PROPERTY("ExitCode", "y", bus_property_get_unsigned, offsetof(Manager, return_value), 0),
- SD_BUS_PROPERTY("DefaultTimerAccuracyUSec", "t", bus_property_get_usec, offsetof(Manager, default_timer_accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultTimeoutStartUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultTimeoutStopUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultRestartUSec", "t", bus_property_get_usec, offsetof(Manager, default_restart_usec), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultStartLimitInterval", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultStartLimitBurst", "u", bus_property_get_unsigned, offsetof(Manager, default_start_limit_burst), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultCPUAccounting", "b", bus_property_get_bool, offsetof(Manager, default_cpu_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultBlockIOAccounting", "b", bus_property_get_bool, offsetof(Manager, default_blockio_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultMemoryAccounting", "b", bus_property_get_bool, offsetof(Manager, default_memory_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultTasksAccounting", "b", bus_property_get_bool, offsetof(Manager, default_tasks_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitCPU", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitCPUSoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitFSIZE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitFSIZESoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitDATA", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitDATASoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitSTACK", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitSTACKSoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitCORE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitCORESoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitRSS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitRSSSoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitNOFILE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitNOFILESoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitAS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitASSoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitNPROC", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitNPROCSoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitMEMLOCK", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitMEMLOCKSoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitLOCKS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitLOCKSSoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitSIGPENDING", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitSIGPENDINGSoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitMSGQUEUE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitMSGQUEUESoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitNICE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitNICESoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitRTPRIO", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitRTPRIOSoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitRTTIME", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultLimitRTTIMESoft", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("DefaultTasksMax", "t", NULL, offsetof(Manager, default_tasks_max), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST),
-
- 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_refuse_snapshot, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("RemoveSnapshot", "s", NULL, method_refuse_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_METHOD("SetExitCode", "y", NULL, method_set_exit_code, 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_(sd_bus_message_unrefp) 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_(sd_bus_message_unrefp) 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 36a2e9481b..0000000000
--- a/src/core/dbus-manager.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#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 935db7c48b..0000000000
--- a/src/core/dbus-mount.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "bus-util.h"
-#include "dbus-cgroup.h"
-#include "dbus-execute.h"
-#include "dbus-kill.h"
-#include "dbus-mount.h"
-#include "mount.h"
-#include "string-util.h"
-#include "unit.h"
-
-static int property_get_what(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Mount *m = userdata;
- const char *d;
-
- 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 ec16166d36..0000000000
--- a/src/core/dbus-mount.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#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 1e153e503f..0000000000
--- a/src/core/dbus-path.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "bus-util.h"
-#include "dbus-path.h"
-#include "path.h"
-#include "string-util.h"
-#include "unit.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 d3c19e0c2b..0000000000
--- a/src/core/dbus-path.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#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 34ee9a8fa9..0000000000
--- a/src/core/dbus-scope.c
+++ /dev/null
@@ -1,229 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "alloc-util.h"
-#include "bus-common-errors.h"
-#include "bus-internal.h"
-#include "bus-util.h"
-#include "dbus-cgroup.h"
-#include "dbus-kill.h"
-#include "dbus-scope.h"
-#include "dbus-unit.h"
-#include "dbus.h"
-#include "scope.h"
-#include "selinux-access.h"
-#include "unit.h"
-
-static int bus_scope_abandon(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Scope *s = userdata;
- int r;
-
- 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_(sd_bus_message_unrefp) 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 270306f508..0000000000
--- a/src/core/dbus-scope.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#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 03eecca911..0000000000
--- a/src/core/dbus-service.c
+++ /dev/null
@@ -1,322 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "alloc-util.h"
-#include "async.h"
-#include "bus-util.h"
-#include "dbus-cgroup.h"
-#include "dbus-execute.h"
-#include "dbus-kill.h"
-#include "dbus-service.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "path-util.h"
-#include "service.h"
-#include "string-util.h"
-#include "strv.h"
-#include "unit.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("RuntimeMaxUSec", "t", bus_property_get_usec, offsetof(Service, runtime_max_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),
- /* The following four are obsolete, and thus marked hidden here. They moved into the Unit interface */
- SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
- SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
- SD_BUS_PROPERTY("StartLimitAction", "s", property_get_failure_action, offsetof(Unit, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
- SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Unit, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
- 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", bus_property_get_unsigned, offsetof(Service, n_fd_store_max), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("NFileDescriptorStore", "u", bus_property_get_unsigned, offsetof(Service, n_fd_store), 0),
- SD_BUS_PROPERTY("StatusText", "s", NULL, offsetof(Service, status_text), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("StatusErrno", "i", NULL, offsetof(Service, status_errno), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Service, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("USBFunctionDescriptors", "s", NULL, offsetof(Service, usb_function_descriptors), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- SD_BUS_PROPERTY("USBFunctionStrings", "s", NULL, offsetof(Service, usb_function_strings), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- 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, "RuntimeMaxUSec")) {
- usec_t u;
-
- r = sd_bus_message_read(message, "t", &u);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- s->runtime_max_usec = u;
- unit_write_drop_in_private_format(UNIT(s), mode, name, "RuntimeMaxSec=" USEC_FMT "us\n", u);
- }
-
- return 1;
-
- } else if (STR_IN_SET(name,
- "StandardInputFileDescriptor",
- "StandardOutputFileDescriptor",
- "StandardErrorFileDescriptor")) {
- int fd;
-
- r = sd_bus_message_read(message, "h", &fd);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- int copy;
-
- copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
- if (copy < 0)
- return -errno;
-
- if (streq(name, "StandardInputFileDescriptor")) {
- asynchronous_close(s->stdin_fd);
- s->stdin_fd = copy;
- } else if (streq(name, "StandardOutputFileDescriptor")) {
- asynchronous_close(s->stdout_fd);
- s->stdout_fd = copy;
- } else {
- asynchronous_close(s->stderr_fd);
- s->stderr_fd = copy;
- }
-
- s->exec_context.stdio_as_fds = true;
- }
-
- 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);
- }
-
- r = fflush_and_check(f);
- if (r < 0)
- return r;
- 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 769a53769e..0000000000
--- a/src/core/dbus-service.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#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 e37f50b283..0000000000
--- a/src/core/dbus-slice.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2013 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "dbus-cgroup.h"
-#include "dbus-slice.h"
-#include "slice.h"
-#include "unit.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 52ceebb135..0000000000
--- a/src/core/dbus-slice.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#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-socket.c b/src/core/dbus-socket.c
deleted file mode 100644
index d33e494f6b..0000000000
--- a/src/core/dbus-socket.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "alloc-util.h"
-#include "bus-util.h"
-#include "dbus-cgroup.h"
-#include "dbus-execute.h"
-#include "dbus-socket.h"
-#include "socket.h"
-#include "string-util.h"
-#include "unit.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:
- case SOCKET_USB_FUNCTION:
- 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);
-}
-
-
-static int property_get_fdname(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Socket *s = SOCKET(userdata);
-
- assert(bus);
- assert(reply);
- assert(s);
-
- return sd_bus_message_append(reply, "s", socket_fdname(s));
-}
-
-const sd_bus_vtable bus_socket_vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_PROPERTY("BindIPv6Only", "s", property_get_bind_ipv6_only, offsetof(Socket, bind_ipv6_only), SD_BUS_VTABLE_PROPERTY_CONST),
- 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("Writable", "b", bus_property_get_bool, offsetof(Socket, writable), 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),
- SD_BUS_PROPERTY("FileDescriptorName", "s", property_get_fdname, 0, 0),
- SD_BUS_PROPERTY("SocketProtocol", "i", bus_property_get_int, offsetof(Socket, socket_protocol), SD_BUS_VTABLE_PROPERTY_CONST),
- 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 7a792c7a89..0000000000
--- a/src/core/dbus-socket.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#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 292f8738c6..0000000000
--- a/src/core/dbus-swap.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/***
- 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 "bus-util.h"
-#include "dbus-cgroup.h"
-#include "dbus-execute.h"
-#include "dbus-swap.h"
-#include "string-util.h"
-#include "swap.h"
-#include "unit.h"
-
-static int property_get_priority(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- Swap *s = SWAP(userdata);
- int p;
-
- assert(bus);
- assert(reply);
- assert(s);
-
- 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 5238471f98..0000000000
--- a/src/core/dbus-swap.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#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 6858b1ce72..0000000000
--- a/src/core/dbus-target.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "dbus-target.h"
-#include "unit.h"
-
-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 9be5ce06b7..0000000000
--- a/src/core/dbus-target.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#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_target_vtable[];
diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c
deleted file mode 100644
index bc121b83a2..0000000000
--- a/src/core/dbus-timer.c
+++ /dev/null
@@ -1,352 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "alloc-util.h"
-#include "bus-util.h"
-#include "dbus-timer.h"
-#include "strv.h"
-#include "timer.h"
-#include "unit.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("RandomizedDelayUSec", "t", bus_property_get_usec, offsetof(Timer, random_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_PROPERTY("RemainAfterElapse", "b", bus_property_get_bool, offsetof(Timer, remain_after_elapse), 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) {
- calendar_spec_free(c);
- return -ENOMEM;
- }
-
- v->base = TIMER_CALENDAR;
- v->calendar_spec = c;
-
- LIST_PREPEND(value, t->values, v);
- }
-
- return 1;
-
- } else if (STR_IN_SET(name, "AccuracyUSec", "AccuracySec")) {
- usec_t u = 0;
-
- if (streq(name, "AccuracySec"))
- log_notice("Client is using obsolete AccuracySec= transient property, please use AccuracyUSec= instead.");
-
- r = sd_bus_message_read(message, "t", &u);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- t->accuracy_usec = u;
- unit_write_drop_in_private_format(UNIT(t), mode, name, "AccuracySec=" USEC_FMT "us\n", u);
- }
-
- return 1;
-
- } else if (streq(name, "RandomizedDelayUSec")) {
- usec_t u = 0;
-
- r = sd_bus_message_read(message, "t", &u);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- t->random_usec = u;
- unit_write_drop_in_private_format(UNIT(t), mode, name, "RandomizedDelaySec=" USEC_FMT "us\n", u);
- }
-
- 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(b));
- }
-
- return 1;
-
- } else if (streq(name, "RemainAfterElapse")) {
- int b;
-
- r = sd_bus_message_read(message, "b", &b);
- if (r < 0)
- return r;
-
- if (mode != UNIT_CHECK) {
- t->remain_after_elapse = b;
- unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, yes_no(b));
- }
-
- 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 39053dc4a2..0000000000
--- a/src/core/dbus-timer.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#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 b351f6a2c2..0000000000
--- a/src/core/dbus-unit.c
+++ /dev/null
@@ -1,1276 +0,0 @@
-/***
- 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 "alloc-util.h"
-#include "bus-common-errors.h"
-#include "cgroup-util.h"
-#include "dbus-unit.h"
-#include "dbus.h"
-#include "locale-util.h"
-#include "log.h"
-#include "selinux-access.h"
-#include "special.h"
-#include "string-util.h"
-#include "strv.h"
-#include "user-util.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_obsolete_dependencies(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- assert(bus);
- assert(reply);
-
- /* For dependency types we don't support anymore always return an empty array */
- return sd_bus_message_append(reply, "as", 0);
-}
-
-static int property_get_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_(sd_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);
-}
-
-static int bus_verify_manage_units_async_full(
- Unit *u,
- const char *verb,
- int capability,
- const char *polkit_message,
- sd_bus_message *call,
- sd_bus_error *error) {
-
- const char *details[9] = {
- "unit", u->id,
- "verb", verb,
- };
-
- if (polkit_message) {
- details[4] = "polkit.message";
- details[5] = polkit_message;
- details[6] = "polkit.gettext_domain";
- details[7] = GETTEXT_PACKAGE;
- }
-
- return bus_verify_polkit_async(call, capability, "org.freedesktop.systemd1.manage-units", details, false, UID_INVALID, &u->manager->polkit_registry, error);
-}
-
-int bus_unit_method_start_generic(
- sd_bus_message *message,
- Unit *u,
- JobType job_type,
- bool reload_if_possible,
- sd_bus_error *error) {
-
- const char *smode;
- JobMode mode;
- _cleanup_free_ char *verb = NULL;
- static const char *const polkit_message_for_job[_JOB_TYPE_MAX] = {
- [JOB_START] = N_("Authentication is required to start '$(unit)'."),
- [JOB_STOP] = N_("Authentication is required to stop '$(unit)'."),
- [JOB_RELOAD] = N_("Authentication is required to reload '$(unit)'."),
- [JOB_RESTART] = N_("Authentication is required to restart '$(unit)'."),
- [JOB_TRY_RESTART] = N_("Authentication is required to restart '$(unit)'."),
- };
- int r;
-
- assert(message);
- assert(u);
- assert(job_type >= 0 && job_type < _JOB_TYPE_MAX);
-
- r = mac_selinux_unit_access_check(
- u, message,
- job_type_to_access_method(job_type),
- 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);
-
- if (reload_if_possible)
- verb = strjoin("reload-or-", job_type_to_string(job_type), NULL);
- else
- verb = strdup(job_type_to_string(job_type));
- if (!verb)
- return -ENOMEM;
-
- r = bus_verify_manage_units_async_full(
- u,
- verb,
- CAP_SYS_ADMIN,
- job_type < _JOB_TYPE_MAX ? polkit_message_for_job[job_type] : NULL,
- 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(message, u, job_type, mode, reload_if_possible, error);
-}
-
-static int method_start(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return bus_unit_method_start_generic(message, userdata, JOB_START, false, error);
-}
-
-static int method_stop(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return bus_unit_method_start_generic(message, userdata, JOB_STOP, false, error);
-}
-
-static int method_reload(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return bus_unit_method_start_generic(message, userdata, JOB_RELOAD, false, error);
-}
-
-static int method_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return bus_unit_method_start_generic(message, userdata, JOB_RESTART, false, error);
-}
-
-static int method_try_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return bus_unit_method_start_generic(message, userdata, JOB_TRY_RESTART, false, error);
-}
-
-static int method_reload_or_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return bus_unit_method_start_generic(message, userdata, JOB_RESTART, true, error);
-}
-
-static int method_reload_or_try_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- return bus_unit_method_start_generic(message, userdata, JOB_TRY_RESTART, true, error);
-}
-
-int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Unit *u = userdata;
- const char *swho;
- int32_t signo;
- KillWho who;
- int r;
-
- 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_full(
- u,
- "kill",
- CAP_KILL,
- N_("Authentication is required to kill '$(unit)'."),
- 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_message *message, void *userdata, sd_bus_error *error) {
- Unit *u = userdata;
- int r;
-
- 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_full(
- u,
- "reset-failed",
- CAP_SYS_ADMIN,
- N_("Authentication is required to reset the \"failed\" state of '$(unit)'."),
- 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_message *message, void *userdata, sd_bus_error *error) {
- Unit *u = userdata;
- int runtime, r;
-
- 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_full(
- u,
- "set-property",
- CAP_SYS_ADMIN,
- N_("Authentication is required to set properties on '$(unit)'."),
- 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("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), 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("RequisiteOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OF]), 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("RequiresOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
- SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
- SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
- SD_BUS_PROPERTY("RequisiteOfOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
- 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("StateChangeTimestamp", offsetof(Unit, state_change_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
- 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("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_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("StartLimitAction", "s", property_get_failure_action, offsetof(Unit, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Unit, reboot_arg), 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, r, "Failed to get memory.usage_in_bytes attribute: %m");
-
- return sd_bus_message_append(reply, "t", sz);
-}
-
-static int property_get_current_tasks(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- uint64_t cn = (uint64_t) -1;
- Unit *u = userdata;
- int r;
-
- assert(bus);
- assert(reply);
- assert(u);
-
- r = unit_get_tasks_current(u, &cn);
- if (r < 0 && r != -ENODATA)
- log_unit_warning_errno(u, r, "Failed to get pids.current attribute: %m");
-
- return sd_bus_message_append(reply, "t", cn);
-}
-
-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, r, "Failed to get cpuacct.usage attribute: %m");
-
- return sd_bus_message_append(reply, "t", ns);
-}
-
-static int property_get_cgroup(
- 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;
- const char *t;
-
- assert(bus);
- assert(reply);
- assert(u);
-
- /* Three cases: a) u->cgroup_path is NULL, in which case the
- * unit has no control group, which we report as the empty
- * string. b) u->cgroup_path is the empty string, which
- * indicates the root cgroup, which we report as "/". c) all
- * other cases we report as-is. */
-
- if (u->cgroup_path)
- t = isempty(u->cgroup_path) ? "/" : u->cgroup_path;
- else
- t = "";
-
- return sd_bus_message_append(reply, "s", t);
-}
-
-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", property_get_cgroup, 0, 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_PROPERTY("TasksCurrent", "t", property_get_current_tasks, 0, 0),
- SD_BUS_VTABLE_END
-};
-
-static int send_new_signal(sd_bus *bus, void *userdata) {
- _cleanup_(sd_bus_message_unrefp) 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 (!p)
- 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_dbus_interface_from_type(u->type),
- 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_unit_debug_errno(u, 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_(sd_bus_message_unrefp) 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 (!p)
- 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_unit_debug_errno(u, r, "Failed to send unit remove signal for %s: %m", u->id);
-}
-
-int bus_unit_queue_job(
- 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(message);
- assert(u);
- assert(type >= 0 && type < _JOB_TYPE_MAX);
- assert(mode >= 0 && mode < _JOB_MODE_MAX);
-
- r = mac_selinux_unit_access_check(
- u, message,
- job_type_to_access_method(type),
- error);
- if (r < 0)
- return r;
-
- 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_TRY_RELOAD;
- }
-
-
- 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)) ||
- (type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start))
- 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, error, &j);
- if (r < 0)
- return r;
-
- if (sd_bus_message_get_bus(message) == u->manager->api_bus) {
- if (!j->clients) {
- r = sd_bus_track_new(sd_bus_message_get_bus(message), &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 *slice;
- const char *s;
-
- if (!UNIT_HAS_CGROUP_CONTEXT(u))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "The slice property is only available for units with control groups.");
- if (u->type == UNIT_SLICE)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Slice may not be set for slice units.");
- if (unit_has_name(u, SPECIAL_INIT_SCOPE))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot set slice for init.scope");
-
- r = sd_bus_message_read(message, "s", &s);
- if (r < 0)
- return r;
-
- if (!unit_name_is_valid(s, UNIT_NAME_PLAIN))
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name '%s'", s);
-
- r = manager_load_unit(u->manager, s, NULL, error, &slice);
- if (r < 0)
- return r;
-
- if (slice->type != UNIT_SLICE)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit name '%s' is not a slice", s);
-
- if (mode != UNIT_CHECK) {
- r = unit_set_slice(u, slice);
- if (r < 0)
- return r;
-
- 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;
-
- if (streq(name, "RequiresOverridable"))
- d = UNIT_REQUIRES; /* redirect for obsolete unit dependency type */
- else if (streq(name, "RequisiteOverridable"))
- d = UNIT_REQUISITE; /* same here */
- else {
- d = unit_dependency_from_string(name);
- if (d < 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit dependency: %s", name);
- }
-
- 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, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
- 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;
-}
-
-int bus_unit_check_load_state(Unit *u, sd_bus_error *error) {
-
- if (u->load_state == UNIT_LOADED)
- return 0;
-
- /* Give a better description of the unit error when
- * possible. Note that in the case of UNIT_MASKED, load_error
- * is not set. */
- if (u->load_state == UNIT_MASKED)
- return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit %s is masked.", u->id);
-
- if (u->load_state == UNIT_NOT_FOUND)
- return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not found.", u->id);
-
- return sd_bus_error_set_errnof(error, u->load_error, "Unit %s is not loaded properly: %m.", u->id);
-}
diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h
deleted file mode 100644
index 07948b9cd0..0000000000
--- a/src/core/dbus-unit.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#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_message *message, Unit *u, JobType job_type, bool reload_if_possible, sd_bus_error *error);
-int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error);
-int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_error *error);
-
-int bus_unit_queue_job(sd_bus_message *message, Unit *u, JobType type, JobMode mode, bool reload_if_possible, sd_bus_error *error);
-int bus_unit_set_properties(Unit *u, sd_bus_message *message, UnitSetPropertiesMode mode, bool commit, sd_bus_error *error);
-int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_bus_error *error);
-
-int bus_unit_check_load_state(Unit *u, sd_bus_error *error);
diff --git a/src/core/dbus.c b/src/core/dbus.c
deleted file mode 100644
index 413489373f..0000000000
--- a/src/core/dbus.c
+++ /dev/null
@@ -1,1258 +0,0 @@
-/***
- 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 <unistd.h>
-
-#include "sd-bus.h"
-
-#include "alloc-util.h"
-#include "bus-common-errors.h"
-#include "bus-error.h"
-#include "bus-internal.h"
-#include "bus-util.h"
-#include "dbus-cgroup.h"
-#include "dbus-execute.h"
-#include "dbus-job.h"
-#include "dbus-kill.h"
-#include "dbus-manager.h"
-#include "dbus-unit.h"
-#include "dbus.h"
-#include "fd-util.h"
-#include "log.h"
-#include "missing.h"
-#include "mkdir.h"
-#include "selinux-access.h"
-#include "special.h"
-#include "string-util.h"
-#include "strv.h"
-#include "strxcpyx.h"
-#include "user-util.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;
-
- /* 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(NULL, 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);
-
- return 0;
-}
-
-static int signal_agent_released(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
- const char *cgroup, *me;
- Manager *m = userdata;
- uid_t sender_uid;
- sd_bus *bus;
- int r;
-
- assert(message);
- assert(m);
-
- /* ignore recursive events sent by us on the system/user bus */
- bus = sd_bus_message_get_bus(message);
- if (!sd_bus_is_server(bus)) {
- r = sd_bus_get_unique_name(bus, &me);
- if (r < 0)
- return r;
-
- if (streq_ptr(sd_bus_message_get_sender(message), me))
- return 0;
- }
-
- /* only accept org.freedesktop.systemd1.Agent from UID=0 */
- r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds);
- if (r < 0)
- return r;
-
- r = sd_bus_creds_get_euid(creds, &sender_uid);
- if (r < 0 || sender_uid != 0)
- return 0;
-
- /* parse 'cgroup-empty' notification */
- r = sd_bus_message_read(message, "s", &cgroup);
- if (r < 0) {
- bus_log_parse_error(r);
- return 0;
- }
-
- manager_notify_cgroup_empty(m, cgroup);
-
- /* if running as system-instance, forward under our name */
- if (m->running_as == MANAGER_SYSTEM && m->system_bus) {
- r = sd_bus_message_rewind(message, 1);
- if (r >= 0)
- r = sd_bus_send(m->system_bus, message, NULL);
- if (r < 0)
- log_warning_errno(r, "Failed to forward Released message: %m");
- }
-
- return 0;
-}
-
-static int signal_disconnected(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- sd_bus *bus;
-
- assert(message);
- assert(m);
- assert_se(bus = sd_bus_message_get_bus(message));
-
- 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_activation_request(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- Manager *m = userdata;
- const char *name;
- Unit *u;
- int r;
-
- 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, &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(sd_bus_message_get_bus(message), &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(NULL, 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_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- const char *verb, *path;
- Unit *u = NULL;
- Job *j;
- int r;
-
- 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_(sd_bus_creds_unrefp) 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_(sd_bus_creds_unrefp) 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_dbus_interface_from_type(u->type)))
- 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_dbus_interface_from_type(u->type)))
- return 0;
-
- if (!UNIT_HAS_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_dbus_interface_from_type(u->type)))
- 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_dbus_interface_from_type(u->type)))
- 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_dbus_interface_from_type(u->type)))
- 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++) {
- const char *interface;
-
- assert_se(interface = unit_dbus_interface_from_type(t));
-
- r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", 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", interface);
-
- if (unit_vtable[t]->cgroup_context_offset > 0) {
- r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", 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", interface);
-
- r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", 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", interface);
- }
-
- if (unit_vtable[t]->exec_context_offset > 0) {
- r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", 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", interface);
- }
-
- if (unit_vtable[t]->kill_context_offset > 0) {
- r = sd_bus_add_fallback_vtable(bus, NULL, "/org/freedesktop/systemd1/unit", 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", 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_(sd_bus_unrefp) 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_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 credentials for new connection: %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 == MANAGER_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 connection bus to set: %m");
- return 0;
- }
-
- bus = NULL;
-
- log_debug("Accepted new private connection.");
-
- return 0;
-}
-
-int manager_sync_bus_names(Manager *m, sd_bus *bus) {
- _cleanup_strv_free_ char **names = NULL;
- const char *name;
- Iterator i;
- Unit *u;
- 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");
-
- /* We have to synchronize the current bus names with the
- * list of active services. To do this, walk the list of
- * all units with bus names. */
- HASHMAP_FOREACH_KEY(u, name, m->watch_bus, i) {
- Service *s = SERVICE(u);
-
- assert(s);
-
- if (!streq_ptr(s->bus_name, name)) {
- log_unit_warning(u, "Bus name has changed from %s → %s, ignoring.", s->bus_name, name);
- continue;
- }
-
- /* Check if a service's bus name is in the list of currently
- * active names */
- if (strv_contains(names, name)) {
- _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
- const char *unique;
-
- /* If it is, determine its current owner */
- r = sd_bus_get_name_creds(bus, name, SD_BUS_CREDS_UNIQUE_NAME, &creds);
- if (r < 0) {
- log_error_errno(r, "Failed to get bus name owner %s: %m", name);
- continue;
- }
-
- r = sd_bus_creds_get_unique_name(creds, &unique);
- if (r < 0) {
- log_error_errno(r, "Failed to get unique name for %s: %m", name);
- continue;
- }
-
- /* Now, let's compare that to the previous bus owner, and
- * if it's still the same, all is fine, so just don't
- * bother the service. Otherwise, the name has apparently
- * changed, so synthesize a name owner changed signal. */
-
- if (!streq_ptr(unique, s->bus_name_owner))
- UNIT_VTABLE(u)->bus_name_owner_change(u, name, s->bus_name_owner, unique);
- } else {
- /* So, the name we're watching is not on the bus.
- * This either means it simply hasn't appeared yet,
- * or it was lost during the daemon reload.
- * Check if the service has a stored name owner,
- * and synthesize a name loss signal in this case. */
-
- if (s->bus_name_owner)
- UNIT_VTABLE(u)->bus_name_owner_change(u, name, s->bus_name_owner, NULL);
- }
- }
-
- return 0;
-}
-
-static int bus_setup_api(Manager *m, sd_bus *bus) {
- Iterator i;
- char *name;
- Unit *u;
- 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;
-
- HASHMAP_FOREACH_KEY(u, name, m->watch_bus, i) {
- r = unit_install_bus_match(u, bus, name);
- if (r < 0)
- log_error_errno(r, "Failed to subscribe to NameOwnerChanged signal for '%s': %m", name);
- }
-
- 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");
-
- r = manager_sync_bus_names(m, bus);
- if (r < 0)
- return r;
-
- log_debug("Successfully connected to API bus.");
- return 0;
-}
-
-static int bus_init_api(Manager *m) {
- _cleanup_(sd_bus_unrefp) 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 == MANAGER_SYSTEM && m->system_bus)
- bus = sd_bus_ref(m->system_bus);
- else {
- if (m->running_as == MANAGER_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 == MANAGER_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_(sd_bus_unrefp) 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 == MANAGER_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 == MANAGER_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");
-
- (void) sd_event_source_set_description(s, "bus-connection");
-
- 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 && sd_bus_message_get_bus(m->queued_message) == *bus)
- 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 != MANAGER_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);
-
- m->private_buses = set_free(m->private_buses);
-
- m->subscribed = sd_bus_track_unref(m->subscribed);
- m->deserialized_subscribed = strv_free(m->deserialized_subscribed);
-
- 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 buses, 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;
- }
- }
-
- *l = strv_free(*l);
-
- 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", NULL, 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", NULL, 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", NULL, 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", NULL, false, UID_INVALID, &m->polkit_registry, error);
-}
diff --git a/src/core/dbus.h b/src/core/dbus.h
deleted file mode 100644
index e16a84fbb8..0000000000
--- a/src/core/dbus.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#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 manager_sync_bus_names(Manager *m, sd_bus *bus);
-
-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_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 d201dc5e4b..0000000000
--- a/src/core/device.c
+++ /dev/null
@@ -1,878 +0,0 @@
-/***
- 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 "alloc-util.h"
-#include "dbus-device.h"
-#include "device.h"
-#include "log.h"
-#include "parse-util.h"
-#include "path-util.h"
-#include "stat-util.h"
-#include "string-util.h"
-#include "swap.h"
-#include "udev-util.h"
-#include "unit-name.h"
-#include "unit.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);
-
- d->sysfs = mfree(d->sysfs);
-}
-
-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;
-}
-
-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), "Changed %s -> %s", device_state_to_string(old_state), device_state_to_string(state));
-
- unit_notify(UNIT(d), state_translation_table[old_state], state_translation_table[state], true);
-}
-
-static int device_coldplug(Unit *u) {
- 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 && d->deserialized_state != DEVICE_PLUGGED)
- /* If a device is found in /proc/self/mountinfo or
- * /proc/swaps, and was not yet announced via udev,
- * it's "tentatively" around. */
- device_set_state(d, DEVICE_TENTATIVE);
-
- return 0;
-}
-
-static int device_serialize(Unit *u, FILE *f, FDSet *fds) {
- Device *d = DEVICE(u);
-
- assert(u);
- assert(f);
- assert(fds);
-
- unit_serialize_item(u, f, "state", device_state_to_string(d->state));
-
- return 0;
-}
-
-static int device_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Device *d = DEVICE(u);
-
- assert(u);
- assert(key);
- assert(value);
- assert(fds);
-
- if (streq(key, "state")) {
- DeviceState state;
-
- state = device_state_from_string(value);
- if (state < 0)
- log_unit_debug(u, "Failed to parse state value: %s", value);
- else
- d->deserialized_state = state;
- } else
- log_unit_debug(u, "Unknown serialization key: %s", key);
-
- 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, 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 == MANAGER_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;
-
- r = unit_name_mangle(e, UNIT_NAME_NOGLOB, &n);
- if (r < 0)
- return log_unit_error_errno(u, r, "Failed to mangle unit name: %m");
-
- r = unit_add_dependency_by_name(u, UNIT_WANTS, n, NULL, true);
- if (r < 0)
- return log_unit_error_errno(u, r, "Failed to add wants dependency: %m");
- }
- if (!isempty(state))
- log_unit_warning(u, "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 = NULL;
- Unit *u = NULL;
- bool delete;
- int r;
-
- assert(m);
- assert(path);
-
- if (dev) {
- sysfs = udev_device_get_syspath(dev);
- if (!sysfs)
- return 0;
- }
-
- r = unit_name_from_path(path, ".device", &e);
- if (r < 0)
- return log_error_errno(r, "Failed to generate unit name from device path: %m");
-
- u = manager_get_unit(m, e);
-
- /* The device unit can still be present even if the device was
- * unplugged: a mount unit can reference it hence preventing
- * the GC to have garbaged it. That's desired since the device
- * unit may have a dependency on the mount unit which was
- * added during the loading of the later. */
- if (u && DEVICE(u)->state == DEVICE_PLUGGED) {
- /* This unit is in plugged state: we're sure it's
- * attached to a device. */
- if (!path_equal(DEVICE(u)->sysfs, sysfs)) {
- log_unit_error(u, "Dev %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. */
- if (sysfs) {
- 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, r, "Failed to set up device unit: %m");
-
- if (delete)
- 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, previous;
-
- assert(d);
-
- n = add ? (d->found | found) : (d->found & ~found);
- if (n == d->found)
- return;
-
- previous = d->found;
- d->found = n;
-
- if (!now)
- return;
-
- if (d->found & DEVICE_FOUND_UDEV)
- /* When the device is known to udev we consider it
- * plugged. */
- device_set_state(d, DEVICE_PLUGGED);
- else if (d->found != DEVICE_NOT_FOUND && (previous & DEVICE_FOUND_UDEV) == 0)
- /* If the device has not been seen by udev yet, but is
- * now referenced by the kernel, then we assume the
- * kernel knows it now, and udev might soon too. */
- device_set_state(d, DEVICE_TENTATIVE);
- else
- /* If nobody sees the device, or if the device was
- * previously seen by udev and now is only referenced
- * from the kernel, then we consider the device is
- * gone, the kernel just hasn't noticed it yet. */
- 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;
- int r;
-
- assert(m);
- assert(path);
-
- if (found == DEVICE_NOT_FOUND)
- return 0;
-
- r = unit_name_from_path(path, ".device", &e);
- if (r < 0)
- return log_error_errno(r, "Failed to generate unit name from device path: %m");
-
- 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;
- }
-
- m->devices_by_sysfs = hashmap_free(m->devices_by_sysfs);
-}
-
-static void device_enumerate(Manager *m) {
- _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
- 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) {
- log_oom();
- 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) {
- log_error_errno(r, "Failed to add udev tag match: %m");
- goto fail;
- }
-
- r = udev_monitor_enable_receiving(m->udev_monitor);
- if (r < 0) {
- log_error_errno(r, "Failed to enable udev event reception: %m");
- 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) {
- log_error_errno(r, "Failed to watch udev file descriptor: %m");
- goto fail;
- }
-
- (void) sd_event_source_set_description(m->udev_event_source, "device");
- }
-
- e = udev_enumerate_new(m->udev);
- if (!e) {
- log_oom();
- goto fail;
- }
-
- r = udev_enumerate_add_match_tag(e, "systemd");
- if (r < 0) {
- log_error_errno(r, "Failed to create udev tag enumeration: %m");
- goto fail;
- }
-
- r = udev_enumerate_add_match_is_initialized(e);
- if (r < 0) {
- log_error_errno(r, "Failed to install initialization match into enumeration: %m");
- goto fail;
- }
-
- r = udev_enumerate_scan_devices(e);
- if (r < 0) {
- log_error_errno(r, "Failed to enumerate devices: %m");
- 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;
-
-fail:
- device_shutdown(m);
-}
-
-static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
- _cleanup_udev_device_unref_ struct udev_device *dev = NULL;
- 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(void) {
- static int read_only = -1;
-
- /* 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);
-
- if (!device_supported())
- return 0;
-
- /* 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;
-
- /* We make an extra check here, if the device node
- * actually exists. If it's missing, then this is an
- * indication that device was unplugged but is still
- * referenced in /proc/swaps or
- * /proc/self/mountinfo. Note that this check doesn't
- * really cover all cases where a device might be gone
- * away, since drives that can have a medium inserted
- * will still have a device node even when the medium
- * is not there... */
-
- if (stat(node, &st) >= 0) {
- 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 && errno != ENOENT)
- return log_error_errno(errno, "Failed to get udev device from devnum %u:%u: %m", major(st.st_rdev), minor(st.st_rdev));
-
- } else if (errno != ENOENT)
- return log_error_errno(errno, "Failed to stat device node file %s: %m", node);
-
- /* 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);
-}
-
-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,
-
- .serialize = device_serialize,
- .deserialize_item = device_deserialize_item,
-
- .dump = device_dump,
-
- .active_state = device_active_state,
- .sub_state_to_string = device_sub_state_to_string,
-
- .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 184a1a349b..0000000000
--- a/src/core/device.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#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;
-
-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, deserialized_state;
-};
-
-extern const UnitVTable device_vtable;
-
-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 1e4630182d..0000000000
--- a/src/core/execute.c
+++ /dev/null
@@ -1,3165 +0,0 @@
-/***
- 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 <glob.h>
-#include <grp.h>
-#include <poll.h>
-#include <signal.h>
-#include <string.h>
-#include <sys/personality.h>
-#include <sys/prctl.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/un.h>
-#include <unistd.h>
-#include <utmpx.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 "sd-messages.h"
-
-#include "af-list.h"
-#include "alloc-util.h"
-#ifdef HAVE_APPARMOR
-#include "apparmor-util.h"
-#endif
-#include "async.h"
-#include "barrier.h"
-#include "bus-endpoint.h"
-#include "cap-list.h"
-#include "capability-util.h"
-#include "def.h"
-#include "env-util.h"
-#include "errno-list.h"
-#include "execute.h"
-#include "exit-status.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "formats-util.h"
-#include "fs-util.h"
-#include "glob-util.h"
-#include "io-util.h"
-#include "ioprio.h"
-#include "log.h"
-#include "macro.h"
-#include "missing.h"
-#include "mkdir.h"
-#include "namespace.h"
-#include "parse-util.h"
-#include "path-util.h"
-#include "process-util.h"
-#include "rlimit-util.h"
-#include "rm-rf.h"
-#ifdef HAVE_SECCOMP
-#include "seccomp-util.h"
-#endif
-#include "securebits.h"
-#include "selinux-util.h"
-#include "signal-util.h"
-#include "smack-util.h"
-#include "string-table.h"
-#include "string-util.h"
-#include "strv.h"
-#include "syslog-util.h"
-#include "terminal-util.h"
-#include "unit.h"
-#include "user-util.h"
-#include "util.h"
-#include "utmp-wtmp.h"
-
-#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;
-
- nfd = fcntl(fds[i], F_DUPFD, i + 3);
- if (nfd < 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++) {
-
- r = fd_nonblock(fds[i], nonblock);
- if (r < 0)
- return r;
-
- /* We unconditionally drop FD_CLOEXEC from the fds,
- * since after all we want to pass these fds to our
- * children */
-
- r = fd_cloexec(fds[i], false);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-static const char *exec_context_tty_path(const ExecContext *context) {
- assert(context);
-
- if (context->stdio_as_fds)
- return NULL;
-
- if (context->tty_path)
- return context->tty_path;
-
- return "/dev/console";
-}
-
-static void exec_context_tty_reset(const ExecContext *context, const ExecParameters *p) {
- const char *path;
-
- assert(context);
-
- path = exec_context_tty_path(context);
-
- if (context->tty_vhangup) {
- if (p && p->stdin_fd >= 0)
- (void) terminal_vhangup_fd(p->stdin_fd);
- else if (path)
- (void) terminal_vhangup(path);
- }
-
- if (context->tty_reset) {
- if (p && p->stdin_fd >= 0)
- (void) reset_terminal_fd(p->stdin_fd, true);
- else if (path)
- (void) reset_terminal(path);
- }
-
- if (context->tty_vt_disallocate && path)
- (void) vt_disallocate(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);
-
- fd = open_terminal(path, mode | O_NOCTTY);
- if (fd < 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,
- const ExecParameters *params,
- int socket_fd) {
-
- ExecInput i;
-
- assert(context);
- assert(params);
-
- if (params->stdin_fd >= 0) {
- if (dup2(params->stdin_fd, STDIN_FILENO) < 0)
- return -errno;
-
- /* Try to make this the controlling tty, if it is a tty, and reset it */
- (void) ioctl(STDIN_FILENO, TIOCSCTTY, context->std_input == EXEC_INPUT_TTY_FORCE);
- (void) reset_terminal_fd(STDIN_FILENO, true);
-
- return STDIN_FILENO;
- }
-
- i = fixup_input(context->std_input, socket_fd, params->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(exec_context_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(
- Unit *unit,
- const ExecContext *context,
- const ExecParameters *params,
- int fileno,
- int socket_fd,
- const char *ident,
- uid_t uid, gid_t gid) {
-
- ExecOutput o;
- ExecInput i;
- int r;
-
- assert(unit);
- assert(context);
- assert(params);
- assert(ident);
-
- if (fileno == STDOUT_FILENO && params->stdout_fd >= 0) {
-
- if (dup2(params->stdout_fd, STDOUT_FILENO) < 0)
- return -errno;
-
- return STDOUT_FILENO;
- }
-
- if (fileno == STDERR_FILENO && params->stderr_fd >= 0) {
- if (dup2(params->stderr_fd, STDERR_FILENO) < 0)
- return -errno;
-
- return STDERR_FILENO;
- }
-
- i = fixup_input(context->std_input, socket_fd, params->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(exec_context_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(exec_context_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_error_errno(unit, r, "Failed to connect %s to the journal socket, ignoring: %m", fileno == STDOUT_FILENO ? "stdout" : "stderr");
- 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) {
- _cleanup_close_ int fd = -1, saved_stdin = -1, saved_stdout = -1;
- int 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)
- return -errno;
-
- fd = acquire_terminal(
- "/dev/console",
- false,
- false,
- false,
- DEFAULT_CONFIRM_USEC);
- if (fd < 0)
- return fd;
-
- r = chown_terminal(fd, getuid());
- if (r < 0)
- return r;
-
- r = reset_terminal_fd(fd, true);
- if (r < 0)
- return r;
-
- if (dup2(fd, STDIN_FILENO) < 0)
- return -errno;
-
- if (dup2(fd, STDOUT_FILENO) < 0)
- return -errno;
-
- if (fd >= 2)
- safe_close(fd);
- fd = -1;
-
- *_saved_stdin = saved_stdin;
- *_saved_stdout = saved_stdout;
-
- saved_stdin = saved_stdout = -1;
-
- return 0;
-}
-
-_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;
-
- *saved_stdin = safe_close(*saved_stdin);
- *saved_stdout = 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) {
- /* 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) {
- k = getgroups(ngroups_max, gids);
- if (k < 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 || context->capability_ambient_set != 0) {
-
- /* 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. */
-
- 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 */
- };
-
- 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
- };
-
- _cleanup_(barrier_destroy) Barrier barrier = BARRIER_NULL;
- pam_handle_t *handle = NULL;
- sigset_t old_ss;
- int pam_code = PAM_SUCCESS, r;
- 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. */
-
- r = barrier_create(&barrier);
- if (r < 0)
- goto fail;
-
- 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 */
-
- assert_se(sigprocmask_many(SIG_BLOCK, &old_ss, SIGTERM, -1) >= 0);
-
- parent_pid = getpid();
-
- pam_pid = fork();
- if (pam_pid < 0) {
- r = -errno;
- goto fail;
- }
-
- if (pam_pid == 0) {
- int sig, ret = EXIT_PAM;
-
- /* The child's job is to reset the PAM session on
- * termination */
- barrier_set_role(&barrier, BARRIER_CHILD);
-
- /* 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");
-
- (void) ignore_signals(SIGPIPE, -1);
-
- /* 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;
-
- /* Tell the parent that our setup is done. This is especially
- * important regarding dropping privileges. Otherwise, unit
- * setup might race against our setresuid(2) call. */
- barrier_place(&barrier);
-
- /* Check if our parent process might already have
- * died? */
- if (getppid() == parent_pid) {
- sigset_t ss;
-
- assert_se(sigemptyset(&ss) >= 0);
- assert_se(sigaddset(&ss, SIGTERM) >= 0);
-
- 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;
- }
-
- ret = 0;
-
- child_finish:
- pam_end(handle, pam_code | flags);
- _exit(ret);
- }
-
- barrier_set_role(&barrier, BARRIER_PARENT);
-
- /* 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 */
- assert_se(sigprocmask(SIG_SETMASK, &old_ss, NULL) >= 0);
-
- /* We close the log explicitly here, since the PAM modules
- * might have opened it, but we don't want this fd around. */
- closelog();
-
- /* Synchronously wait for the child to initialize. We don't care for
- * errors as we cannot recover. However, warn loudly if it happens. */
- if (!barrier_place_and_sync(&barrier))
- log_error("PAM initialization failed");
-
- *pam_env = e;
- e = NULL;
-
- return 0;
-
-fail:
- if (pam_code != PAM_SUCCESS) {
- log_error("PAM failed: %s", pam_strerror(handle, pam_code));
- r = -EPERM; /* PAM errors do not map to errno */
- } else
- log_error_errno(r, "PAM failed: %m");
-
- if (handle) {
- if (close_session)
- pam_code = pam_close_session(handle, flags);
-
- pam_end(handle, pam_code | flags);
- }
-
- strv_free(e);
- closelog();
-
- return r;
-}
-#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);
-
-
- idle_pipe[1] = safe_close(idle_pipe[1]);
- idle_pipe[2] = 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 */) {
- ssize_t n;
-
- /* Signal systemd that we are bored and want to continue. */
- n = write(idle_pipe[3], "x", 1);
- if (n > 0)
- /* Wait for systemd to react to the signal above. */
- fd_wait_for_event(idle_pipe[0], POLLHUP, IDLE_TIMEOUT2_USEC);
- }
-
- idle_pipe[0] = safe_close(idle_pipe[0]);
-
- }
-
- idle_pipe[3] = safe_close(idle_pipe[3]);
-}
-
-static int build_environment(
- const ExecContext *c,
- const ExecParameters *p,
- unsigned n_fds,
- 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*, 11);
- if (!our_env)
- return -ENOMEM;
-
- if (n_fds > 0) {
- _cleanup_free_ char *joined = NULL;
-
- 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;
-
- joined = strv_join(p->fd_names, ":");
- if (!joined)
- return -ENOMEM;
-
- x = strjoin("LISTEN_FDNAMES=", joined, NULL);
- if (!x)
- return -ENOMEM;
- our_env[n_env++] = x;
- }
-
- if (p->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, p->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(exec_context_tty_path(c)));
- if (!x)
- return -ENOMEM;
- our_env[n_env++] = x;
- }
-
- our_env[n_env++] = NULL;
- assert(n_env <= 11);
-
- *ret = our_env;
- our_env = NULL;
-
- return 0;
-}
-
-static int build_pass_environment(const ExecContext *c, char ***ret) {
- _cleanup_strv_free_ char **pass_env = NULL;
- size_t n_env = 0, n_bufsize = 0;
- char **i;
-
- STRV_FOREACH(i, c->pass_environment) {
- _cleanup_free_ char *x = NULL;
- char *v;
-
- v = getenv(*i);
- if (!v)
- continue;
- x = strjoin(*i, "=", v, NULL);
- if (!x)
- return -ENOMEM;
- if (!GREEDY_REALLOC(pass_env, n_bufsize, n_env + 2))
- return -ENOMEM;
- pass_env[n_env++] = x;
- pass_env[n_env] = NULL;
- x = NULL;
- }
-
- *ret = pass_env;
- pass_env = NULL;
-
- return 0;
-}
-
-static bool exec_needs_mount_namespace(
- const ExecContext *context,
- const ExecParameters *params,
- ExecRuntime *runtime) {
-
- assert(context);
- assert(params);
-
- if (!strv_isempty(context->read_write_dirs) ||
- !strv_isempty(context->read_only_dirs) ||
- !strv_isempty(context->inaccessible_dirs))
- return true;
-
- if (context->mount_flags != 0)
- return true;
-
- if (context->private_tmp && runtime && (runtime->tmp_dir || runtime->var_tmp_dir))
- return true;
-
- if (params->bus_endpoint_path)
- return true;
-
- if (context->private_devices ||
- context->protect_system != PROTECT_SYSTEM_NO ||
- context->protect_home != PROTECT_HOME_NO)
- return true;
-
- return false;
-}
-
-static int close_remaining_fds(
- const ExecParameters *params,
- ExecRuntime *runtime,
- int socket_fd,
- int *fds, unsigned n_fds) {
-
- unsigned n_dont_close = 0;
- int dont_close[n_fds + 7];
-
- assert(params);
-
- if (params->stdin_fd >= 0)
- dont_close[n_dont_close++] = params->stdin_fd;
- if (params->stdout_fd >= 0)
- dont_close[n_dont_close++] = params->stdout_fd;
- if (params->stderr_fd >= 0)
- dont_close[n_dont_close++] = params->stderr_fd;
-
- 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];
- }
-
- return close_all_fds(dont_close, n_dont_close);
-}
-
-static int exec_child(
- Unit *unit,
- 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, **pass_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, *wd;
- uid_t uid = UID_INVALID;
- gid_t gid = GID_INVALID;
- int i, r;
- bool needs_mount_namespace;
-
- assert(unit);
- 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. */
- (void) default_signals(SIGNALS_CRASH_HANDLER,
- SIGNALS_IGNORE, -1);
-
- if (context->ignore_sigpipe)
- (void) 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();
-
- r = close_remaining_fds(params, runtime, socket_fd, fds, n_fds);
- 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, params);
-
- 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 (context->group) {
- const char *g = context->group;
-
- r = get_group_creds(&g, &gid);
- if (r < 0) {
- *exit_status = EXIT_GROUP;
- return r;
- }
- }
-
-
- /* If a socket is connected to STDIN/STDOUT/STDERR, we
- * must sure to drop O_NONBLOCK */
- if (socket_fd >= 0)
- (void) fd_nonblock(socket_fd, false);
-
- r = setup_input(context, params, socket_fd);
- if (r < 0) {
- *exit_status = EXIT_STDIN;
- return r;
- }
-
- r = setup_output(unit, context, params, STDOUT_FILENO, socket_fd, basename(command->path), uid, gid);
- if (r < 0) {
- *exit_status = EXIT_STDOUT;
- return r;
- }
-
- r = setup_output(unit, context, params, STDERR_FILENO, socket_fd, basename(command->path), 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, 0);
- if (r == -EPERM || r == -EACCES) {
- log_open();
- log_unit_debug_errno(unit, 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 != PERSONALITY_INVALID)
- 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,
- context->utmp_mode == EXEC_UTMP_INIT ? INIT_PROCESS :
- context->utmp_mode == EXEC_UTMP_LOGIN ? LOGIN_PROCESS :
- USER_PROCESS,
- username ? "root" : context->user);
-
- if (context->user && is_terminal_input(context->std_input)) {
- r = chown_terminal(STDIN_FILENO, uid);
- if (r < 0) {
- *exit_status = EXIT_STDIN;
- return r;
- }
- }
-
- 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;
- }
- }
-
- /* 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_p_label(p, context->runtime_directory_mode);
- if (r < 0) {
- *exit_status = EXIT_RUNTIME_DIRECTORY;
- return r;
- }
-
- r = chmod_and_chown(p, context->runtime_directory_mode, uid, gid);
- if (r < 0) {
- *exit_status = EXIT_RUNTIME_DIRECTORY;
- return r;
- }
- }
- }
-
- umask(context->umask);
-
- if (params->apply_permissions) {
- r = enforce_groups(context, username, gid);
- if (r < 0) {
- *exit_status = EXIT_GROUP;
- 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;
- }
- }
-#ifdef SMACK_DEFAULT_PROCESS_LABEL
- else {
- _cleanup_free_ char *exec_label = NULL;
-
- r = mac_smack_read(command->path, SMACK_ATTR_EXEC, &exec_label);
- if (r < 0 && r != -ENODATA && r != -EOPNOTSUPP) {
- *exit_status = EXIT_SMACK_PROCESS_LABEL;
- return r;
- }
-
- r = mac_smack_apply_pid(0, exec_label ? : SMACK_DEFAULT_PROCESS_LABEL);
- if (r < 0) {
- *exit_status = EXIT_SMACK_PROCESS_LABEL;
- return r;
- }
- }
-#endif
-#endif
-#ifdef HAVE_PAM
- if (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;
- }
- }
-
- needs_mount_namespace = exec_needs_mount_namespace(context, params, runtime);
-
- if (needs_mount_namespace) {
- 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(
- params->apply_chroot ? context->root_directory : NULL,
- 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(unit, r, "Failed to set up namespace, assuming containerized execution, ignoring: %m");
- log_close();
- } else if (r < 0) {
- *exit_status = EXIT_NAMESPACE;
- return r;
- }
- }
-
- if (context->working_directory_home)
- wd = home;
- else if (context->working_directory)
- wd = context->working_directory;
- else
- wd = "/";
-
- if (params->apply_chroot) {
- if (!needs_mount_namespace && context->root_directory)
- if (chroot(context->root_directory) < 0) {
- *exit_status = EXIT_CHROOT;
- return -errno;
- }
-
- if (chdir(wd) < 0 &&
- !context->working_directory_missing_ok) {
- *exit_status = EXIT_CHDIR;
- return -errno;
- }
- } else {
- const char *d;
-
- d = strjoina(strempty(context->root_directory), "/", strempty(wd));
- 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) {
-
- int secure_bits = context->secure_bits;
-
- 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 (!cap_test_all(context->capability_bounding_set)) {
- r = capability_bounding_set_drop(context->capability_bounding_set, false);
- if (r < 0) {
- *exit_status = EXIT_CAPABILITIES;
- return r;
- }
- }
-
- /* This is done before enforce_user, but ambient set
- * does not survive over setresuid() if keep_caps is not set. */
- if (context->capability_ambient_set != 0) {
- r = capability_ambient_set_apply(context->capability_ambient_set, true);
- if (r < 0) {
- *exit_status = EXIT_CAPABILITIES;
- return r;
- }
-
- if (context->capabilities) {
-
- /* The capabilities in ambient set need to be also in the inherited
- * set. If they aren't, trying to get them will fail. Add the ambient
- * set inherited capabilities to the capability set in the context.
- * This is needed because if capabilities are set (using "Capabilities="
- * keyword), they will override whatever we set now. */
-
- r = capability_update_inherited_set(context->capabilities, context->capability_ambient_set);
- if (r < 0) {
- *exit_status = EXIT_CAPABILITIES;
- return r;
- }
- }
- }
-
- if (context->user) {
- r = enforce_user(context, uid);
- if (r < 0) {
- *exit_status = EXIT_USER;
- return r;
- }
- if (context->capability_ambient_set != 0) {
-
- /* Fix the ambient capabilities after user change. */
- r = capability_ambient_set_apply(context->capability_ambient_set, false);
- if (r < 0) {
- *exit_status = EXIT_CAPABILITIES;
- return r;
- }
-
- /* If we were asked to change user and ambient capabilities
- * were requested, we had to add keep-caps to the securebits
- * so that we would maintain the inherited capability set
- * through the setresuid(). Make sure that the bit is added
- * also to the context secure_bits so that we don't try to
- * drop the bit away next. */
-
- secure_bits |= 1<<SECURE_KEEP_CAPS;
- }
- }
-
- /* 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) != secure_bits)
- if (prctl(PR_SET_SECUREBITS, 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, params, n_fds, home, username, shell, &our_env);
- if (r < 0) {
- *exit_status = EXIT_MEMORY;
- return r;
- }
-
- r = build_pass_environment(context, &pass_env);
- if (r < 0) {
- *exit_status = EXIT_MEMORY;
- return r;
- }
-
- final_env = strv_env_merge(6,
- params->environment,
- our_env,
- pass_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_struct(LOG_DEBUG,
- LOG_UNIT_ID(unit),
- "EXECUTABLE=%s", command->path,
- LOG_UNIT_MESSAGE(unit, "Executing: %s", line),
- NULL);
- log_close();
- }
- }
-
- execve(command->path, final_argv, final_env);
- *exit_status = EXIT_EXEC;
- return -errno;
-}
-
-int exec_spawn(Unit *unit,
- 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(unit);
- 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(unit, "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(unit, context, &files_env);
- if (r < 0)
- return log_unit_error_errno(unit, r, "Failed to load environment files: %m");
-
- argv = params->argv ?: command->argv;
- line = exec_command_line(argv);
- if (!line)
- return log_oom();
-
- log_struct(LOG_DEBUG,
- LOG_UNIT_ID(unit),
- LOG_UNIT_MESSAGE(unit, "About to execute: %s", line),
- "EXECUTABLE=%s", command->path,
- NULL);
- pid = fork();
- if (pid < 0)
- return log_unit_error_errno(unit, errno, "Failed to fork: %m");
-
- if (pid == 0) {
- int exit_status;
-
- r = exec_child(unit,
- command,
- context,
- params,
- runtime,
- argv,
- socket_fd,
- fds, n_fds,
- files_env,
- &exit_status);
- if (r < 0) {
- log_open();
- log_struct_errno(LOG_ERR, r,
- LOG_MESSAGE_ID(SD_MESSAGE_SPAWN_FAILED),
- LOG_UNIT_ID(unit),
- LOG_UNIT_MESSAGE(unit, "Failed at step %s spawning %s: %m",
- exit_status_to_string(exit_status, EXIT_STATUS_SYSTEMD),
- command->path),
- "EXECUTABLE=%s", command->path,
- NULL);
- }
-
- _exit(exit_status);
- }
-
- log_unit_debug(unit, "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)
- (void) 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 = PERSONALITY_INVALID;
- c->runtime_directory_mode = 0755;
- c->capability_bounding_set = CAP_ALL;
-}
-
-void exec_context_done(ExecContext *c) {
- unsigned l;
-
- assert(c);
-
- c->environment = strv_free(c->environment);
- c->environment_files = strv_free(c->environment_files);
- c->pass_environment = strv_free(c->pass_environment);
-
- for (l = 0; l < ELEMENTSOF(c->rlimit); l++)
- c->rlimit[l] = mfree(c->rlimit[l]);
-
- c->working_directory = mfree(c->working_directory);
- c->root_directory = mfree(c->root_directory);
- c->tty_path = mfree(c->tty_path);
- c->syslog_identifier = mfree(c->syslog_identifier);
- c->user = mfree(c->user);
- c->group = mfree(c->group);
-
- c->supplementary_groups = strv_free(c->supplementary_groups);
-
- c->pam_name = mfree(c->pam_name);
-
- if (c->capabilities) {
- cap_free(c->capabilities);
- c->capabilities = NULL;
- }
-
- c->read_only_dirs = strv_free(c->read_only_dirs);
- c->read_write_dirs = strv_free(c->read_write_dirs);
- c->inaccessible_dirs = strv_free(c->inaccessible_dirs);
-
- if (c->cpuset)
- CPU_FREE(c->cpuset);
-
- c->utmp_id = mfree(c->utmp_id);
- c->selinux_context = mfree(c->selinux_context);
- c->apparmor_profile = mfree(c->apparmor_profile);
-
- c->syscall_filter = set_free(c->syscall_filter);
- c->syscall_archs = set_free(c->syscall_archs);
- c->address_families = set_free(c->address_families);
-
- c->runtime_directory = strv_free(c->runtime_directory);
-
- 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. */
- (void) rm_rf(p, REMOVE_ROOT);
- }
-
- return 0;
-}
-
-void exec_command_done(ExecCommand *c) {
- assert(c);
-
- c->path = mfree(c->path);
-
- c->argv = strv_free(c->argv);
-}
-
-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 {
- Unit *unit;
- const char *path;
-} InvalidEnvInfo;
-
-static void invalid_env(const char *p, void *userdata) {
- InvalidEnvInfo *info = userdata;
-
- log_unit_error(info->unit, "Ignoring invalid environment assignment '%s': %s", p, info->path);
-}
-
-int exec_context_load_environment(Unit *unit, const ExecContext *c, 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 > 0 ? -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 = unit,
- .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 (!tty)
- return true;
-
- 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(exec_context_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, **d;
- 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);
-
- STRV_FOREACH(e, c->pass_environment)
- fprintf(f, "%sPassEnvironment: %s\n", prefix, *e);
-
- fprintf(f, "%sRuntimeDirectoryMode: %04o\n", prefix, c->runtime_directory_mode);
-
- STRV_FOREACH(d, c->runtime_directory)
- fprintf(f, "%sRuntimeDirectory: %s\n", prefix, *d);
-
- 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);
- fprintf(f, "%s%sSoft: " RLIM_FMT "\n",
- prefix, rlimit_to_string(i), c->rlimit[i]->rlim_cur);
- }
-
- 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 != CAP_ALL) {
- unsigned long l;
- fprintf(f, "%sCapabilityBoundingSet:", prefix);
-
- for (l = 0; l <= cap_last_cap(); l++)
- if (c->capability_bounding_set & (UINT64_C(1) << l))
- fprintf(f, " %s", strna(capability_to_name(l)));
-
- fputs("\n", f);
- }
-
- if (c->capability_ambient_set != 0) {
- unsigned long l;
- fprintf(f, "%sAmbientCapabilities:", prefix);
-
- for (l = 0; l <= cap_last_cap(); l++)
- if (c->capability_ambient_set & (UINT64_C(1) << 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 != PERSONALITY_INVALID)
- 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, NULL);
- }
-}
-
-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, false);
- 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)
- return NULL;
-
- free(r->tmp_dir);
- free(r->var_tmp_dir);
- safe_close_pair(r->netns_storage_socket);
- free(r);
-
- return NULL;
-}
-
-int exec_runtime_serialize(Unit *u, ExecRuntime *rt, 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(Unit *u, ExecRuntime **rt, 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 log_oom();
-
- 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 log_oom();
-
- 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 log_oom();
-
- if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u, "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 log_oom();
-
- if (safe_atoi(value, &fd) < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u, "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;
-
- (void) rm_rf(path, REMOVE_ROOT|REMOVE_PHYSICAL);
- 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);
-
-static const char* const exec_utmp_mode_table[_EXEC_UTMP_MODE_MAX] = {
- [EXEC_UTMP_INIT] = "init",
- [EXEC_UTMP_LOGIN] = "login",
- [EXEC_UTMP_USER] = "user",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(exec_utmp_mode, ExecUtmpMode);
diff --git a/src/core/execute.h b/src/core/execute.h
deleted file mode 100644
index 578f85b6bc..0000000000
--- a/src/core/execute.h
+++ /dev/null
@@ -1,297 +0,0 @@
-#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 <sched.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <sys/capability.h>
-
-#include "bus-endpoint.h"
-#include "fdset.h"
-#include "list.h"
-#include "missing.h"
-#include "namespace.h"
-
-typedef enum ExecUtmpMode {
- EXEC_UTMP_INIT,
- EXEC_UTMP_LOGIN,
- EXEC_UTMP_USER,
- _EXEC_UTMP_MODE_MAX,
- _EXEC_UTMP_MODE_INVALID = -1
-} ExecUtmpMode;
-
-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;
- char **pass_environment;
-
- struct rlimit *rlimit[_RLIMIT_MAX];
- char *working_directory, *root_directory;
- bool working_directory_missing_ok;
- bool working_directory_home;
-
- 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;
-
- bool stdio_as_fds;
-
- 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;
- ExecUtmpMode utmp_mode;
-
- 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;
-
- uint64_t capability_ambient_set;
-
- 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
- * /usr/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-util.h"
-#include "cgroup.h"
-
-struct ExecParameters {
- char **argv;
- char **environment;
-
- int *fds;
- char **fd_names;
- unsigned n_fds;
-
- bool apply_permissions:1;
- bool apply_chroot:1;
- bool apply_tty_stdin:1;
-
- bool confirm_spawn:1;
- bool selinux_context_net:1;
-
- bool cgroup_delegate:1;
- CGroupMask cgroup_supported;
- const char *cgroup_path;
-
- const char *runtime_prefix;
-
- usec_t watchdog_usec;
-
- int *idle_pipe;
-
- char *bus_endpoint_path;
- int bus_endpoint_fd;
-
- int stdin_fd;
- int stdout_fd;
- int stderr_fd;
-};
-
-int exec_spawn(Unit *unit,
- 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(Unit *unit, const ExecContext *c, 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(Unit *unit, ExecRuntime *rt, FILE *f, FDSet *fds);
-int exec_runtime_deserialize_item(Unit *unit, ExecRuntime **rt, 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_;
-
-const char* exec_utmp_mode_to_string(ExecUtmpMode i) _const_;
-ExecUtmpMode exec_utmp_mode_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 39f5519ca1..0000000000
--- a/src/core/failure-action.c
+++ /dev/null
@@ -1,125 +0,0 @@
-/***
- 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-error.h"
-#include "bus-util.h"
-#include "failure-action.h"
-#include "special.h"
-#include "string-table.h"
-#include "terminal-util.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 " !! " ANSI_NORMAL,
- "%s", message);
-}
-
-int failure_action(
- Manager *m,
- FailureAction action,
- const char *reboot_arg) {
-
- assert(m);
- assert(action >= 0);
- assert(action < _FAILURE_ACTION_MAX);
-
- if (action == FAILURE_ACTION_NONE)
- return -ECANCELED;
-
- if (m->running_as == MANAGER_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:
- log_and_status(m, "Rebooting as result of failure.");
-
- update_reboot_param_file(reboot_arg);
- (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE, NULL);
-
- 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:
- log_and_status(m, "Powering off as result of failure.");
- (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE, NULL);
- 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 1adac4ad5c..0000000000
--- a/src/core/failure-action.h
+++ /dev/null
@@ -1,41 +0,0 @@
-#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 68be52856b..0000000000
--- a/src/core/hostname-setup.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/***
- 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 <stdlib.h>
-
-#include "alloc-util.h"
-#include "fileio.h"
-#include "hostname-setup.h"
-#include "hostname-util.h"
-#include "log.h"
-#include "macro.h"
-#include "string-util.h"
-#include "util.h"
-
-int hostname_setup(void) {
- int r;
- _cleanup_free_ char *b = NULL;
- const char *hn;
- bool enoent = false;
-
- r = read_hostname_config("/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";
- }
-
- r = sethostname_idempotent(hn);
- if (r < 0)
- return log_warning_errno(r, "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 73e8c75c71..0000000000
--- a/src/core/hostname-setup.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#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 ff7558d500..0000000000
--- a/src/core/ima-setup.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/***
- 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 <errno.h>
-#include <unistd.h>
-
-#include "fd-util.h"
-#include "fileio.h"
-#include "ima-setup.h"
-#include "log.h"
-#include "util.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) {
-#ifdef HAVE_IMA
- _cleanup_fclose_ FILE *input = NULL;
- _cleanup_close_ int imafd = -1;
- unsigned lineno = 0;
- char line[page_size()];
-
- if (access(IMA_SECFS_DIR, F_OK) < 0) {
- log_debug("IMA support is disabled in the kernel, ignoring.");
- return 0;
- }
-
- input = fopen(IMA_POLICY_PATH, "re");
- if (!input) {
- 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;
- }
-
- FOREACH_LINE(line, input,
- return log_error_errno(errno, "Failed to read the IMA custom policy file "IMA_POLICY_PATH": %m")) {
- size_t len;
-
- len = strlen(line);
- lineno++;
-
- if (len > 0 && write(imafd, line, len) < 0)
- return log_error_errno(errno, "Failed to load the IMA custom policy file "IMA_POLICY_PATH"%u: %m",
- lineno);
- }
-
- log_info("Successfully loaded the IMA custom policy "IMA_POLICY_PATH".");
-#endif /* HAVE_IMA */
- return 0;
-}
diff --git a/src/core/ima-setup.h b/src/core/ima-setup.h
deleted file mode 100644
index 3bad74b246..0000000000
--- a/src/core/ima-setup.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#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 97304c4d05..0000000000
--- a/src/core/job.c
+++ /dev/null
@@ -1,1249 +0,0 @@
-/***
- 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 "alloc-util.h"
-#include "async.h"
-#include "dbus-job.h"
-#include "dbus.h"
-#include "escape.h"
-#include "job.h"
-#include "log.h"
-#include "macro.h"
-#include "parse-util.h"
-#include "set.h"
-#include "special.h"
-#include "stdio-util.h"
-#include "string-table.h"
-#include "string-util.h"
-#include "strv.h"
-#include "terminal-util.h"
-#include "unit.h"
-#include "virt.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->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,
- "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,
- "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,
- "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, "Unit already has a job installed. Not installing deserialized job.");
- return -EEXIST;
- }
-
- *pj = j;
- j->installed = true;
-
- if (j->state == JOB_RUNNING)
- j->unit->manager->n_running_jobs++;
-
- log_unit_debug(j->unit,
- "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\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->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");
- }
-}
-
-JobType 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))
- return JOB_NOP;
-
- return JOB_RESTART;
-
- case JOB_TRY_RELOAD:
- s = unit_active_state(u);
- if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
- return JOB_NOP;
-
- return JOB_RELOAD;
-
- case JOB_RELOAD_OR_START:
- s = unit_active_state(u);
- if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
- return JOB_START;
-
- return JOB_RELOAD;
-
- default:
- return t;
- }
-}
-
-int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u) {
- JobType t;
-
- t = job_type_lookup_merge(*a, b);
- if (t < 0)
- return -EEXIST;
-
- *a = job_type_collapse(t, 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 let's 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 let's 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) {
- assert(j);
-
- log_unit_debug(j->unit,
- "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;
-}
-
-static int job_perform_on_unit(Job **j) {
- uint32_t id;
- Manager *m;
- JobType t;
- Unit *u;
- int r;
-
- /* While we execute this operation the job might go away (for
- * example: because it finishes immediately or 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. */
-
- assert(j);
- assert(*j);
-
- m = (*j)->manager;
- u = (*j)->unit;
- t = (*j)->type;
- id = (*j)->id;
-
- switch (t) {
- case JOB_START:
- r = unit_start(u);
- break;
-
- case JOB_RESTART:
- t = JOB_STOP;
- /* fall through */
- case JOB_STOP:
- r = unit_stop(u);
- break;
-
- case JOB_RELOAD:
- r = unit_reload(u);
- break;
-
- default:
- assert_not_reached("Invalid job type");
- }
-
- /* Log if the job still exists and the start/stop/reload function
- * actually did something. */
- *j = manager_get_job(m, id);
- if (*j && r > 0)
- unit_status_emit_starting_stopping_reloading(u, t);
-
- return r;
-}
-
-int job_run_and_invalidate(Job *j) {
- int r;
-
- 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);
-
-
- switch (j->type) {
-
- 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_START:
- case JOB_STOP:
- case JOB_RESTART:
- r = job_perform_on_unit(&j);
-
- /* If the unit type does not support starting/stopping,
- * then simply wait. */
- if (r == -EBADR)
- r = 0;
- break;
-
- case JOB_RELOAD:
- r = job_perform_on_unit(&j);
- break;
-
- case JOB_NOP:
- r = -EALREADY;
- break;
-
- default:
- assert_not_reached("Unknown job type");
- }
-
- 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) {
-
- static const char *const generic_finished_start_job[_JOB_RESULT_MAX] = {
- [JOB_DONE] = "Started %s.",
- [JOB_TIMEOUT] = "Timed out starting %s.",
- [JOB_FAILED] = "Failed to start %s.",
- [JOB_DEPENDENCY] = "Dependency failed for %s.",
- [JOB_ASSERT] = "Assertion failed for %s.",
- [JOB_UNSUPPORTED] = "Starting of %s not supported.",
- };
- static const char *const generic_finished_stop_job[_JOB_RESULT_MAX] = {
- [JOB_DONE] = "Stopped %s.",
- [JOB_FAILED] = "Stopped (with error) %s.",
- [JOB_TIMEOUT] = "Timed out stoppping %s.",
- };
- static const char *const generic_finished_reload_job[_JOB_RESULT_MAX] = {
- [JOB_DONE] = "Reloaded %s.",
- [JOB_FAILED] = "Reload failed for %s.",
- [JOB_TIMEOUT] = "Timed out reloading %s.",
- };
- /* 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. */
- static const char *const generic_finished_verify_active_job[_JOB_RESULT_MAX] = {
- [JOB_SKIPPED] = "%s is not active.",
- };
-
- const UnitStatusMessageFormats *format_table;
- const char *format;
-
- assert(u);
- assert(t >= 0);
- assert(t < _JOB_TYPE_MAX);
-
- if (IN_SET(t, JOB_START, JOB_STOP, JOB_RESTART)) {
- format_table = &UNIT_VTABLE(u)->status_message_formats;
- if (format_table) {
- format = t == JOB_START ? format_table->finished_start_job[result] :
- format_table->finished_stop_job[result];
- if (format)
- return format;
- }
- }
-
- /* Return generic strings */
- if (t == JOB_START)
- return generic_finished_start_job[result];
- else if (t == JOB_STOP || t == JOB_RESTART)
- return generic_finished_stop_job[result];
- else if (t == JOB_RELOAD)
- return generic_finished_reload_job[result];
- else if (t == JOB_VERIFY_ACTIVE)
- return generic_finished_verify_active_job[result];
-
- return NULL;
-}
-
-static void job_print_status_message(Unit *u, JobType t, JobResult result) {
- static const char* const job_result_status_table[_JOB_RESULT_MAX] = {
- [JOB_DONE] = ANSI_GREEN " OK " ANSI_NORMAL,
- [JOB_TIMEOUT] = ANSI_HIGHLIGHT_RED " TIME " ANSI_NORMAL,
- [JOB_FAILED] = ANSI_HIGHLIGHT_RED "FAILED" ANSI_NORMAL,
- [JOB_DEPENDENCY] = ANSI_HIGHLIGHT_YELLOW "DEPEND" ANSI_NORMAL,
- [JOB_SKIPPED] = ANSI_HIGHLIGHT " INFO " ANSI_NORMAL,
- [JOB_ASSERT] = ANSI_HIGHLIGHT_YELLOW "ASSERT" ANSI_NORMAL,
- [JOB_UNSUPPORTED] = ANSI_HIGHLIGHT_YELLOW "UNSUPP" ANSI_NORMAL,
- };
-
- const char *format;
-
- assert(u);
- assert(t >= 0);
- assert(t < _JOB_TYPE_MAX);
-
- /* Reload status messages have traditionally not been printed to console. */
- if (t == JOB_RELOAD)
- return;
-
- format = job_get_status_message_format(u, t, result);
- if (!format)
- return;
-
- if (result != JOB_DONE)
- manager_flip_auto_status(u->manager, true);
-
- DISABLE_WARNING_FORMAT_NONLITERAL;
- unit_status_printf(u, job_result_status_table[result], format);
- REENABLE_WARNING;
-
- if (t == JOB_START && result == JOB_FAILED) {
- _cleanup_free_ char *quoted;
-
- quoted = shell_maybe_quote(u->id);
- manager_status_printf(u->manager, STATUS_TYPE_NORMAL, NULL, "See 'systemctl status %s' for details.", strna(quoted));
- }
-}
-
-static void job_log_status_message(Unit *u, JobType t, JobResult result) {
- const char *format;
- char buf[LINE_MAX];
- sd_id128_t mid;
- static const int job_result_log_level[_JOB_RESULT_MAX] = {
- [JOB_DONE] = LOG_INFO,
- [JOB_CANCELED] = LOG_INFO,
- [JOB_TIMEOUT] = LOG_ERR,
- [JOB_FAILED] = LOG_ERR,
- [JOB_DEPENDENCY] = LOG_WARNING,
- [JOB_SKIPPED] = LOG_NOTICE,
- [JOB_INVALID] = LOG_INFO,
- [JOB_ASSERT] = LOG_WARNING,
- [JOB_UNSUPPORTED] = LOG_WARNING,
- };
-
- 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(u, t, result);
- if (!format)
- return;
-
- DISABLE_WARNING_FORMAT_NONLITERAL;
- xsprintf(buf, format, unit_description(u));
- REENABLE_WARNING;
-
- switch (t) {
-
- case JOB_START:
- mid = result == JOB_DONE ? SD_MESSAGE_UNIT_STARTED : SD_MESSAGE_UNIT_FAILED;
- break;
-
- case JOB_RELOAD:
- mid = SD_MESSAGE_UNIT_RELOADED;
- break;
-
- case JOB_STOP:
- case JOB_RESTART:
- mid = SD_MESSAGE_UNIT_STOPPED;
- break;
-
- default:
- log_struct(job_result_log_level[result],
- LOG_UNIT_ID(u),
- LOG_MESSAGE("%s", buf),
- "RESULT=%s", job_result_to_string(result),
- NULL);
- return;
- }
-
- log_struct(job_result_log_level[result],
- LOG_MESSAGE_ID(mid),
- LOG_UNIT_ID(u),
- LOG_MESSAGE("%s", buf),
- "RESULT=%s", job_result_to_string(result),
- NULL);
-}
-
-static void job_emit_status_message(Unit *u, JobType t, JobResult result) {
-
- /* No message if the job did not actually do anything due to failed condition. */
- if (t == JOB_START && result == JOB_DONE && !u->condition_result)
- return;
-
- job_log_status_message(u, t, result);
- job_print_status_message(u, t, result);
-}
-
-static void job_fail_dependencies(Unit *u, UnitDependency d) {
- Unit *other;
- Iterator i;
-
- assert(u);
-
- SET_FOREACH(other, u->dependencies[d], i) {
- Job *j = other->job;
-
- if (!j)
- continue;
- if (!IN_SET(j->type, JOB_START, JOB_VERIFY_ACTIVE))
- continue;
-
- job_finish_and_invalidate(j, JOB_DEPENDENCY, true);
- }
-}
-
-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, "Job %s/%s finished, result=%s", u->id, job_type_to_string(t), job_result_to_string(result));
-
- job_emit_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 (IN_SET(t, JOB_START, JOB_VERIFY_ACTIVE)) {
- job_fail_dependencies(u, UNIT_REQUIRED_BY);
- job_fail_dependencies(u, UNIT_REQUISITE_OF);
- job_fail_dependencies(u, UNIT_BOUND_BY);
- } else if (t == JOB_STOP)
- job_fail_dependencies(u, UNIT_CONFLICTED_BY);
- }
-
- /* 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_struct(LOG_NOTICE,
- "JOB_TYPE=%s", job_type_to_string(t),
- "JOB_RESULT=%s", job_result_to_string(result),
- LOG_UNIT_ID(u),
- LOG_UNIT_MESSAGE(u, "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, "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 == USEC_INFINITY)
- return 0;
-
- r = sd_event_add_time(
- j->manager->event,
- &j->timer_event_source,
- CLOCK_MONOTONIC,
- usec_add(j->begin_usec, j->unit->job_timeout), 0,
- job_dispatch_timer, j);
- if (r < 0)
- return r;
-
- (void) sd_event_source_set_description(j->timer_event_source, "job-start");
-
- 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-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-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 == USEC_INFINITY)
- return 0;
-
- 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,
- usec_add(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");
-
- (void) sd_event_source_set_description(j->timer_event_source, "job-timeout");
-
- 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 != MANAGER_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() > 0)
- return;
-
- asynchronous_sync();
-}
-
-int job_get_timeout(Job *j, usec_t *timeout) {
- usec_t x = USEC_INFINITY, y = USEC_INFINITY;
- Unit *u = j->unit;
- int r;
-
- assert(u);
-
- if (j->timer_event_source) {
- r = sd_event_source_get_time(j->timer_event_source, &x);
- if (r < 0)
- return r;
- }
-
- if (UNIT_VTABLE(u)->get_timeout) {
- r = UNIT_VTABLE(u)->get_timeout(u, &y);
- if (r < 0)
- return r;
- }
-
- if (x == USEC_INFINITY && y == USEC_INFINITY)
- 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_TRY_RELOAD] = "try-reload",
- [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);
-
-const char* job_type_to_access_method(JobType t) {
- assert(t >= 0);
- assert(t < _JOB_TYPE_MAX);
-
- if (IN_SET(t, JOB_START, JOB_RESTART, JOB_TRY_RESTART))
- return "start";
- else if (t == JOB_STOP)
- return "stop";
- else
- return "reload";
-}
diff --git a/src/core/job.h b/src/core/job.h
deleted file mode 100644
index 856b0ce829..0000000000
--- a/src/core/job.h
+++ /dev/null
@@ -1,242 +0,0 @@
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-
-#include "sd-event.h"
-
-#include "list.h"
-#include "unit-name.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 */
-
- /* Similar to JOB_TRY_RESTART but collapses to JOB_RELOAD or JOB_NOP */
- JOB_TRY_RELOAD,
-
- /* 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 "unit.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 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. */
-JobType 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);
-
-int job_get_timeout(Job *j, usec_t *timeout) _pure_;
-
-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_;
-
-const char* job_type_to_access_method(JobType t);
diff --git a/src/core/kill.c b/src/core/kill.c
deleted file mode 100644
index 6854587d54..0000000000
--- a/src/core/kill.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2012 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "kill.h"
-#include "signal-util.h"
-#include "string-table.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",
- [KILL_MAIN_FAIL] = "main-fail",
- [KILL_CONTROL_FAIL] = "control-fail",
- [KILL_ALL_FAIL] = "all-fail"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);
diff --git a/src/core/kill.h b/src/core/kill.h
deleted file mode 100644
index b3d2056cb0..0000000000
--- a/src/core/kill.h
+++ /dev/null
@@ -1,65 +0,0 @@
-#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_MAIN_FAIL,
- KILL_CONTROL_FAIL,
- KILL_ALL_FAIL,
- _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 09378f7085..0000000000
--- a/src/core/killall.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/***
- 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 <signal.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#include "alloc-util.h"
-#include "fd-util.h"
-#include "formats-util.h"
-#include "killall.h"
-#include "parse-util.h"
-#include "process-util.h"
-#include "set.h"
-#include "string-util.h"
-#include "terminal-util.h"
-#include "util.h"
-
-#define TIMEOUT_USEC (10 * USEC_PER_SEC)
-
-static bool ignore_proc(pid_t pid, bool warn_rootfs) {
- _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 (c == '@' && warn_rootfs) {
- _cleanup_free_ char *comm = NULL;
-
- r = pid_from_same_root_fs(pid);
- if (r < 0)
- return true;
-
- get_process_comm(pid, &comm);
-
- if (r)
- log_notice("Process " PID_FMT " (%s) has been been marked to be excluded from killing. It is "
- "running from the root file system, and thus likely to block re-mounting of the "
- "root file system to read-only. Please consider moving it into an initrd file "
- "system instead.", pid, strna(comm));
- return true;
- } else if (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;
- }
-
- (void) set_remove(pids, PID_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(PTR_TO_PID(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;
- int r;
-
- 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, sig == SIGKILL && !in_initrd()))
- 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) {
- r = set_put(pids, PID_TO_PTR(pid));
- if (r < 0)
- log_oom();
- }
- } 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 acc2439f00..0000000000
--- a/src/core/killall.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#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 3503db52ed..0000000000
--- a/src/core/kmod-setup.c
+++ /dev/null
@@ -1,131 +0,0 @@
-/***
- 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 <string.h>
-#include <unistd.h>
-
-#ifdef HAVE_KMOD
-#include <libkmod.h>
-#endif
-
-#include "bus-util.h"
-#include "capability-util.h"
-#include "kmod-setup.h"
-#include "macro.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;
-}
-#endif
-
-int kmod_setup(void) {
-#ifdef HAVE_KMOD
-
- static const struct {
- const char *module;
- const char *path;
- bool warn_if_unavailable:1;
- bool warn_if_module:1;
- bool (*condition_fn)(void);
- } kmod_table[] = {
- /* auto-loading on use doesn't work before udev is up */
- { "autofs4", "/sys/class/misc/autofs", true, false, NULL },
-
- /* early configure of ::1 on the loopback device */
- { "ipv6", "/sys/module/ipv6", false, true, NULL },
-
- /* this should never be a module */
- { "unix", "/proc/net/unix", true, true, NULL },
-
- /* IPC is needed before we bring up any other services */
- { "kdbus", "/sys/fs/kdbus", false, false, is_kdbus_wanted },
-
-#ifdef HAVE_LIBIPTC
- /* netfilter is needed by networkd, nspawn among others, and cannot be autoloaded */
- { "ip_tables", "/proc/net/ip_tables_names", false, false, NULL },
-#endif
- };
- 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_if_module)
- 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_debug("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 {
- bool print_warning = kmod_table[i].warn_if_unavailable || (r < 0 && r != -ENOENT);
-
- log_full_errno(print_warning ? LOG_WARNING : LOG_DEBUG, r,
- "Failed to insert module '%s': %m", 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 685f4df301..0000000000
--- a/src/core/kmod-setup.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#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 22b71b6f5e..0000000000
--- a/src/core/load-dropin.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-
-#include "conf-parser.h"
-#include "load-dropin.h"
-#include "load-fragment.h"
-#include "log.h"
-#include "strv.h"
-#include "unit-name.h"
-#include "unit.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);
- }
- }
-
- u->dropin_paths = strv_free(u->dropin_paths);
- 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 d8a4aefbb3..0000000000
--- a/src/core/load-dropin.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "dropin.h"
-#include "unit.h"
-
-/* Read service data supplementary drop-in directories */
-
-static inline int unit_find_dropin_paths(Unit *u, char ***paths) {
- 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 5024fd19a5..0000000000
--- a/src/core/load-fragment-gperf.gperf.m4
+++ /dev/null
@@ -1,378 +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_working_directory, 0, offsetof($1, exec_context)
-$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.PassEnvironment, config_parse_pass_environ, 0, offsetof($1, exec_context.pass_environment)
-$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_capability_set, 0, offsetof($1, exec_context.capability_bounding_set)
-$1.AmbientCapabilities, config_parse_capability_set, 0, offsetof($1, exec_context.capability_ambient_set)
-$1.TimerSlackNSec, config_parse_nsec, 0, offsetof($1, exec_context.timer_slack_nsec)
-$1.NoNewPrivileges, config_parse_no_new_privileges, 0, offsetof($1, exec_context)
-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)
-$1.UtmpMode, config_parse_exec_utmp_mode, 0, offsetof($1, exec_context.utmp_mode)
-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_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.TasksAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.tasks_accounting)
-$1.TasksMax, config_parse_tasks_max, 0, offsetof($1, cgroup_context.tasks_max)
-$1.Delegate, config_parse_bool, 0, offsetof($1, cgroup_context.delegate)
-$1.NetClass, config_parse_warn_compat, DISABLED_LEGACY, 0'
-)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.Requisite, config_parse_unit_deps, UNIT_REQUISITE, 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.RequiresOverridable, config_parse_obsolete_unit_deps, UNIT_REQUIRES, 0
-Unit.RequisiteOverridable, config_parse_obsolete_unit_deps, UNIT_REQUISITE, 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_warn_compat, DISABLED_LEGACY, 0
-Unit.JobTimeoutSec, config_parse_sec_fix_0, 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.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval)
-Unit.StartLimitBurst, config_parse_unsigned, 0, offsetof(Unit, start_limit.burst)
-Unit.StartLimitAction, config_parse_failure_action, 0, offsetof(Unit, start_limit_action)
-Unit.RebootArgument, config_parse_string, 0, offsetof(Unit, 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, 0
-Service.TimeoutStartSec, config_parse_service_timeout, 0, 0
-Service.TimeoutStopSec, config_parse_service_timeout, 0, 0
-Service.RuntimeMaxSec, config_parse_sec, 0, offsetof(Service, runtime_max_usec)
-Service.WatchdogSec, config_parse_sec, 0, offsetof(Service, watchdog_usec)
-Service.StartLimitInterval, config_parse_sec, 0, offsetof(Unit, start_limit.interval)
-Service.StartLimitBurst, config_parse_unsigned, 0, offsetof(Unit, start_limit.burst)
-Service.StartLimitAction, config_parse_failure_action, 0, offsetof(Unit, start_limit_action)
-Service.RebootArgument, config_parse_string, 0, offsetof(Unit, 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
-Service.BusPolicy, config_parse_bus_endpoint_policy, 0, offsetof(Service, exec_context)
-Service.USBFunctionDescriptors, config_parse_path, 0, offsetof(Service, usb_function_descriptors)
-Service.USBFunctionStrings, config_parse_path, 0, offsetof(Service, usb_function_strings)
-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.ListenUSBFunction, config_parse_socket_listen, SOCKET_USB_FUNCTION, 0
-Socket.SocketProtocol, config_parse_socket_protocol, 0, 0
-Socket.BindIPv6Only, config_parse_socket_bind, 0, 0,
-Socket.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.Writable, config_parse_bool, 0, offsetof(Socket, writable)
-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.FileDescriptorName, config_parse_fdname, 0, 0
-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)
-Automount.TimeoutIdleSec, config_parse_sec, 0, offsetof(Automount, timeout_idle_usec)
-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.RemainAfterElapse, config_parse_bool, 0, offsetof(Timer, remain_after_elapse)
-Timer.AccuracySec, config_parse_sec, 0, offsetof(Timer, accuracy_usec)
-Timer.RandomizedDelaySec, config_parse_sec, 0, offsetof(Timer, random_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 8804b3ac41..0000000000
--- a/src/core/load-fragment.c
+++ /dev/null
@@ -1,3939 +0,0 @@
-/***
- 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 <errno.h>
-#include <fcntl.h>
-#include <linux/fs.h>
-#include <linux/oom.h>
-#ifdef HAVE_SECCOMP
-#include <seccomp.h>
-#endif
-#include <sched.h>
-#include <string.h>
-#include <sys/resource.h>
-#include <sys/stat.h>
-
-#include "af-list.h"
-#include "alloc-util.h"
-#include "bus-error.h"
-#include "bus-internal.h"
-#include "bus-util.h"
-#include "cap-list.h"
-#include "capability-util.h"
-#include "cgroup.h"
-#include "conf-parser.h"
-#include "cpu-set-util.h"
-#include "env-util.h"
-#include "errno-list.h"
-#include "escape.h"
-#include "fd-util.h"
-#include "fs-util.h"
-#include "ioprio.h"
-#include "load-fragment.h"
-#include "log.h"
-#include "missing.h"
-#include "parse-util.h"
-#include "path-util.h"
-#include "process-util.h"
-#include "rlimit-util.h"
-#ifdef HAVE_SECCOMP
-#include "seccomp-util.h"
-#endif
-#include "securebits.h"
-#include "signal-util.h"
-#include "stat-util.h"
-#include "string-util.h"
-#include "strv.h"
-#include "unit-name.h"
-#include "unit-printf.h"
-#include "unit.h"
-#include "utf8.h"
-#include "web-util.h"
-
-int config_parse_warn_compat(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
- Disabled reason = ltype;
-
- switch(reason) {
- case DISABLED_CONFIGURATION:
- log_syntax(unit, LOG_DEBUG, filename, line, 0,
- "Support for option %s= has been disabled at compile time and it is ignored", lvalue);
- break;
- case DISABLED_LEGACY:
- log_syntax(unit, LOG_INFO, filename, line, 0,
- "Support for option %s= has been removed and it is ignored", lvalue);
- break;
- case DISABLED_EXPERIMENTAL:
- log_syntax(unit, LOG_INFO, filename, line, 0,
- "Support for option %s= has not yet been enabled and it is ignored", lvalue);
- break;
- };
-
- 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 *p;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- p = rvalue;
- for(;;) {
- _cleanup_free_ char *word = NULL, *k = NULL;
- int r;
-
- r = extract_first_word(&p, &word, NULL, EXTRACT_RETAIN_ESCAPE);
- if (r == 0)
- break;
- if (r == -ENOMEM)
- return log_oom();
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
- break;
- }
-
- r = unit_name_printf(u, word, &k);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
- 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: %m", k);
- }
-
- return 0;
-}
-
-int config_parse_obsolete_unit_deps(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- log_syntax(unit, LOG_WARNING, filename, line, 0,
- "Unit dependency type %s= is obsolete, replacing by %s=, please update your unit file", lvalue, unit_dependency_to_string(ltype));
-
- return config_parse_unit_deps(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, 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) {
-
- _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: %m", rvalue);
- return 0;
- }
-
- return config_parse_strv(unit, filename, line, section, section_line, lvalue, ltype, k, 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: %m", rvalue);
- 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: %m", t);
- return 0;
- }
-
- if (!utf8_is_valid(k)) {
- log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
- return 0;
- }
-
- if (!path_is_absolute(k)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Symlink path %s is not absolute, ignoring: %m", k);
- 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, 0, "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) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s, ignoring: %m", rvalue);
- return 0;
- }
-
- 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: %m", rvalue);
- return 0;
- }
-
- r = socket_address_parse_netlink(&p->address, k);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address value, ignoring: %s", rvalue);
- 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: %m", rvalue);
- return 0;
- }
-
- r = socket_address_parse_and_warn(&p->address, k);
- 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, 0, "Address family not supported, ignoring: %s", rvalue);
- return 0;
- }
- }
-
- p->fd = -1;
- p->auxiliary_fds = NULL;
- p->n_auxiliary_fds = 0;
- 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_protocol(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
- Socket *s;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- s = SOCKET(data);
-
- if (streq(rvalue, "udplite"))
- s->socket_protocol = IPPROTO_UDPLITE;
- else if (streq(rvalue, "sctp"))
- s->socket_protocol = IPPROTO_SCTP;
- else {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Socket protocol not supported, ignoring: %s", rvalue);
- return 0;
- }
-
- 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, r, "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, 0, "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, 0, "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;
- const char *p;
- bool semicolon;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(e);
-
- e += ltype;
- rvalue += strspn(rvalue, WHITESPACE);
-
- if (isempty(rvalue)) {
- /* An empty assignment resets the list */
- *e = exec_command_free_list(*e);
- return 0;
- }
-
- p = rvalue;
- do {
- _cleanup_free_ char *path = NULL, *firstword = NULL;
- bool separate_argv0 = false, ignore = false;
- _cleanup_free_ ExecCommand *nce = NULL;
- _cleanup_strv_free_ char **n = NULL;
- size_t nlen = 0, nbufsize = 0;
- char *f;
- int i;
-
- semicolon = false;
-
- r = extract_first_word_and_warn(&p, &firstword, WHITESPACE, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, unit, filename, line, rvalue);
- if (r <= 0)
- return 0;
-
- f = firstword;
- for (i = 0; i < 2; i++) {
- /* We accept an absolute path as first argument, or
- * alternatively an absolute prefixed with @ to allow
- * overriding of argv[0]. */
- if (*f == '-' && !ignore)
- ignore = true;
- else if (*f == '@' && !separate_argv0)
- separate_argv0 = true;
- else
- break;
- f ++;
- }
-
- if (isempty(f)) {
- /* First word is either "-" or "@" with no command. */
- log_syntax(unit, LOG_ERR, filename, line, 0, "Empty path in command line, ignoring: \"%s\"", rvalue);
- return 0;
- }
- if (!string_is_safe(f)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path contains special characters, ignoring: %s", rvalue);
- return 0;
- }
- if (!path_is_absolute(f)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path is not absolute, ignoring: %s", rvalue);
- return 0;
- }
- if (endswith(f, "/")) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Executable path specifies a directory, ignoring: %s", rvalue);
- return 0;
- }
-
- if (f == firstword) {
- path = firstword;
- firstword = NULL;
- } else {
- path = strdup(f);
- if (!path)
- return log_oom();
- }
-
- if (!separate_argv0) {
- if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
- return log_oom();
- f = strdup(path);
- if (!f)
- return log_oom();
- n[nlen++] = f;
- n[nlen] = NULL;
- }
-
- path_kill_slashes(path);
-
- while (!isempty(p)) {
- _cleanup_free_ char *word = NULL;
-
- /* Check explicitly for an unquoted semicolon as
- * command separator token. */
- if (p[0] == ';' && (!p[1] || strchr(WHITESPACE, p[1]))) {
- p ++;
- p += strspn(p, WHITESPACE);
- semicolon = true;
- break;
- }
-
- /* Check for \; explicitly, to not confuse it with \\;
- * or "\;" or "\\;" etc. extract_first_word would
- * return the same for all of those. */
- if (p[0] == '\\' && p[1] == ';' && (!p[2] || strchr(WHITESPACE, p[2]))) {
- p += 2;
- p += strspn(p, WHITESPACE);
- if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
- return log_oom();
- f = strdup(";");
- if (!f)
- return log_oom();
- n[nlen++] = f;
- n[nlen] = NULL;
- continue;
- }
-
- r = extract_first_word_and_warn(&p, &word, WHITESPACE, EXTRACT_QUOTES|EXTRACT_CUNESCAPE, unit, filename, line, rvalue);
- if (r == 0)
- break;
- else if (r < 0)
- return 0;
-
- if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
- return log_oom();
- n[nlen++] = word;
- n[nlen] = NULL;
- word = NULL;
- }
-
- if (!n || !n[0]) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Empty executable name or zeroeth argument, ignoring: %s", rvalue);
- return 0;
- }
-
- nce = new0(ExecCommand, 1);
- if (!nce)
- return log_oom();
-
- nce->argv = n;
- nce->path = path;
- nce->ignore = ignore;
-
- exec_command_append_list(e, nce);
-
- /* Do not _cleanup_free_ these. */
- n = NULL;
- path = NULL;
- nce = NULL;
-
- rvalue = p;
- } while (semicolon);
-
- return 0;
-}
-
-DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
-DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
-
-int config_parse_socket_bindtodevice(const char* unit,
- const char *filename,
- 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, 0, "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, 0, "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, 0, "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;
- _cleanup_cpu_free_ cpu_set_t *cpuset = NULL;
- int ncpus;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- ncpus = parse_cpu_set_and_warn(rvalue, &cpuset, unit, filename, line, lvalue);
- if (ncpus < 0)
- return ncpus;
-
- if (c->cpuset)
- CPU_FREE(c->cpuset);
-
- if (ncpus == 0)
- /* An empty assignment resets the CPU list */
- c->cpuset = NULL;
- else {
- c->cpuset = cpuset;
- cpuset = NULL;
- }
- c->cpuset_ncpus = ncpus;
-
- 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, 0, "Failed to parse secure bits, ignoring: %s", rvalue);
- return 0;
- }
- }
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, garbage at the end, ignoring.");
-
- return 0;
-}
-
-int config_parse_capability_set(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- uint64_t *capability_set = data;
- uint64_t sum = 0, initial = 0;
- bool invert = false;
- const char *p;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (rvalue[0] == '~') {
- invert = true;
- rvalue++;
- }
-
- if (strcmp(lvalue, "CapabilityBoundingSet") == 0)
- initial = CAP_ALL; /* initialized to all bits on */
- /* else "AmbientCapabilities" initialized to all bits off */
-
- p = rvalue;
- for (;;) {
- _cleanup_free_ char *word = NULL;
- int cap, r;
-
- r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
- if (r == 0)
- break;
- if (r == -ENOMEM)
- return log_oom();
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse word, ignoring: %s", rvalue);
- break;
- }
-
- cap = capability_from_name(word);
- if (cap < 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding/ambient set, ignoring: %s", word);
- continue;
- }
-
- sum |= ((uint64_t) UINT64_C(1)) << (uint64_t) cap;
- }
-
- sum = invert ? ~sum : sum;
-
- if (sum == 0 || *capability_set == initial)
- /* "" or uninitialized data -> replace */
- *capability_set = sum;
- else
- /* previous data -> merge */
- *capability_set |= 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, d = {};
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- r = rlimit_parse(ltype, rvalue, &d);
- if (r == -EILSEQ) {
- log_syntax(unit, LOG_WARNING, filename, line, r, "Soft resource limit chosen higher than hard limit, ignoring: %s", rvalue);
- return 0;
- }
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
- return 0;
- }
-
- if (rl[ltype])
- *rl[ltype] = d;
- else {
- rl[ltype] = newdup(struct rlimit, &d, 1);
- if (!rl[ltype])
- return log_oom();
- }
-
- return 0;
-}
-
-#ifdef HAVE_SYSV_COMPAT
-int config_parse_sysv_priority(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- int *priority = data;
- int i, r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- r = safe_atoi(rvalue, &i);
- if (r < 0 || i < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse SysV start priority, ignoring: %s", rvalue);
- return 0;
- }
-
- *priority = (int) i;
- return 0;
-}
-#endif
-
-DEFINE_CONFIG_PARSE_ENUM(config_parse_exec_utmp_mode, exec_utmp_mode, ExecUtmpMode, "Failed to parse utmp mode");
-DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
-
-int config_parse_exec_mount_flags(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
-
- unsigned long flags = 0;
- ExecContext *c = data;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (streq(rvalue, "shared"))
- flags = MS_SHARED;
- else if (streq(rvalue, "slave"))
- flags = MS_SLAVE;
- else if (streq(rvalue, "private"))
- flags = MS_PRIVATE;
- else {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse mount flag %s, ignoring.", rvalue);
- return 0;
- }
-
- 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)) {
- c->selinux_context = mfree(c->selinux_context);
- 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: %m");
- 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)) {
- c->apparmor_profile = mfree(c->apparmor_profile);
- 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: %m");
- 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)) {
- c->smack_process_label = mfree(c->smack_process_label);
- 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: %m");
- 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, 0, "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, 0, "Failed to parse calendar specification, ignoring: %s", rvalue);
- return 0;
- }
- } else {
- if (parse_sec(rvalue, &u) < 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "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, 0, "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: %m");
- return 0;
- }
-
- type = unit_name_to_type(p);
- if (type < 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Unit type not valid, ignoring: %s", rvalue);
- return 0;
- }
-
- if (type == u->type) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Trigger cannot be of same type, ignoring: %s", rvalue);
- return 0;
- }
-
- r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_TRIGGERS, p, NULL, true);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add trigger on %s, ignoring: %m", p);
- 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, 0, "Failed to parse path type, ignoring: %s", lvalue);
- return 0;
- }
-
- r = unit_full_printf(UNIT(p), rvalue, &k);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers on %s. Ignoring.", rvalue);
- return 0;
- }
-
- if (!path_is_absolute(k)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "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_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_free_ char *p = NULL;
- Socket *s = data;
- Unit *x;
- int r;
-
- 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, 0, "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_fdname(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- _cleanup_free_ char *p = NULL;
- Socket *s = data;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (isempty(rvalue)) {
- s->fdname = mfree(s->fdname);
- return 0;
- }
-
- 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 (!fdname_is_valid(p)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name, ignoring: %s", p);
- return 0;
- }
-
- free(s->fdname);
- s->fdname = p;
- p = NULL;
-
- 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 *p;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- p = rvalue;
- for(;;) {
- _cleanup_free_ char *word = NULL, *k = NULL;
-
- r = extract_first_word(&p, &word, NULL, 0);
- if (r == 0)
- break;
- if (r == -ENOMEM)
- return log_oom();
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage in sockets, ignoring: %s", rvalue);
- break;
- }
-
- r = unit_name_printf(UNIT(s), word, &k);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
- continue;
- }
-
- if (!endswith(k, ".socket")) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "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);
- }
-
- 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, 0, "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;
- usec_t usec;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(s);
-
- /* This is called for three cases: TimeoutSec=, TimeoutStopSec= and TimeoutStartSec=. */
-
- r = parse_sec(rvalue, &usec);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue);
- return 0;
- }
-
- /* Traditionally, these options accepted 0 to disable the timeouts. However, a timeout of 0 suggests it happens
- * immediately, hence fix this to become USEC_INFINITY instead. This is in-line with how we internally handle
- * all other timeouts. */
- if (usec <= 0)
- usec = USEC_INFINITY;
-
- if (!streq(lvalue, "TimeoutStopSec")) {
- s->start_timeout_defined = true;
- s->timeout_start_usec = usec;
- }
-
- if (!streq(lvalue, "TimeoutStartSec"))
- s->timeout_stop_usec = usec;
-
- return 0;
-}
-
-int config_parse_sec_fix_0(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- usec_t *usec = data;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(usec);
-
- /* This is pretty much like config_parse_sec(), except that this treats a time of 0 as infinity, for
- * compatibility with older versions of systemd where 0 instead of infinity was used as indicator to turn off a
- * timeout. */
-
- r = parse_sec(rvalue, usec);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse %s= parameter, ignoring: %s", lvalue, rvalue);
- return 0;
- }
-
- if (*usec <= 0)
- *usec = USEC_INFINITY;
-
- 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_(sd_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, 0, "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, 0, "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, 0, "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, 0, "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, 0, "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 log_error_errno(r, "Failed to create bus endpoint object: %m");
- }
-
- return bus_endpoint_add_policy(c->bus_endpoint, name, access);
-}
-
-int config_parse_working_directory(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- ExecContext *c = data;
- Unit *u = userdata;
- bool missing_ok;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(c);
- assert(u);
-
- if (rvalue[0] == '-') {
- missing_ok = true;
- rvalue++;
- } else
- missing_ok = false;
-
- if (streq(rvalue, "~")) {
- c->working_directory_home = true;
- c->working_directory = mfree(c->working_directory);
- } else {
- _cleanup_free_ char *k = NULL;
-
- r = unit_full_printf(u, rvalue, &k);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve unit specifiers in working directory path '%s', ignoring: %m", rvalue);
- return 0;
- }
-
- path_kill_slashes(k);
-
- if (!utf8_is_valid(k)) {
- log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
- return 0;
- }
-
- if (!path_is_absolute(k)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Working directory path '%s' is not absolute, ignoring.", rvalue);
- return 0;
- }
-
- free(c->working_directory);
- c->working_directory = k;
- k = NULL;
-
- c->working_directory_home = false;
- }
-
- c->working_directory_missing_ok = missing_ok;
- return 0;
-}
-
-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;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (isempty(rvalue)) {
- /* Empty assignment frees the list */
- *env = strv_free(*env);
- 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);
- return 0;
- }
-
- if (!path_is_absolute(n[0] == '-' ? n + 1 : n)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Path '%s' is not absolute, ignoring.", n);
- return 0;
- }
-
- r = strv_extend(env, n);
- 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 */
- *env = strv_free(*env);
- 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);
- return 0;
- }
- }
-
- if (!k) {
- k = strdup(rvalue);
- if (!k)
- return log_oom();
- }
-
- FOREACH_WORD_QUOTED(word, l, k, state) {
- _cleanup_free_ char *n = NULL;
- char **x;
-
- r = cunescape_length(word, l, 0, &n);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Couldn't unescape assignment, ignoring: %s", rvalue);
- continue;
- }
-
- if (!env_assignment_is_valid(n)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "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, 0, "Trailing garbage, ignoring.");
-
- return 0;
-}
-
-int config_parse_pass_environ(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- const char *whole_rvalue = rvalue;
- char*** passenv = data;
- _cleanup_strv_free_ char **n = NULL;
- size_t nlen = 0, nbufsize = 0;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (isempty(rvalue)) {
- /* Empty assignment resets the list */
- *passenv = strv_free(*passenv);
- return 0;
- }
-
- for (;;) {
- _cleanup_free_ char *word = NULL;
-
- r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES);
- if (r == 0)
- break;
- if (r == -ENOMEM)
- return log_oom();
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r,
- "Trailing garbage in %s, ignoring: %s", lvalue, whole_rvalue);
- break;
- }
-
- if (!env_name_is_valid(word)) {
- log_syntax(unit, LOG_ERR, filename, line, EINVAL,
- "Invalid environment name for %s, ignoring: %s", lvalue, word);
- continue;
- }
-
- if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
- return log_oom();
- n[nlen++] = word;
- n[nlen] = NULL;
- word = NULL;
- }
-
- if (n) {
- r = strv_extend_strv(passenv, n, true);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-int config_parse_ip_tos(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- int *ip_tos = data, x;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- x = ip_tos_from_string(rvalue);
- if (x < 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse IP TOS value, ignoring: %s", rvalue);
- return 0;
- }
-
- *ip_tos = x;
- return 0;
-}
-
-int config_parse_unit_condition_path(
- const char *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, 0, "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_syntax_invalid_utf8(unit, LOG_ERR, filename, line, 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, 0, "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 */
- u->documentation = strv_free(u->documentation);
- 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, 0, "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 */
- c->syscall_filter = set_free(c->syscall_filter);
- 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 == 0)
- 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, 0, "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 == 0)
- 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, 0, "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 == MANAGER_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)) {
- *archs = set_free(*archs);
- 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, 0, "Failed to parse system call architecture, ignoring: %s", t);
- continue;
- }
-
- r = set_put(*archs, UINT32_TO_PTR(a + 1));
- if (r == 0)
- continue;
- if (r < 0)
- return log_oom();
- }
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, 0, "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, 0, "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 */
- c->address_families = set_free(c->address_families);
- 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, 0, "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 == 0)
- 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, 0, "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 = NULL;
- 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);
- return 0;
- }
-
- 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;
- }
-
- r = unit_set_slice(u, slice);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to assign slice %s to unit %s. Ignoring.", slice->id, u->id);
- return 0;
- }
-
- return 0;
-}
-
-DEFINE_CONFIG_PARSE_ENUM(config_parse_device_policy, cgroup_device_policy, CGroupDevicePolicy, "Failed to parse device policy");
-
-int config_parse_cpu_shares(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- uint64_t *shares = data;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- r = cg_cpu_shares_parse(rvalue, shares);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "CPU shares '%s' invalid. Ignoring.", rvalue);
- return 0;
- }
-
- 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, 0, "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, 0, "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;
- uint64_t bytes;
- int r;
-
- if (isempty(rvalue) || streq(rvalue, "infinity")) {
- c->memory_limit = (uint64_t) -1;
- return 0;
- }
-
- r = parse_size(rvalue, 1024, &bytes);
- if (r < 0 || bytes < 1) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue);
- return 0;
- }
-
- c->memory_limit = bytes;
- return 0;
-}
-
-int config_parse_tasks_max(
- const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- uint64_t *tasks_max = data, u;
- int r;
-
- if (isempty(rvalue) || streq(rvalue, "infinity")) {
- *tasks_max = (uint64_t) -1;
- return 0;
- }
-
- r = safe_atou64(rvalue, &u);
- if (r < 0 || u < 1) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Maximum tasks value '%s' invalid. Ignoring.", rvalue);
- return 0;
- }
-
- *tasks_max = u;
- 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, 0, "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, 0, "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) {
-
- uint64_t *weight = data;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- r = cg_blkio_weight_parse(rvalue, weight);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", rvalue);
- return 0;
- }
-
- return 0;
-}
-
-int config_parse_blockio_device_weight(
- const char *unit,
- const char *filename,
- 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;
- const char *weight;
- uint64_t u;
- 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;
- weight += strspn(weight, WHITESPACE);
-
- if (isempty(weight)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Expected block device and device weight. Ignoring.");
- return 0;
- }
-
- path = strndup(rvalue, n);
- if (!path)
- return log_oom();
-
- if (!path_startswith(path, "/dev")) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid device node path '%s'. Ignoring.", path);
- return 0;
- }
-
- r = cg_blkio_weight_parse(weight, &u);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Block IO weight '%s' invalid. Ignoring.", weight);
- return 0;
- }
-
- assert(u != CGROUP_BLKIO_WEIGHT_INVALID);
-
- w = new0(CGroupBlockIODeviceWeight, 1);
- if (!w)
- return log_oom();
-
- w->path = path;
- path = NULL;
-
- w->weight = u;
-
- 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;
- uint64_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, 0, "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, 0, "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, r, "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 = 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, r, "Failed to parse boolean, ignoring: %s", rvalue);
- return 0;
- }
-
- *m = r ? JOB_ISOLATE : JOB_REPLACE;
- 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;
- Unit *u = userdata;
- 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 */
- *rt = strv_free(*rt);
- return 0;
- }
-
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *t = NULL, *n = NULL;
-
- t = strndup(word, l);
- if (!t)
- return log_oom();
-
- r = unit_name_printf(u, t, &n);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
- continue;
- }
-
- if (!filename_is_valid(n)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "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, 0, "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, 0, "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, 0, "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, 0, "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 *prev;
- const char *cur;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (isempty(rvalue)) {
- /* Empty assignment resets the list */
- *sv = strv_free(*sv);
- return 0;
- }
-
- prev = cur = rvalue;
- for (;;) {
- _cleanup_free_ char *word = NULL;
- int offset;
-
- r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES);
- if (r == 0)
- break;
- if (r == -ENOMEM)
- return log_oom();
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage, ignoring: %s", prev);
- return 0;
- }
-
- if (!utf8_is_valid(word)) {
- log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
- prev = cur;
- continue;
- }
-
- offset = word[0] == '-';
- if (!path_is_absolute(word + offset)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", word);
- prev = cur;
- continue;
- }
-
- path_kill_slashes(word + offset);
-
- r = strv_push(sv, word);
- if (r < 0)
- return log_oom();
-
- prev = cur;
- word = NULL;
- }
-
- 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, 0, "Failed to parse protect home value, ignoring: %s", rvalue);
- return 0;
- }
-
- c->protect_home = h;
- }
-
- return 0;
-}
-
-int config_parse_protect_system(
- const char* unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- ExecContext *c = data;
- 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, 0, "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, UNIT_NAME_ANY)) {
-
- 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) {
- filename = mfree(filename);
- 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) {
- filename = mfree(filename);
- 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);
-
- if (u->transient) {
- u->load_state = UNIT_LOADED;
- return 0;
- }
-
- /* 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. */
- u->fragment_path = mfree(u->fragment_path);
- }
-
- /* Look for a template */
- if (u->load_state == UNIT_STUB && u->instance) {
- _cleanup_free_ char *k = NULL;
-
- r = unit_name_template(u->id, &k);
- if (r < 0)
- return r;
-
- 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;
-
- r = unit_name_template(t, &z);
- if (r < 0)
- return r;
-
- 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[] = {
-#if !defined(HAVE_SYSV_COMPAT) || !defined(HAVE_SECCOMP) || !defined(HAVE_PAM) || !defined(HAVE_SELINUX) || !defined(HAVE_SMACK) || !defined(HAVE_APPARMOR)
- { config_parse_warn_compat, "NOTSUPPORTED" },
-#endif
- { config_parse_int, "INTEGER" },
- { config_parse_unsigned, "UNSIGNED" },
- { config_parse_iec_size, "SIZE" },
- { config_parse_iec_uint64, "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_capability_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" },
-#ifdef HAVE_SYSV_COMPAT
- { config_parse_sysv_priority, "SYSVPRIORITY" },
-#endif
- { config_parse_kill_mode, "KILLMODE" },
- { config_parse_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 5fb5910919..0000000000
--- a/src/core/load-fragment.h
+++ /dev/null
@@ -1,122 +0,0 @@
-#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_obsolete_unit_deps(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_string_printf(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_strv_printf(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_path_printf(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_path_strv_printf(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_documentation(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_socket_listen(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_socket_protocol(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_socket_bind(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_nice(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_oom_score_adjust(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_service_timeout(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_service_type(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_service_restart(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_socket_bindtodevice(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_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_capability_set(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_sysv_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_kill_signal(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_mount_flags(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_timer(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_trigger_unit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_path_spec(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_socket_service(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_service_sockets(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_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_pass_environ(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_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_tasks_max(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_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_netclass(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_job_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_job_mode_isolate(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_selinux_context(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_apparmor_profile(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_smack_process_label(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_address_families(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_runtime_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);
-int config_parse_exec_utmp_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_working_directory(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_fdname(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_sec_fix_0(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-
-/* 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 ccf61d29fb..0000000000
--- a/src/core/locale-setup.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <stdlib.h>
-
-#include "env-util.h"
-#include "fileio.h"
-#include "locale-setup.h"
-#include "locale-util.h"
-#include "string-util.h"
-#include "strv.h"
-#include "util.h"
-#include "virt.h"
-
-int locale_setup(char ***environment) {
- char **add;
- char *variables[_VARIABLE_LC_MAX] = {};
- int r = 0, i;
-
- if (detect_container() <= 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 3b97497afe..0000000000
--- a/src/core/locale-setup.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#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 04062a7910..0000000000
--- a/src/core/loopback-setup.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/***
- 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-netlink.h"
-
-#include "loopback-setup.h"
-#include "missing.h"
-#include "netlink-util.h"
-
-static int start_loopback(sd_netlink *rtnl) {
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_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_netlink_call(rtnl, req, 0, NULL);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-static bool check_loopback(sd_netlink *rtnl) {
- _cleanup_(sd_netlink_message_unrefp) sd_netlink_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_netlink_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_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
- int r;
-
- r = sd_netlink_open(&rtnl);
- 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 e7547b8a26..0000000000
--- a/src/core/loopback-setup.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#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 9e6b3d3292..0000000000
--- a/src/core/machine-id-setup.c
+++ /dev/null
@@ -1,375 +0,0 @@
-/***
- 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 <sched.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/mount.h>
-#include <unistd.h>
-
-#include "sd-id128.h"
-
-#include "alloc-util.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "fs-util.h"
-#include "hexdecoct.h"
-#include "io-util.h"
-#include "log.h"
-#include "machine-id-setup.h"
-#include "macro.h"
-#include "mkdir.h"
-#include "mount-util.h"
-#include "path-util.h"
-#include "process-util.h"
-#include "stat-util.h"
-#include "string-util.h"
-#include "umask-util.h"
-#include "util.h"
-#include "virt.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 *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 */
-
- if (detect_container() > 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 (detect_vm() == VIRTUALIZATION_KVM) {
-
- /* 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 */
-
- 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, sd_id128_t machine_id) {
- 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;
- }
- }
-
- /* A machine id argument overrides all other machined-ids */
- if (!sd_id128_is_null(machine_id)) {
- sd_id128_to_string(machine_id, id);
- id[32] = '\n';
- id[33] = 0;
- } else {
- 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, WRITE_STRING_FILE_CREATE);
- }
- 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, 0);
- 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 = fd_is_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, 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, -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 a7e7678ed9..0000000000
--- a/src/core/machine-id-setup.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-int machine_id_commit(const char *root);
-int machine_id_setup(const char *root, sd_id128_t machine_id);
diff --git a/src/core/macros.systemd.in b/src/core/macros.systemd.in
deleted file mode 100644
index 2cace3d3ba..0000000000
--- a/src/core/macros.systemd.in
+++ /dev/null
@@ -1,105 +0,0 @@
-# -*- Mode: rpm-spec; 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/>.
-
-# 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 --no-reload preset %{?*} >/dev/null 2>&1 || : \
-fi \
-%{nil}
-
-%systemd_user_post() %{expand:%systemd_post \\--user \\--global %%{?*}}
-
-%systemd_preun() \
-if [ $1 -eq 0 ] ; then \
- # Package removal, not upgrade \
- systemctl --no-reload disable --now %{?*} > /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() %{nil}
-
-%systemd_user_postun() %{nil}
-
-%systemd_postun_with_restart() \
-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 5346392d73..0000000000
--- a/src/core/main.c
+++ /dev/null
@@ -1,2142 +0,0 @@
-/***
- 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 <getopt.h>
-#include <signal.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/mount.h>
-#include <sys/prctl.h>
-#include <sys/reboot.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#ifdef HAVE_SECCOMP
-#include <seccomp.h>
-#endif
-#ifdef HAVE_VALGRIND_VALGRIND_H
-#include <valgrind/valgrind.h>
-#endif
-
-#include "sd-bus.h"
-#include "sd-daemon.h"
-
-#include "alloc-util.h"
-#include "architecture.h"
-#include "build.h"
-#include "bus-error.h"
-#include "bus-util.h"
-#include "capability-util.h"
-#include "clock-util.h"
-#include "conf-parser.h"
-#include "cpu-set-util.h"
-#include "dbus-manager.h"
-#include "def.h"
-#include "env-util.h"
-#include "fd-util.h"
-#include "fdset.h"
-#include "fileio.h"
-#include "formats-util.h"
-#include "fs-util.h"
-#include "hostname-setup.h"
-#include "ima-setup.h"
-#include "killall.h"
-#include "kmod-setup.h"
-#include "load-fragment.h"
-#include "log.h"
-#include "loopback-setup.h"
-#include "machine-id-setup.h"
-#include "manager.h"
-#include "missing.h"
-#include "mount-setup.h"
-#include "pager.h"
-#include "parse-util.h"
-#include "proc-cmdline.h"
-#include "process-util.h"
-#include "rlimit-util.h"
-#include "selinux-setup.h"
-#include "selinux-util.h"
-#include "signal-util.h"
-#include "smack-setup.h"
-#include "special.h"
-#include "stat-util.h"
-#include "stdio-util.h"
-#include "strv.h"
-#include "switch-root.h"
-#include "terminal-util.h"
-#include "user-util.h"
-#include "virt.h"
-#include "watchdog.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 ManagerRunningAs arg_running_as = _MANAGER_RUNNING_AS_INVALID;
-static bool arg_dump_core = true;
-static int arg_crash_chvt = -1;
-static bool arg_crash_shell = false;
-static bool arg_crash_reboot = false;
-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 = CAP_ALL;
-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 bool arg_default_tasks_accounting = true;
-static uint64_t arg_default_tasks_max = UINT64_C(512);
-static sd_id128_t arg_machine_id = {};
-
-static void pager_open_if_enabled(void) {
-
- if (arg_no_pager <= 0)
- return;
-
- pager_open(false);
-}
-
-noreturn static void freeze_or_reboot(void) {
-
- if (arg_crash_reboot) {
- log_notice("Rebooting in 10s...");
- (void) sleep(10);
-
- log_notice("Rebooting now...");
- (void) reboot(RB_AUTOBOOT);
- log_emergency_errno(errno, "Failed to reboot: %m");
- }
-
- log_emergency("Freezing execution.");
- freeze();
-}
-
-noreturn static void crash(int sig) {
- struct sigaction sa;
- pid_t pid;
-
- if (getpid() != 1)
- /* Pass this on immediately, if this is not PID 1 */
- (void) raise(sig);
- else if (!arg_dump_core)
- log_emergency("Caught <%s>, not dumping core.", signal_to_string(sig));
- else {
- sa = (struct sigaction) {
- .sa_handler = nop_signal_handler,
- .sa_flags = SA_NOCLDSTOP|SA_RESTART,
- };
-
- /* We want to wait for the core process, hence let's enable SIGCHLD */
- (void) 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) {
- /* Enable default signal handler for core dump */
-
- sa = (struct sigaction) {
- .sa_handler = SIG_DFL,
- };
- (void) sigaction(sig, &sa, NULL);
-
- /* Don't limit the coredump size */
- (void) setrlimit(RLIMIT_CORE, &RLIMIT_MAKE_CONST(RLIM_INFINITY));
-
- /* Just to be sure... */
- (void) chdir("/");
-
- /* Raise the signal again */
- pid = raw_getpid();
- (void) kill(pid, sig); /* raise() would kill the parent */
-
- assert_not_reached("We shouldn't be here...");
- _exit(EXIT_FAILURE);
- } 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 >= 0)
- (void) chvt(arg_crash_chvt);
-
- sa = (struct sigaction) {
- .sa_handler = SIG_IGN,
- .sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART,
- };
-
- /* Let the kernel reap children for us */
- (void) sigaction(SIGCHLD, &sa, NULL);
-
- if (arg_crash_shell) {
- log_notice("Executing crash shell in 10s...");
- (void) sleep(10);
-
- pid = raw_clone(SIGCHLD, NULL);
- if (pid < 0)
- log_emergency_errno(errno, "Failed to fork off crash shell: %m");
- else if (pid == 0) {
- (void) setsid();
- (void) make_console_stdio();
- (void) execle("/bin/sh", "/bin/sh", NULL, environ);
-
- log_emergency_errno(errno, "execle() failed: %m");
- _exit(EXIT_FAILURE);
- } else {
- log_info("Spawned crash shell as PID "PID_FMT".", pid);
- (void) wait_for_terminate(pid, NULL);
- }
- }
-
- freeze_or_reboot();
-}
-
-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 parse_crash_chvt(const char *value) {
- int b;
-
- if (safe_atoi(value, &arg_crash_chvt) >= 0)
- return 0;
-
- b = parse_boolean(value);
- if (b < 0)
- return b;
-
- if (b > 0)
- arg_crash_chvt = 0; /* switch to where kmsg goes */
- else
- arg_crash_chvt = -1; /* turn off switching */
-
- return 0;
-}
-
-static int set_machine_id(const char *m) {
-
- if (sd_id128_from_string(m, &arg_machine_id) < 0)
- return -EINVAL;
-
- if (sd_id128_is_null(arg_machine_id))
- return -EINVAL;
-
- return 0;
-}
-
-static int parse_proc_cmdline_item(const char *key, const char *value) {
-
- int r;
-
- assert(key);
-
- if (streq(key, "systemd.unit") && value) {
-
- if (!in_initrd())
- return free_and_strdup(&arg_default_unit, value);
-
- } else if (streq(key, "rd.systemd.unit") && value) {
-
- if (in_initrd())
- return free_and_strdup(&arg_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_chvt") && value) {
-
- if (parse_crash_chvt(value) < 0)
- log_warning("Failed to parse crash chvt switch %s. Ignoring.", value);
-
- } 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_reboot") && value) {
-
- r = parse_boolean(value);
- if (r < 0)
- log_warning("Failed to parse crash reboot switch %s. Ignoring.", value);
- else
- arg_crash_reboot = 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, "systemd.machine_id") && value) {
-
- r = set_machine_id(value);
- if (r < 0)
- log_warning("MachineID '%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() > 0)
- log_set_target(LOG_TARGET_CONSOLE);
-
- } else if (!in_initrd() && !value) {
- const char *target;
-
- /* SysV compatibility */
- target = runlevel_to_target(key);
- if (target)
- return free_and_strdup(&arg_default_unit, target);
- }
-
- 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': %m", \
- rvalue); \
- \
- 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) {
-
- _cleanup_cpu_free_ cpu_set_t *c = NULL;
- int ncpus;
-
- ncpus = parse_cpu_set_and_warn(rvalue, &c, unit, filename, line, lvalue);
- if (ncpus < 0)
- return ncpus;
-
- if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0)
- log_warning("Failed to set CPU affinity: %m");
-
- 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 int config_parse_crash_chvt(
- const char* 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 = parse_crash_chvt(rvalue);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse CrashChangeVT= setting, ignoring: %s", rvalue);
- return 0;
- }
-
- return 0;
-}
-
-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) {
-
- const char *whole_rvalue = rvalue;
- unsigned n = 0;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- arg_join_controllers = strv_free_free(arg_join_controllers);
-
- for (;;) {
- _cleanup_free_ char *word = NULL;
- char **l;
- int r;
-
- r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES);
- if (r < 0) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Invalid value for %s: %s", lvalue, whole_rvalue);
- return r;
- }
- if (r == 0)
- break;
-
- l = strv_split(word, ",");
- if (!l)
- return log_oom();
- 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, false) < 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(rvalue))
- log_syntax(unit, LOG_ERR, filename, line, 0, "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", "CrashChVT", /* legacy */ config_parse_crash_chvt, 0, NULL },
- { "Manager", "CrashChangeVT", config_parse_crash_chvt, 0, NULL },
- { "Manager", "CrashShell", config_parse_bool, 0, &arg_crash_shell },
- { "Manager", "CrashReboot", config_parse_bool, 0, &arg_crash_reboot },
- { "Manager", "ShowStatus", config_parse_show_status, 0, &arg_show_status },
- { "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_capability_set, 0, &arg_capability_bounding_set },
-#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, RLIMIT_CPU, arg_default_rlimit },
- { "Manager", "DefaultLimitFSIZE", config_parse_limit, RLIMIT_FSIZE, arg_default_rlimit },
- { "Manager", "DefaultLimitDATA", config_parse_limit, RLIMIT_DATA, arg_default_rlimit },
- { "Manager", "DefaultLimitSTACK", config_parse_limit, RLIMIT_STACK, arg_default_rlimit },
- { "Manager", "DefaultLimitCORE", config_parse_limit, RLIMIT_CORE, arg_default_rlimit },
- { "Manager", "DefaultLimitRSS", config_parse_limit, RLIMIT_RSS, arg_default_rlimit },
- { "Manager", "DefaultLimitNOFILE", config_parse_limit, RLIMIT_NOFILE, arg_default_rlimit },
- { "Manager", "DefaultLimitAS", config_parse_limit, RLIMIT_AS, arg_default_rlimit },
- { "Manager", "DefaultLimitNPROC", config_parse_limit, RLIMIT_NPROC, arg_default_rlimit },
- { "Manager", "DefaultLimitMEMLOCK", config_parse_limit, RLIMIT_MEMLOCK, arg_default_rlimit },
- { "Manager", "DefaultLimitLOCKS", config_parse_limit, RLIMIT_LOCKS, arg_default_rlimit },
- { "Manager", "DefaultLimitSIGPENDING", config_parse_limit, RLIMIT_SIGPENDING, arg_default_rlimit },
- { "Manager", "DefaultLimitMSGQUEUE", config_parse_limit, RLIMIT_MSGQUEUE, arg_default_rlimit },
- { "Manager", "DefaultLimitNICE", config_parse_limit, RLIMIT_NICE, arg_default_rlimit },
- { "Manager", "DefaultLimitRTPRIO", config_parse_limit, RLIMIT_RTPRIO, arg_default_rlimit },
- { "Manager", "DefaultLimitRTTIME", config_parse_limit, RLIMIT_RTTIME, arg_default_rlimit },
- { "Manager", "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 },
- { "Manager", "DefaultTasksAccounting", config_parse_bool, 0, &arg_default_tasks_accounting },
- { "Manager", "DefaultTasksMax", config_parse_tasks_max, 0, &arg_default_tasks_max },
- {}
- };
-
- const char *fn, *conf_dirs_nulstr;
-
- fn = arg_running_as == MANAGER_SYSTEM ?
- PKGSYSCONFDIR "/system.conf" :
- PKGSYSCONFDIR "/user.conf";
-
- conf_dirs_nulstr = arg_running_as == MANAGER_SYSTEM ?
- CONF_PATHS_NULSTR("systemd/system.conf.d") :
- CONF_PATHS_NULSTR("systemd/user.conf.d");
-
- config_parse_many(fn, conf_dirs_nulstr, "Manager\0", config_item_table_lookup, items, false, NULL);
-
- /* Traditionally "0" was used to turn off the default unit timeouts. Fix this up so that we used USEC_INFINITY
- * like everywhere else. */
- if (arg_default_timeout_start_usec <= 0)
- arg_default_timeout_start_usec = USEC_INFINITY;
- if (arg_default_timeout_stop_usec <= 0)
- arg_default_timeout_stop_usec = USEC_INFINITY;
-
- return 0;
-}
-
-static void manager_set_defaults(Manager *m) {
-
- assert(m);
-
- 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_timeout_start_usec = arg_default_timeout_start_usec;
- m->default_timeout_stop_usec = arg_default_timeout_stop_usec;
- m->default_restart_usec = arg_default_restart_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->default_tasks_accounting = arg_default_tasks_accounting;
- m->default_tasks_max = arg_default_tasks_max;
-
- manager_set_default_rlimits(m, arg_default_rlimit);
- manager_environment_add(m, NULL, arg_default_environment);
-}
-
-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_CHVT,
- ARG_CRASH_SHELL,
- ARG_CRASH_REBOOT,
- ARG_CONFIRM_SPAWN,
- ARG_SHOW_STATUS,
- ARG_DESERIALIZE,
- ARG_SWITCHED_ROOT,
- ARG_DEFAULT_STD_OUTPUT,
- ARG_DEFAULT_STD_ERROR,
- ARG_MACHINE_ID
- };
-
- 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-chvt", required_argument, NULL, ARG_CRASH_CHVT },
- { "crash-shell", optional_argument, NULL, ARG_CRASH_SHELL },
- { "crash-reboot", optional_argument, NULL, ARG_CRASH_REBOOT },
- { "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, },
- { "machine-id", required_argument, NULL, ARG_MACHINE_ID },
- {}
- };
-
- 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 = free_and_strdup(&arg_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 = MANAGER_SYSTEM;
- break;
-
- case ARG_USER:
- arg_running_as = MANAGER_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:
- if (!optarg)
- arg_dump_core = true;
- else {
- r = parse_boolean(optarg);
- if (r < 0)
- return log_error_errno(r, "Failed to parse dump core boolean: %s", optarg);
- arg_dump_core = r;
- }
- break;
-
- case ARG_CRASH_CHVT:
- r = parse_crash_chvt(optarg);
- if (r < 0)
- return log_error_errno(r, "Failed to parse crash virtual terminal index: %s", optarg);
- break;
-
- case ARG_CRASH_SHELL:
- if (!optarg)
- arg_crash_shell = true;
- else {
- r = parse_boolean(optarg);
- if (r < 0)
- return log_error_errno(r, "Failed to parse crash shell boolean: %s", optarg);
- arg_crash_shell = r;
- }
- break;
-
- case ARG_CRASH_REBOOT:
- if (!optarg)
- arg_crash_reboot = true;
- else {
- r = parse_boolean(optarg);
- if (r < 0)
- return log_error_errno(r, "Failed to parse crash shell boolean: %s", optarg);
- arg_crash_reboot = 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 -EINVAL;
- }
-
- (void) fd_cloexec(fd, true);
-
- f = fdopen(fd, "r");
- if (!f)
- return log_error_errno(errno, "Failed to open serialization fd: %m");
-
- safe_fclose(arg_serialization);
- arg_serialization = f;
-
- break;
- }
-
- case ARG_SWITCHED_ROOT:
- arg_switched_root = true;
- break;
-
- case ARG_MACHINE_ID:
- r = set_machine_id(optarg);
- if (r < 0) {
- log_error("MachineID '%s' is not valid.", optarg);
- return r;
- }
- 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[=BOOL] Dump core on crash\n"
- " --crash-vt=NR Change to specified VT on crash\n"
- " --crash-reboot[=BOOL] Reboot on crash\n"
- " --crash-shell[=BOOL] Run shell on crash\n"
- " --confirm-spawn[=BOOL] Ask for confirmation when spawning processes\n"
- " --show-status[=BOOL] 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[=BOOL] Highlight important log messages\n"
- " --log-location[=BOOL] 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 prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds, bool switching_root) {
- _cleanup_fdset_free_ FDSet *fds = NULL;
- _cleanup_fclose_ FILE *f = NULL;
- int r;
-
- assert(m);
- assert(_f);
- assert(_fds);
-
- r = manager_open_serialization(m, &f);
- if (r < 0)
- return log_error_errno(r, "Failed to create serialization file: %m");
-
- /* Make sure nothing is really destructed when we shut down */
- m->n_reloading ++;
- bus_manager_send_reloading(m, true);
-
- fds = fdset_new();
- if (!fds)
- return log_oom();
-
- r = manager_serialize(m, f, fds, switching_root);
- if (r < 0)
- return log_error_errno(r, "Failed to serialize state: %m");
-
- if (fseeko(f, 0, SEEK_SET) == (off_t) -1)
- return log_error_errno(errno, "Failed to rewind serialization fd: %m");
-
- r = fd_cloexec(fileno(f), false);
- if (r < 0)
- return log_error_errno(r, "Failed to disable O_CLOEXEC for serialization: %m");
-
- r = fdset_cloexec(fds, false);
- if (r < 0)
- return log_error_errno(r, "Failed to disable O_CLOEXEC for serialization fds: %m");
-
- *_f = f;
- *_fds = fds;
-
- f = NULL;
- fds = NULL;
-
- return 0;
-}
-
-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_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);
- if (!arg_join_controllers[0])
- goto oom;
-
- arg_join_controllers[1] = strv_new("net_cls", "net_prio", NULL);
- if (!arg_join_controllers[1])
- goto oom;
-
- arg_join_controllers[2] = NULL;
- return 0;
-
-oom:
- arg_join_controllers = strv_free_free(arg_join_controllers);
- return -ENOMEM;
-}
-
-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) ? "GNU/Linux" : pretty_name);
-}
-
-static int write_container_id(void) {
- const char *c;
- int r;
-
- c = getenv("container");
- if (isempty(c))
- return 0;
-
- r = write_string_file("/run/systemd/container", c, WRITE_STRING_FILE_CREATE);
- if (r < 0)
- return log_warning_errno(r, "Failed to write /run/systemd/container, ignoring: %m");
-
- return 1;
-}
-
-static int bump_unix_max_dgram_qlen(void) {
- _cleanup_free_ char *qlen = NULL;
- unsigned long v;
- int r;
-
- /* Let's bump the net.unix.max_dgram_qlen sysctl. The kernel
- * default of 16 is simply too low. We set the value really
- * really early during boot, so that it is actually applied to
- * all our sockets, including the $NOTIFY_SOCKET one. */
-
- r = read_one_line_file("/proc/sys/net/unix/max_dgram_qlen", &qlen);
- if (r < 0)
- return log_warning_errno(r, "Failed to read AF_UNIX datagram queue length, ignoring: %m");
-
- r = safe_atolu(qlen, &v);
- if (r < 0)
- return log_warning_errno(r, "Failed to parse AF_UNIX datagram queue length, ignoring: %m");
-
- if (v >= DEFAULT_UNIX_MAX_DGRAM_QLEN)
- return 0;
-
- qlen = mfree(qlen);
- if (asprintf(&qlen, "%lu\n", DEFAULT_UNIX_MAX_DGRAM_QLEN) < 0)
- return log_oom();
-
- r = write_string_file("/proc/sys/net/unix/max_dgram_qlen", qlen, 0);
- if (r < 0)
- return log_full_errno(IN_SET(r, -EROFS, -EPERM, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to bump AF_UNIX datagram queue length, ignoring: %m");
-
- return 1;
-}
-
-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;
-
-#ifdef HAVE_SYSV_COMPAT
- if (getpid() != 1 && strstr(program_invocation_short_name, "init")) {
- /* This is compatibility support for SysV, where
- * calling init as a user is identical to telinit. */
-
- errno = -ENOENT;
- execv(SYSTEMCTL_BINARY_PATH, argv);
- log_error_errno(errno, "Failed to exec " SYSTEMCTL_BINARY_PATH ": %m");
- return 1;
- }
-#endif
-
- 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() <= 0) {
-
- /* Running outside of a container as PID 1 */
- arg_running_as = MANAGER_SYSTEM;
- make_null_stdio();
- log_set_target(LOG_TARGET_KMSG);
- log_open();
-
- if (in_initrd())
- initrd_timestamp = userspace_timestamp;
-
- if (!skip_setup) {
- r = mount_setup_early();
- if (r < 0) {
- error_message = "Failed to early mount API filesystems";
- goto finish;
- }
- 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.
- */
- (void) clock_reset_timewarp();
- }
-
- r = clock_apply_epoch();
- if (r < 0)
- log_error_errno(r, "Current system time is before build time, but cannot correct: %m");
- else if (r > 0)
- log_info("System time before build time, advancing clock.");
- }
-
- /* Set the default for later on, but don't actually
- * open the logs like this for now. Note that if we
- * are transitioning from the initrd there might still
- * be journal fd open, and we shouldn't attempt
- * opening that before we parsed /proc/cmdline which
- * might redirect output elsewhere. */
- log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
-
- } else if (getpid() == 1) {
- /* Running inside a container, as PID 1 */
- arg_running_as = MANAGER_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 = MANAGER_USER;
- log_set_target(LOG_TARGET_AUTO);
- log_open();
-
- /* clear the kernel timestamp,
- * because we are not PID 1 */
- kernel_timestamp = DUAL_TIMESTAMP_NULL;
- }
-
- if (getpid() == 1) {
- /* Don't limit the core dump size, so that coredump handlers such as systemd-coredump (which honour the limit)
- * will process core dumps for system services by default. */
- (void) setrlimit(RLIMIT_CORE, &RLIMIT_MAKE_CONST(RLIM_INFINITY));
-
- /* But at the same time, turn off the core_pattern logic by default, so that no coredumps are stored
- * until the systemd-coredump tool is enabled via sysctl. */
- if (!skip_setup)
- (void) write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", 0);
- }
-
- /* Initialize default unit */
- r = free_and_strdup(&arg_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 initialize 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. */
- (void) reset_all_signal_handlers();
- (void) ignore_signals(SIGNALS_IGNORE, -1);
-
- if (parse_config_file() < 0) {
- error_message = "Failed to parse config file";
- goto finish;
- }
-
- if (arg_running_as == MANAGER_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 == MANAGER_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 == MANAGER_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 == MANAGER_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 == MANAGER_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 == MANAGER_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 == MANAGER_SYSTEM) {
- int v;
-
- log_info(PACKAGE_STRING " running in %ssystem mode. (" SYSTEMD_FEATURES ")",
- arg_action == ACTION_TEST ? "test " : "" );
-
- v = detect_virtualization();
- if (v > 0)
- log_info("Detected virtualization %s.", virtualization_to_string(v));
-
- 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 == MANAGER_SYSTEM && !skip_setup) {
- if (arg_show_status > 0)
- status_welcome();
-
- hostname_setup();
- machine_id_setup(NULL, arg_machine_id);
- loopback_setup();
- bump_unix_max_dgram_qlen();
-
- test_usr();
- }
-
- if (arg_running_as == MANAGER_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 (!cap_test_all(arg_capability_bounding_set)) {
- r = capability_bounding_set_drop_usermode(arg_capability_bounding_set);
- 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, 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 == MANAGER_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 (arg_running_as == MANAGER_SYSTEM) {
- bump_rlimit_nofile(&saved_rlimit_nofile);
-
- if (empty_etc) {
- r = unit_file_preset_all(UNIT_FILE_SYSTEM, false, NULL, UNIT_FILE_PRESET_ENABLE_ONLY, false, NULL, 0);
- if (r < 0)
- log_full_errno(r == -EEXIST ? LOG_NOTICE : LOG_WARNING, r, "Failed to populate /etc with preset unit settings, ignoring: %m");
- else
- log_info("Populated /etc with preset unit settings.");
- }
- }
-
- 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->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_defaults(m);
- 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. */
- fds = fdset_free(fds);
-
- arg_serialization = safe_fclose(arg_serialization);
-
- if (queue_default_job) {
- _cleanup_(sd_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, &error, &default_unit_job);
- if (r == -EPERM) {
- log_debug("Default target could not be isolated, starting instead: %s", bus_error_message(&error, r));
-
- sd_bus_error_free(&error);
-
- r = manager_add_job(m, JOB_START, target, JOB_REPLACE, &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_RELOAD:
- log_info("Reloading.");
-
- r = parse_config_file();
- if (r < 0)
- log_error("Failed to parse config file.");
-
- manager_set_defaults(m);
-
- 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 reexecution";
- 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 reexecution";
- goto finish;
- }
-
- reexecute = true;
- log_notice("Switching root.");
- goto finish;
-
- case MANAGER_EXIT:
- retval = m->return_value;
-
- if (m->running_as == MANAGER_USER) {
- log_debug("Exit.");
- goto finish;
- }
-
- /* fallthrough */
- case MANAGER_REBOOT:
- case MANAGER_POWEROFF:
- case MANAGER_HALT:
- case MANAGER_KEXEC: {
- static const char * const table[_MANAGER_EXIT_CODE_MAX] = {
- [MANAGER_EXIT] = "exit",
- [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++)
- arg_default_rlimit[j] = mfree(arg_default_rlimit[j]);
-
- arg_default_unit = mfree(arg_default_unit);
- arg_join_controllers = strv_free_free(arg_join_controllers);
- arg_default_environment = strv_free(arg_default_environment);
- arg_syscall_archs = set_free(arg_syscall_archs);
-
- 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)
- (void) 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 == MANAGER_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)
- (void) clearenv();
-
- assert(i <= args_size);
-
- /*
- * We want valgrind to print its memory usage summary before reexecution.
- * Valgrind won't do this is on its own on exec(), but it will do it on exit().
- * Hence, to ensure we get a summary here, fork() off a child, let it exit() cleanly,
- * so that it prints the summary, and wait() for it in the parent, before proceeding into the exec().
- */
- valgrind_summary_hack();
-
- (void) 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.) */
-
- arg_serialization = safe_fclose(arg_serialization);
- fds = fdset_free(fds);
-
- /* Reopen the console */
- (void) 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=... */
- (void) reset_all_signal_handlers();
- (void) reset_signal_mask();
-
- if (switch_root_init) {
- args[0] = switch_root_init;
- (void) execv(args[0], (char* const*) args);
- log_warning_errno(errno, "Failed to execute configured init, trying fallback: %m");
- }
-
- args[0] = "/sbin/init";
- (void) execv(args[0], (char* const*) args);
-
- if (errno == ENOENT) {
- log_warning("No /sbin/init, trying fallback");
-
- args[0] = "/bin/sh";
- args[1] = NULL;
- (void) 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");
- }
-
- arg_serialization = safe_fclose(arg_serialization);
- fds = fdset_free(fds);
-
-#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];
- char exit_code[DECIMAL_STR_MAX(uint8_t) + 1];
- const char* command_line[11] = {
- 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_NULL:
- command_line[pos++] = "null";
- 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";
-
- if (streq(shutdown_verb, "exit")) {
- command_line[pos++] = "--exit-code";
- command_line[pos++] = exit_code;
- xsprintf(exit_code, "%d", retval);
- }
-
- 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)
- (void) 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() <= 0)
- (void) 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 "!!!!!!" ANSI_NORMAL,
- "%s, freezing.", error_message);
- freeze_or_reboot();
- }
-
- return retval;
-}
diff --git a/src/core/manager.c b/src/core/manager.c
deleted file mode 100644
index f36cf5e320..0000000000
--- a/src/core/manager.c
+++ /dev/null
@@ -1,3124 +0,0 @@
-/***
- 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 <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <linux/kd.h>
-#include <signal.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include <sys/inotify.h>
-#include <sys/ioctl.h>
-#include <sys/reboot.h>
-#include <sys/timerfd.h>
-#include <sys/wait.h>
-#include <unistd.h>
-
-#ifdef HAVE_AUDIT
-#include <libaudit.h>
-#endif
-
-#include "sd-daemon.h"
-#include "sd-messages.h"
-
-#include "alloc-util.h"
-#include "audit-fd.h"
-#include "boot-timestamps.h"
-#include "bus-common-errors.h"
-#include "bus-error.h"
-#include "bus-kernel.h"
-#include "bus-util.h"
-#include "dbus-job.h"
-#include "dbus-manager.h"
-#include "dbus-unit.h"
-#include "dbus.h"
-#include "env-util.h"
-#include "escape.h"
-#include "exit-status.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "fs-util.h"
-#include "hashmap.h"
-#include "io-util.h"
-#include "locale-setup.h"
-#include "log.h"
-#include "macro.h"
-#include "manager.h"
-#include "missing.h"
-#include "mkdir.h"
-#include "parse-util.h"
-#include "path-lookup.h"
-#include "path-util.h"
-#include "process-util.h"
-#include "ratelimit.h"
-#include "rm-rf.h"
-#include "signal-util.h"
-#include "special.h"
-#include "stat-util.h"
-#include "string-table.h"
-#include "string-util.h"
-#include "strv.h"
-#include "terminal-util.h"
-#include "time-util.h"
-#include "transaction.h"
-#include "umask-util.h"
-#include "unit-name.h"
-#include "util.h"
-#include "virt.h"
-#include "watchdog.h"
-
-#define NOTIFY_RCVBUF_SIZE (8*1024*1024)
-
-/* 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;
- int r;
-
- assert(m);
-
- if (m->jobs_in_progress_event_source)
- return;
-
- next = now(CLOCK_MONOTONIC) + JOBS_IN_PROGRESS_WAIT_USEC;
- r = sd_event_add_time(
- m->event,
- &m->jobs_in_progress_event_source,
- CLOCK_MONOTONIC,
- next, 0,
- manager_dispatch_jobs_in_progress, m);
- if (r < 0)
- return;
-
- (void) sd_event_source_set_description(m->jobs_in_progress_event_source, "manager-jobs-in-progress");
-}
-
-#define CYLON_BUFFER_EXTRA (2*(sizeof(ANSI_RED)-1) + sizeof(ANSI_HIGHLIGHT_RED)-1 + 2*(sizeof(ANSI_NORMAL)-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);
- *p++ = '*';
- }
-
- if (pos > 0 && pos <= width) {
- p = stpcpy(p, ANSI_HIGHLIGHT_RED);
- *p++ = '*';
- }
-
- p = stpcpy(p, ANSI_NORMAL);
-
- if (pos < width) {
- p = stpcpy(p, ANSI_RED);
- *p++ = '*';
- if (pos < width-1)
- p = mempset(p, ' ', width-1-pos);
- strcpy(p, ANSI_NORMAL);
- }
-}
-
-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_event_source = sd_event_source_unref(m->ask_password_event_source);
- m->ask_password_inotify_fd = safe_close(m->ask_password_inotify_fd);
- 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;
- }
-
- (void) sd_event_source_set_description(m->ask_password_event_source, "manager-ask-password");
-
- /* 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");
-
- (void) sd_event_source_set_description(m->idle_pipe_event_source, "manager-idle-pipe");
-
- return 0;
-}
-
-static void manager_close_idle_pipe(Manager *m) {
- assert(m);
-
- m->idle_pipe_event_source = sd_event_source_unref(m->idle_pipe_event_source);
-
- 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");
-
- (void) sd_event_source_set_description(m->time_change_event_source, "manager-time-change");
-
- 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);
-
- if (m->test_run)
- return 0;
-
- /* 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;
-
- (void) sd_event_source_set_description(m->signal_event_source, "manager-signal");
-
- /* 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, SD_EVENT_PRIORITY_NORMAL-5);
- if (r < 0)
- return r;
-
- if (m->running_as == MANAGER_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",
- "LISTEN_FDNAMES",
- "WATCHDOG_PID",
- "WATCHDOG_USEC",
- NULL);
-}
-
-static int manager_default_environment(Manager *m) {
- assert(m);
-
- if (m->running_as == MANAGER_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(ManagerRunningAs running_as, bool test_run, Manager **_m) {
-
- static const char * const unit_log_fields[_MANAGER_RUNNING_AS_MAX] = {
- [MANAGER_SYSTEM] = "UNIT=",
- [MANAGER_USER] = "USER_UNIT=",
- };
-
- static const char * const unit_log_format_strings[_MANAGER_RUNNING_AS_MAX] = {
- [MANAGER_SYSTEM] = "UNIT=%s",
- [MANAGER_USER] = "USER_UNIT=%s",
- };
-
- Manager *m;
- int r;
-
- assert(_m);
- assert(running_as >= 0);
- assert(running_as < _MANAGER_RUNNING_AS_MAX);
-
- m = new0(Manager, 1);
- if (!m)
- return -ENOMEM;
-
-#ifdef ENABLE_EFI
- if (running_as == MANAGER_SYSTEM && detect_container() <= 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->default_tasks_accounting = true;
- m->default_tasks_max = UINT64_C(512);
-
- /* Prepare log fields we can use for structured logging */
- m->unit_log_field = unit_log_fields[running_as];
- m->unit_log_format_string = unit_log_format_strings[running_as];
-
- 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->cgroup_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->first_boot = -1;
-
- 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 = 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;
-
- (void) sd_event_source_set_description(m->run_queue_event_source, "manager-run-queue");
-
- 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 */
- m->notify_socket = mfree(m->notify_socket);
- 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");
-
- fd_inc_rcvbuf(fd, NOTIFY_RCVBUF_SIZE);
-
- if (m->running_as == MANAGER_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, SD_EVENT_PRIORITY_NORMAL-7);
- if (r < 0)
- return log_error_errno(r, "Failed to set priority of notify event source: %m");
-
- (void) sd_event_source_set_description(m->notify_event_source, "manager-notify");
- }
-
- return 0;
-}
-
-static int manager_setup_kdbus(Manager *m) {
- _cleanup_free_ char *p = NULL;
-
- assert(m);
-
- if (m->test_run || m->kdbus_fd >= 0)
- return 0;
- if (!is_kdbus_available())
- return -ESOCKTNOSUPPORT;
-
- m->kdbus_fd = bus_kernel_create_bus(
- m->running_as == MANAGER_SYSTEM ? "system" : "user",
- m->running_as == MANAGER_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);
-
- 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 == MANAGER_USER && getenv("DBUS_SESSION_BUS_ADDRESS"));
-
- /* Try to connect to the buses, 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, "Collecting.");
- 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->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++)
- m->rlimit[i] = mfree(m->rlimit[i]);
-
- assert(hashmap_isempty(m->units_requiring_mounts_for));
- hashmap_free(m->units_requiring_mounts_for);
-
- free(m);
- return NULL;
-}
-
-void manager_enumerate(Manager *m) {
- UnitType c;
-
- assert(m);
-
- /* Let's ask every type to load all units from disk/kernel
- * that it might know */
- for (c = 0; c < _UNIT_TYPE_MAX; c++) {
- if (!unit_type_supported(c)) {
- log_debug("Unit type .%s is not supported on this system.", unit_type_to_string(c));
- continue;
- }
-
- if (!unit_vtable[c]->enumerate)
- continue;
-
- unit_vtable[c]->enumerate(m);
- }
-
- manager_dispatch_load_queue(m);
-}
-
-static void manager_coldplug(Manager *m) {
- Iterator i;
- Unit *u;
- char *k;
- int r;
-
- assert(m);
-
- /* Then, let's set up their initial state. */
- HASHMAP_FOREACH_KEY(u, k, m->units, i) {
-
- /* ignore aliases */
- if (u->id != k)
- continue;
-
- r = unit_coldplug(u);
- if (r < 0)
- log_warning_errno(r, "We couldn't coldplug %s, proceeding anyway: %m", u->id);
- }
-}
-
-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;
- }
-
- d = safe_closedir(d);
- }
-
- 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 void manager_distribute_fds(Manager *m, FDSet *fds) {
- Iterator i;
- Unit *u;
-
- assert(m);
-
- HASHMAP_FOREACH(u, m->units, i) {
-
- if (fdset_size(fds) <= 0)
- break;
-
- if (!UNIT_VTABLE(u)->distribute_fds)
- continue;
-
- UNIT_VTABLE(u)->distribute_fds(u, fds);
- }
-}
-
-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);
- 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. */
- manager_distribute_fds(m, fds);
-
- /* 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! */
- manager_coldplug(m);
-
- 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, 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, "Trying to enqueue job %s/%s/%s", unit->id, job_type_to_string(type), job_mode_to_string(mode));
-
- type = 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, 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,
- "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, 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, e, ret);
-}
-
-int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Job **ret) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- int r;
-
- assert(m);
- assert(type < _JOB_TYPE_MAX);
- assert(name);
- assert(mode < _JOB_MODE_MAX);
-
- r = manager_add_job_by_name(m, type, name, mode, &error, ret);
- if (r < 0)
- return log_warning_errno(r, "Failed to enqueue %s job for %s: %s", job_mode_to_string(mode), name, bus_error_message(&error, r));
-
- return r;
-}
-
-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, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
- 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, const 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;
- }
-
- if (UNIT_VTABLE(u)->notify_message)
- UNIT_VTABLE(u)->notify_message(u, pid, tags, fds);
- else
- log_unit_debug(u, "Got notification message for unit. Ignoring.");
-}
-
-static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
- _cleanup_fdset_free_ FDSet *fds = NULL;
- Manager *m = userdata;
-
- 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 r, *fd_array = NULL;
- unsigned n_fds = 0;
- ssize_t n;
-
- assert(m);
- assert(m->notify_fd == fd);
-
- if (revents != EPOLLIN) {
- log_warning("Got unexpected poll event for notify fd.");
- return 0;
- }
-
- n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
- if (n < 0) {
- if (errno == EAGAIN || errno == EINTR)
- return 0;
-
- return -errno;
- }
-
- CMSG_FOREACH(cmsg, &msghdr) {
- 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.");
- return 0;
- }
-
- if ((size_t) n >= sizeof(buf)) {
- log_warning("Received notify message exceeded maximum size. Ignoring.");
- return 0;
- }
-
- 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_cgroup(m, ucred->pid);
- if (u1) {
- manager_invoke_notify_message(m, u1, ucred->pid, buf, n, fds);
- found = true;
- }
-
- u2 = hashmap_get(m->watch_pids1, PID_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, PID_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, const siginfo_t *si) {
- assert(m);
- assert(u);
- assert(si);
-
- log_unit_debug(u, "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_cgroup(m, si.si_pid);
- if (u1)
- invoke_sigchld_event(m, u1, &si);
- u2 = hashmap_get(m->watch_pids1, PID_TO_PTR(si.si_pid));
- if (u2 && u2 != u1)
- invoke_sigchld_event(m, u2, &si);
- u3 = hashmap_get(m->watch_pids2, PID_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_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- int r;
-
- log_debug("Activating special unit %s", name);
-
- r = manager_add_job_by_name(m, JOB_START, name, mode, &error, NULL);
- if (r < 0)
- log_error("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;
- int r;
-
- 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 == MANAGER_USER)
- ? LOG_DEBUG : LOG_INFO,
- &sfsi);
-
- switch (sfsi.ssi_signo) {
-
- case SIGCHLD:
- sigchld = true;
- break;
-
- case SIGTERM:
- if (m->running_as == MANAGER_SYSTEM) {
- /* This is for compatibility with the
- * original sysvinit */
- m->exit_code = MANAGER_REEXECUTE;
- break;
- }
-
- /* Fall through */
-
- case SIGINT:
- if (m->running_as == MANAGER_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 == MANAGER_SYSTEM)
- manager_start_target(m, SPECIAL_KBREQUEST_TARGET, JOB_REPLACE);
-
- /* This is a nop on non-init */
- break;
-
- case SIGPWR:
- if (m->running_as == MANAGER_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_errno(errno, "Failed to allocate memory stream: %m");
- break;
- }
-
- manager_dump_units(m, f, "\t");
- manager_dump_jobs(m, f, "\t");
-
- r = fflush_and_check(f);
- if (r < 0) {
- log_warning_errno(r, "Failed to write status stream: %m");
- 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:
- manager_set_show_status(m, SHOW_STATUS_YES);
- break;
-
- case 21:
- manager_set_show_status(m, SHOW_STATUS_NO);
- break;
-
- case 22:
- log_set_max_level(LOG_DEBUG);
- log_info("Setting log level to debug.");
- break;
-
- case 23:
- log_set_max_level(LOG_INFO);
- log_info("Setting log level to info.");
- break;
-
- case 24:
- if (m->running_as == MANAGER_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;
-
- 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 */
- m->unit_path_cache = set_free_free(m->unit_path_cache);
-
- 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 == MANAGER_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);
- }
-
- 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 == MANAGER_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, r;
-
- if (m->running_as != MANAGER_SYSTEM)
- return;
-
- 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 (u->type != UNIT_SERVICE)
- return;
-
- r = unit_name_to_prefix_and_instance(u->id, &p);
- if (r < 0) {
- log_error_errno(r, "Failed to extract prefix and instance of unit name: %m");
- 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 != MANAGER_SYSTEM)
- return;
-
- if (detect_container() > 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");
-}
-
-int manager_open_serialization(Manager *m, FILE **_f) {
- const char *path;
- int fd = -1;
- FILE *f;
-
- assert(_f);
-
- path = m->running_as == MANAGER_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;
-
- r = cunescape(l + 4, UNESCAPE_RELAX, &uce);
- if (r < 0)
- 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 */
- manager_enumerate(m);
-
- /* 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! */
- manager_coldplug(m);
-
- /* Sync current state of bus names with our set of listening units */
- if (m->api_bus)
- manager_sync_bus_names(m, m->api_bus);
-
- 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 == MANAGER_SYSTEM && detect_container() <= 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) {
- assert(m);
-
- if (m->n_reloading > 0)
- return;
-
- /* Verify that we are actually running currently. Initially
- * the exit code is set to invalid, and during operation it is
- * then set to MANAGER_OK */
- if (m->exit_code != MANAGER_OK)
- return;
-
- 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 */
- 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);
-
- manager_invalidate_startup_units(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 == MANAGER_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 == MANAGER_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)
- *generator = mfree(*generator);
-
- return;
-}
-
-static int manager_run_generators(Manager *m) {
- _cleanup_strv_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);
- (void) rm_rf(*generator, REMOVE_ROOT);
-
- *generator = mfree(*generator);
-}
-
-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++) {
- m->rlimit[i] = mfree(m->rlimit[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 != MANAGER_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 != MANAGER_SYSTEM)
- return;
-
- if (m->show_status != mode)
- log_debug("%s showing of status.",
- mode == SHOW_STATUS_NO ? "Disabling" : "Enabling");
- m->show_status = mode;
-
- if (mode > 0)
- (void) touch("/run/systemd/show-status");
- else
- (void) unlink("/run/systemd/show-status");
-}
-
-static bool manager_get_show_status(Manager *m, StatusType type) {
- assert(m);
-
- if (m->running_as != MANAGER_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 != MANAGER_SYSTEM)
- return;
-
- if (m->first_boot != (int) b) {
- if (b)
- (void) touch("/run/systemd/first-boot");
- else
- (void) unlink("/run/systemd/first-boot");
- }
-
- m->first_boot = b;
-}
-
-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);
-}
-
-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 == MANAGER_SYSTEM ?
- "/run" :
- getenv("XDG_RUNTIME_DIR");
-}
-
-int manager_update_failed_units(Manager *m, Unit *u, bool failed) {
- unsigned size;
- int r;
-
- assert(m);
- assert(u->manager == m);
-
- size = set_size(m->failed_units);
-
- if (failed) {
- r = set_ensure_allocated(&m->failed_units, NULL);
- if (r < 0)
- return log_oom();
-
- if (set_put(m->failed_units, u) < 0)
- return log_oom();
- } else
- (void) set_remove(m->failed_units, u);
-
- if (set_size(m->failed_units) != size)
- bus_manager_send_change_signal(m);
-
- return 0;
-}
-
-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_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_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_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 9803f73129..0000000000
--- a/src/core/manager.h
+++ /dev/null
@@ -1,376 +0,0 @@
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <libmount.h>
-#include <stdbool.h>
-#include <stdio.h>
-
-#include "sd-bus.h"
-#include "sd-event.h"
-
-#include "cgroup-util.h"
-#include "fdset.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 "execute.h"
-#include "job.h"
-#include "path-lookup.h"
-#include "show-status.h"
-#include "unit-name.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;
-
- 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 */
- struct libmnt_monitor *mount_monitor;
- sd_event_source *mount_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;
-
- /* This is used during reloading: before the reload we queue
- * the reply message here, and afterwards we send it */
- sd_bus_message *queued_message;
-
- 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;
- CGroupMask cgroup_supported;
- char *cgroup_root;
-
- /* Notifications from cgroups, when the unified hierarchy is
- * used is done via inotify. */
- int cgroup_inotify_fd;
- sd_event_source *cgroup_inotify_event_source;
- Hashmap *cgroup_inotify_wd_unit;
-
- /* Make sure the user cannot accidentally unmount our cgroup
- * file system */
- int pin_cgroupfs_fd;
-
- int gc_marker;
- unsigned n_in_gc_queue;
-
- /* Flags */
- ManagerRunningAs running_as;
- ManagerExitCode exit_code:5;
-
- bool dispatching_load_queue:1;
- bool dispatching_dbus_queue:1;
-
- bool taint_usr:1;
-
- bool test_run:1;
-
- /* If non-zero, exit with the following value when the systemd
- * process terminate. Useful for containers: systemd-nspawn could get
- * the return value. */
- uint8_t return_value;
-
- 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;
- bool default_tasks_accounting;
-
- uint64_t default_tasks_max;
- 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;
-
- const char *unit_log_field;
- const char *unit_log_format_string;
-
- int first_boot;
-};
-
-int manager_new(ManagerRunningAs running_as, bool test_run, Manager **m);
-Manager* manager_free(Manager *m);
-
-void 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_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, sd_bus_error *e, Job **_ret);
-int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, sd_bus_error *e, Job **_ret);
-int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, 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);
-
-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);
-
-int 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 de1a361cc4..0000000000
--- a/src/core/mount-setup.c
+++ /dev/null
@@ -1,412 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <ftw.h>
-#include <stdlib.h>
-#include <sys/mount.h>
-#include <unistd.h>
-
-#include "alloc-util.h"
-#include "bus-util.h"
-#include "cgroup-util.h"
-#include "dev-setup.h"
-#include "efivars.h"
-#include "label.h"
-#include "log.h"
-#include "macro.h"
-#include "missing.h"
-#include "mkdir.h"
-#include "mount-setup.h"
-#include "mount-util.h"
-#include "path-util.h"
-#include "set.h"
-#include "smack-util.h"
-#include "strv.h"
-#include "user-util.h"
-#include "util.h"
-#include "virt.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 },
- { "cgroup", "/sys/fs/cgroup", "cgroup", "__DEVEL__sane_behavior", MS_NOSUID|MS_NOEXEC|MS_NODEV,
- cg_is_unified_wanted, MNT_FATAL|MNT_IN_CONTAINER },
- { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
- cg_is_legacy_wanted, MNT_FATAL|MNT_IN_CONTAINER },
- { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV,
- cg_is_legacy_wanted, MNT_IN_CONTAINER },
- { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV,
- cg_is_legacy_wanted, 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
- { "kdbusfs", "/sys/fs/kdbus", "kdbusfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
- is_kdbus_wanted, MNT_IN_CONTAINER },
-};
-
-/* 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)
- (void) label_fix(p->where, true, true);
-
- r = path_is_mount_point(p->where, AT_SYMLINK_FOLLOW);
- if (r < 0 && r != -ENOENT) {
- log_full_errno((p->mode & MNT_FATAL) ? LOG_ERR : LOG_DEBUG, r, "Failed to determine whether %s is a mount point: %m", p->where);
- return (p->mode & MNT_FATAL) ? r : 0;
- }
- if (r > 0)
- return 0;
-
- /* Skip securityfs in a container */
- if (!(p->mode & MNT_IN_CONTAINER) && detect_container() > 0)
- return 0;
-
- /* The access mode here doesn't really matter too much, since
- * the mounted file system will take precedence anyway. */
- if (relabel)
- (void) mkdir_p_label(p->where, 0755);
- else
- (void) 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_errno((p->mode & MNT_FATAL) ? LOG_ERR : LOG_DEBUG, errno, "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)
- (void) label_fix(p->where, false, false);
-
- return 1;
-}
-
-static int mount_points_setup(unsigned n, bool loaded_policy) {
- unsigned i;
- int r = 0;
-
- for (i = 0; i < n; i ++) {
- int j;
-
- j = mount_one(mount_table + i, loaded_policy);
- if (j != 0 && r >= 0)
- r = j;
- }
-
- return r;
-}
-
-int mount_setup_early(void) {
- 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 */
- return mount_points_setup(N_EARLY_MOUNT, false);
-}
-
-int mount_cgroup_controllers(char ***join_controllers) {
- _cleanup_set_free_free_ Set *controllers = NULL;
- int r;
-
- if (!cg_is_legacy_wanted())
- return 0;
-
- /* 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) {
-#ifdef SMACK_RUN_LABEL
- _cleanup_free_ char *src;
- src = strappend("/sys/fs/cgroup/", options);
- if (!src)
- return log_oom();
- r = mac_smack_copy(t, src);
- if (r < 0 && r != -EOPNOTSUPP)
- return log_error_errno(r, "Failed to copy smack label from %s to %s: %m", src, t);
-#endif
- } else if (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) {
- int r = 0;
-
- r = mount_points_setup(ELEMENTSOF(mount_table), loaded_policy);
-
- 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, UID_INVALID, GID_INVALID);
-
- /* 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() <= 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 647bd770ae..0000000000
--- a/src/core/mount-setup.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#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 de1075d3a0..0000000000
--- a/src/core/mount.c
+++ /dev/null
@@ -1,1873 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <signal.h>
-#include <stdio.h>
-#include <sys/epoll.h>
-
-#include "sd-messages.h"
-
-#include "alloc-util.h"
-#include "dbus-mount.h"
-#include "escape.h"
-#include "exit-status.h"
-#include "formats-util.h"
-#include "fstab-util.h"
-#include "log.h"
-#include "manager.h"
-#include "mkdir.h"
-#include "mount-setup.h"
-#include "mount-util.h"
-#include "mount.h"
-#include "parse-util.h"
-#include "path-util.h"
-#include "process-util.h"
-#include "special.h"
-#include "string-table.h"
-#include "string-util.h"
-#include "strv.h"
-#include "unit-name.h"
-#include "unit.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 /usr/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, usec_t usec) {
- int r;
-
- assert(m);
-
- if (m->timer_event_source) {
- r = sd_event_source_set_time(m->timer_event_source, usec);
- if (r < 0)
- return r;
-
- return sd_event_source_set_enabled(m->timer_event_source, SD_EVENT_ONESHOT);
- }
-
- if (usec == USEC_INFINITY)
- return 0;
-
- r = sd_event_add_time(
- UNIT(m)->manager->event,
- &m->timer_event_source,
- CLOCK_MONOTONIC,
- usec, 0,
- mount_dispatch_timer, m);
- if (r < 0)
- return r;
-
- (void) sd_event_source_set_description(m->timer_event_source, "mount-timer");
-
- return 0;
-}
-
-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);
-
- m->where = mfree(m->where);
-
- 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 */
-
- parent = dirname_malloc(m->where);
- if (!parent)
- return -ENOMEM;
-
- 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;
-
- /* /dev/root is a really weird thing, it's not a real device,
- * but just a path the kernel exports for the root file system
- * specified on the kernel command line. Ignore it here. */
- if (path_equal(p->what, "/dev/root"))
- return 0;
-
- if (path_equal(m->where, "/"))
- return 0;
-
- if (mount_is_auto(p) && UNIT(m)->manager->running_as == MANAGER_SYSTEM)
- device_wants_mount = true;
-
- r = unit_add_node_link(UNIT(m), p->what, device_wants_mount, m->from_fragment ? UNIT_BINDS_TO : UNIT_REQUIRES);
- 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 != MANAGER_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) {
- MountParameters *p;
- const char *after;
- int r;
-
- assert(m);
-
- if (!UNIT(m)->default_dependencies)
- return 0;
-
- if (UNIT(m)->manager->running_as != MANAGER_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)) {
- /* We order ourselves after network.target. This is
- * primarily useful at shutdown: services that take
- * down the network should order themselves before
- * network.target, so that they are shut down only
- * after this mount unit is stopped. */
-
- r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_NETWORK_TARGET, NULL, true);
- if (r < 0)
- return r;
-
- /* We pull in network-online.target, and order
- * ourselves after it. This is useful at start-up to
- * actively pull in tools that want to be started
- * before we start mounting network file systems, and
- * whose purpose it is to delay this until the network
- * is "up". */
-
- r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, SPECIAL_NETWORK_ONLINE_TARGET, NULL, true);
- if (r < 0)
- return r;
-
- after = SPECIAL_REMOTE_FS_PRE_TARGET;
- } else
- after = SPECIAL_LOCAL_FS_PRE_TARGET;
-
- r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, 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;
- int r;
-
- assert(m);
-
- if (UNIT(m)->load_state != UNIT_LOADED)
- return 0;
-
- if (!m->from_fragment && !m->from_proc_self_mountinfo)
- return -ENOENT;
-
- r = unit_name_from_path(m->where, ".mount", &e);
- if (r < 0)
- return log_unit_error_errno(UNIT(m), r, "Failed to generate unit name from mount path: %m");
-
- if (!unit_has_name(UNIT(m), e)) {
- log_unit_error(UNIT(m), "Where= setting doesn't match unit name. Refusing.");
- return -EINVAL;
- }
-
- if (mount_point_is_api(m->where) || mount_point_ignore(m->where)) {
- log_unit_error(UNIT(m), "Cannot create mount unit for API file system %s. Refusing.", m->where);
- return -EINVAL;
- }
-
- if (UNIT(m)->fragment_path && !m->parameters_fragment.what) {
- log_unit_error(UNIT(m), "What= setting is missing. Refusing.");
- return -EBADMSG;
- }
-
- if (m->exec_context.pam_name && m->kill_context.kill_mode != KILL_CONTROL_GROUP) {
- log_unit_error(UNIT(m), "Unit has PAM enabled. Kill mode must be set to control-group'. Refusing.");
- return -EINVAL;
- }
-
- return 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) {
- r = unit_name_to_path(u->id, &m->where);
- if (r < 0)
- return r;
- }
-
- 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_set_default_slice(u);
- if (r < 0)
- return r;
-
- 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, MountState old_state, MountState state) {
- 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_update_mount(AUTOMOUNT(p), old_state, state);
- 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;
- }
-
- mount_notify_automount(m, old_state, state);
-
- if (state != old_state)
- log_unit_debug(UNIT(m), "Changed %s -> %s", mount_state_to_string(old_state), mount_state_to_string(state));
-
- unit_notify(UNIT(m), state_translation_table[old_state], state_translation_table[state], m->reload_result == MOUNT_SUCCESS);
- m->reload_result = MOUNT_SUCCESS;
-}
-
-static int mount_coldplug(Unit *u) {
- 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 (m->control_pid > 0 &&
- pid_is_unwaited(m->control_pid) &&
- IN_SET(new_state,
- MOUNT_MOUNTING,
- MOUNT_MOUNTING_DONE,
- MOUNT_REMOUNTING,
- MOUNT_UNMOUNTING,
- MOUNT_MOUNTING_SIGTERM,
- MOUNT_MOUNTING_SIGKILL,
- MOUNT_UNMOUNTING_SIGTERM,
- MOUNT_UNMOUNTING_SIGKILL,
- MOUNT_REMOUNTING_SIGTERM,
- MOUNT_REMOUNTING_SIGKILL)) {
-
- r = unit_watch_pid(UNIT(m), m->control_pid);
- if (r < 0)
- return r;
-
- r = mount_arm_timer(m, usec_add(u->state_change_timestamp.monotonic, m->timeout_usec));
- 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,
- .bus_endpoint_fd = -1,
- .stdin_fd = -1,
- .stdout_fd = -1,
- .stderr_fd = -1,
- };
-
- 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)
- return r;
-
- r = mount_arm_timer(m, usec_add(now(CLOCK_MONOTONIC), m->timeout_usec));
- if (r < 0)
- return r;
-
- 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);
-
- r = exec_spawn(UNIT(m),
- c,
- &m->exec_context,
- &exec_params,
- m->exec_runtime,
- &pid);
- if (r < 0)
- return r;
-
- r = unit_watch_pid(UNIT(m), pid);
- if (r < 0)
- /* FIXME: we need to do something here */
- return r;
-
- *_pid = pid;
-
- return 0;
-}
-
-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, usec_add(now(CLOCK_MONOTONIC), m->timeout_usec));
- 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_errno(UNIT(m), r, "Failed to kill processes: %m");
-
- if (state == MOUNT_REMOUNTING_SIGTERM || state == MOUNT_REMOUNTING_SIGKILL)
- mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
- else
- mount_enter_dead(m, MOUNT_FAILURE_RESOURCES);
-}
-
-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, UMOUNT_PATH, m->where, 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_errno(UNIT(m), r, "Failed to run 'umount' task: %m");
- mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
-}
-
-static int mount_get_opts(Mount *m, char **ret) {
- return fstab_filter_options(m->parameters_fragment.options,
- "nofail\0" "noauto\0" "auto\0", NULL, NULL, ret);
-}
-
-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;
-
- r = unit_fail_if_symlink(UNIT(m), m->where);
- if (r < 0)
- goto fail;
-
- (void) mkdir_p_label(m->where, m->directory_mode);
-
- unit_warn_if_dir_nonempty(UNIT(m), m->where);
-
- /* Create the source directory for bind-mounts if needed */
- p = get_mount_parameters_fragment(m);
- if (p && mount_is_bind(p))
- (void) mkdir_p_label(p->what, m->directory_mode);
-
- if (m->from_fragment) {
- _cleanup_free_ char *opts = NULL;
-
- r = mount_get_opts(m, &opts);
- if (r < 0)
- goto fail;
-
- r = exec_command_set(m->control_command, MOUNT_PATH,
- m->parameters_fragment.what, m->where, 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_errno(UNIT(m), r, "Failed to run 'mount' task: %m");
- 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, MOUNT_PATH,
- m->parameters_fragment.what, m->where,
- "-o", o, 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_errno(UNIT(m), r, "Failed to run 'remount' task: %m");
- 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 1;
-}
-
-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, "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(u, "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(u, "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(u, "Failed to parse control-pid value: %s", value);
- else
- m->control_pid = pid;
- } else if (streq(key, "control-command")) {
- MountExecCommand id;
-
- id = mount_exec_command_from_string(value);
- if (id < 0)
- log_unit_debug(u, "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(u, "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, f == MOUNT_SUCCESS ? LOG_DEBUG : LOG_NOTICE, 0,
- "Mount process exited, code=%s status=%i", 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, "Mount still present, trying again.");
- m->n_retry_umount++;
- mount_enter_unmounting(m);
- } else {
- log_unit_debug(u, "Mount still present after %u attempts to unmount, giving up.", 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), "Mounting timed out. Stopping.");
- mount_enter_signal(m, MOUNT_MOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
- break;
-
- case MOUNT_REMOUNTING:
- log_unit_warning(UNIT(m), "Remounting timed out. Stopping.");
- m->reload_result = MOUNT_FAILURE_TIMEOUT;
- mount_enter_mounted(m, MOUNT_SUCCESS);
- break;
-
- case MOUNT_UNMOUNTING:
- log_unit_warning(UNIT(m), "Unmounting timed out. Stopping.");
- 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), "Mounting timed out. Killing.");
- mount_enter_signal(m, MOUNT_MOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
- } else {
- log_unit_warning(UNIT(m), "Mounting timed out. Skipping SIGKILL. Ignoring.");
-
- 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), "Remounting timed out. Killing.");
- mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
- } else {
- log_unit_warning(UNIT(m), "Remounting timed out. Skipping SIGKILL. Ignoring.");
-
- 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), "Unmounting timed out. Killing.");
- mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
- } else {
- log_unit_warning(UNIT(m), "Unmounting timed out. Skipping SIGKILL. Ignoring.");
-
- 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),"Mount process still around after SIGKILL. Ignoring.");
-
- 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;
-
- r = unit_name_from_path(where, ".mount", &e);
- if (r < 0)
- return r;
-
- 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 == MANAGER_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 == MANAGER_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_ 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);
-
- if (!device || !path)
- continue;
-
- if (cunescape(device, UNESCAPE_RELAX, &d) < 0)
- return log_oom();
-
- if (cunescape(path, UNESCAPE_RELAX, &p) < 0)
- 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);
-
- mnt_unref_monitor(m->mount_monitor);
- m->mount_monitor = NULL;
-}
-
-static int mount_get_timeout(Unit *u, usec_t *timeout) {
- Mount *m = MOUNT(u);
- usec_t t;
- int r;
-
- if (!m->timer_event_source)
- return 0;
-
- r = sd_event_source_get_time(m->timer_event_source, &t);
- if (r < 0)
- return r;
- if (t == USEC_INFINITY)
- return 0;
-
- *timeout = t;
- return 1;
-}
-
-static void mount_enumerate(Manager *m) {
- int r;
-
- assert(m);
-
- mnt_init_debug(0);
-
- if (!m->mount_monitor) {
- int fd;
-
- m->mount_monitor = mnt_new_monitor();
- if (!m->mount_monitor) {
- log_oom();
- goto fail;
- }
-
- r = mnt_monitor_enable_kernel(m->mount_monitor, 1);
- if (r < 0) {
- log_error_errno(r, "Failed to enable watching of kernel mount events: %m");
- goto fail;
- }
-
- r = mnt_monitor_enable_userspace(m->mount_monitor, 1, NULL);
- if (r < 0) {
- log_error_errno(r, "Failed to enable watching of userspace mount events: %m");
- goto fail;
- }
-
- /* mnt_unref_monitor() will close the fd */
- fd = r = mnt_monitor_get_fd(m->mount_monitor);
- if (r < 0) {
- log_error_errno(r, "Failed to acquire watch file descriptor: %m");
- goto fail;
- }
-
- r = sd_event_add_io(m->event, &m->mount_event_source, fd, EPOLLIN, mount_dispatch_io, m);
- if (r < 0) {
- log_error_errno(r, "Failed to watch mount file descriptor: %m");
- goto fail;
- }
-
- r = sd_event_source_set_priority(m->mount_event_source, -10);
- if (r < 0) {
- log_error_errno(r, "Failed to adjust mount watch priority: %m");
- goto fail;
- }
-
- (void) sd_event_source_set_description(m->mount_event_source, "mount-monitor-dispatch");
- }
-
- r = mount_load_proc_self_mountinfo(m, false);
- if (r < 0)
- goto fail;
-
- return;
-
-fail:
- mount_shutdown(m);
-}
-
-static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
- _cleanup_set_free_ Set *around = NULL, *gone = NULL;
- Manager *m = userdata;
- const char *what;
- Iterator i;
- Unit *u;
- int r;
-
- assert(m);
- assert(revents & EPOLLIN);
-
- if (fd == mnt_monitor_get_fd(m->mount_monitor)) {
- bool rescan = false;
-
- /* Drain all events and verify that the event is valid.
- *
- * Note that libmount also monitors /run/mount mkdir if the
- * directory does not exist yet. The mkdir may generate event
- * which is irrelevant for us.
- *
- * error: r < 0; valid: r == 0, false positive: rc == 1 */
- do {
- r = mnt_monitor_next_change(m->mount_monitor, NULL, NULL);
- if (r == 0)
- rescan = true;
- else if (r < 0)
- return log_error_errno(r, "Failed to drain libmount events");
- } while (r == 0);
-
- log_debug("libmount event [rescan: %s]", yes_no(rescan));
- 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) {
-
- /* A mount point is not around right now. It
- * might be gone, or might never have
- * existed. */
-
- if (mount->from_proc_self_mountinfo &&
- mount->parameters_proc_self_mountinfo.what) {
-
- /* Remember that this device might just have disappeared */
- if (set_ensure_allocated(&gone, &string_hash_ops) < 0 ||
- set_put(gone, mount->parameters_proc_self_mountinfo.what) < 0)
- log_oom(); /* we don't care too much about OOM here... */
- }
-
- 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;
- }
-
- } else if (mount->just_mounted || mount->just_changed) {
-
- /* A mount point was added or changed */
-
- 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;
- }
- }
-
- if (mount->is_mounted &&
- mount->from_proc_self_mountinfo &&
- mount->parameters_proc_self_mountinfo.what) {
-
- if (set_ensure_allocated(&around, &string_hash_ops) < 0 ||
- set_put(around, mount->parameters_proc_self_mountinfo.what) < 0)
- log_oom();
- }
-
- /* Reset the flags for later calls */
- mount->is_mounted = mount->just_mounted = mount->just_changed = false;
- }
-
- SET_FOREACH(what, gone, i) {
- if (set_contains(around, what))
- continue;
-
- /* Let the device units know that the device is no longer mounted */
- (void) device_found_node(m, what, false, DEVICE_FOUND_MOUNT, true);
- }
-
- 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_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_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_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 3b343c6b1f..0000000000
--- a/src/core/mount.h
+++ /dev/null
@@ -1,107 +0,0 @@
-#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 "execute.h"
-#include "kill.h"
-
-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_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_;
diff --git a/src/core/namespace.c b/src/core/namespace.c
deleted file mode 100644
index 4fa381db5b..0000000000
--- a/src/core/namespace.c
+++ /dev/null
@@ -1,727 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <sched.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/mount.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <linux/fs.h>
-
-#include "alloc-util.h"
-#include "dev-setup.h"
-#include "fd-util.h"
-#include "loopback-setup.h"
-#include "missing.h"
-#include "mkdir.h"
-#include "mount-util.h"
-#include "namespace.h"
-#include "path-util.h"
-#include "selinux-util.h"
-#include "socket-util.h"
-#include "string-table.h"
-#include "string-util.h"
-#include "strv.h"
-#include "umask-util.h"
-#include "user-util.h"
-#include "util.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 == 0) {
- /* 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, UID_INVALID, GID_INVALID);
-
- /* Create the /dev directory if missing. It is more likely to be
- * missing when the service is started with RootDirectory. This is
- * consistent with mount units creating the mount points when missing.
- */
- (void) mkdir_p_label(m->path, 0755);
-
- if (mount(dev, m->path, 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) {
- r = log_error_errno(errno, "Failed to stat /dev/null: %m");
- goto fail;
- }
-
- busnode = strjoina(root, "/bus");
- if (mknod(busnode, (st.st_mode & ~07777) | 0600, st.st_rdev) < 0) {
- r = log_error_errno(errno, "mknod() for %s failed: %m",
- busnode);
- goto fail;
- }
-
- r = mount(m->path, busnode, NULL, MS_BIND, NULL);
- if (r < 0) {
- r = log_error_errno(errno, "bind mount of %s failed: %m",
- m->path);
- goto fail;
- }
-
- basepath = dirname_malloc(m->path);
- if (!basepath) {
- r = -ENOMEM;
- goto fail;
- }
-
- if (mount(root, basepath, NULL, MS_MOVE, NULL) < 0) {
- r = log_error_errno(errno, "bind mount of %s failed: %m",
- basepath);
- 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(
- const char* root_directory,
- 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 = prefix_roota(root_directory, "/tmp");
- m->mode = PRIVATE_TMP;
- m++;
- }
-
- if (var_tmp_dir) {
- m->path = prefix_roota(root_directory, "/var/tmp");
- m->mode = PRIVATE_VAR_TMP;
- m++;
- }
-
- if (private_dev) {
- m->path = prefix_roota(root_directory, "/dev");
- m->mode = PRIVATE_DEV;
- m++;
- }
-
- if (bus_endpoint_path) {
- m->path = prefix_roota(root_directory, bus_endpoint_path);
- m->mode = PRIVATE_BUS_ENDPOINT;
- m++;
- }
-
- if (protect_home != PROTECT_HOME_NO) {
- const char *home_dir, *run_user_dir, *root_dir;
-
- home_dir = prefix_roota(root_directory, "/home");
- home_dir = strjoina("-", home_dir);
- run_user_dir = prefix_roota(root_directory, "/run/user");
- run_user_dir = strjoina("-", run_user_dir);
- root_dir = prefix_roota(root_directory, "/root");
- root_dir = strjoina("-", root_dir);
-
- r = append_mounts(&m, STRV_MAKE(home_dir, run_user_dir, root_dir),
- protect_home == PROTECT_HOME_READ_ONLY ? READONLY : INACCESSIBLE);
- if (r < 0)
- return r;
- }
-
- if (protect_system != PROTECT_SYSTEM_NO) {
- const char *usr_dir, *boot_dir, *etc_dir;
-
- usr_dir = prefix_roota(root_directory, "/usr");
- boot_dir = prefix_roota(root_directory, "/boot");
- boot_dir = strjoina("-", boot_dir);
- etc_dir = prefix_roota(root_directory, "/etc");
-
- r = append_mounts(&m, protect_system == PROTECT_SYSTEM_FULL
- ? STRV_MAKE(usr_dir, boot_dir, etc_dir)
- : STRV_MAKE(usr_dir, boot_dir), 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 || root_directory) {
- /* 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;
- }
-
- if (root_directory) {
- /* Turn directory into bind mount */
- if (mount(root_directory, root_directory, NULL, MS_BIND|MS_REC, NULL) < 0)
- return -errno;
- }
-
- if (n > 0) {
- 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;
- }
- }
-
- if (root_directory) {
- /* MS_MOVE does not work on MS_SHARED so the remount MS_SHARED will be done later */
- r = mount_move_root(root_directory);
-
- /* at this point, we cannot rollback */
- if (r < 0)
- return r;
- }
-
- /* 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)
- /* at this point, we cannot rollback */
- return -errno;
-
- 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;
- int r, q;
-
- 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;
-
- netns = receive_one_fd(netns_storage_socket[0], MSG_DONTWAIT);
- if (netns == -EAGAIN) {
- /* 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 if (netns < 0) {
- r = netns;
- goto fail;
-
- } else {
- /* Yay, found something, so let's join the namespace */
- if (setns(netns, CLONE_NEWNET) < 0) {
- r = -errno;
- goto fail;
- }
-
- r = 0;
- }
-
- q = send_one_fd(netns_storage_socket[1], netns, MSG_DONTWAIT);
- if (q < 0) {
- r = q;
- 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 40bee74e2c..0000000000
--- a/src/core/namespace.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#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(const char *chroot,
- 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 6a7a37ee92..0000000000
--- 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 cc39a9e1c3..0000000000
--- 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 d4df3e93a2..0000000000
--- 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 460c1d3bf2..0000000000
--- a/src/core/path.c
+++ /dev/null
@@ -1,778 +0,0 @@
-/***
- 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 <sys/inotify.h>
-#include <unistd.h>
-
-#include "bus-error.h"
-#include "bus-util.h"
-#include "dbus-path.h"
-#include "fd-util.h"
-#include "fs-util.h"
-#include "glob-util.h"
-#include "macro.h"
-#include "mkdir.h"
-#include "path.h"
-#include "special.h"
-#include "stat-util.h"
-#include "string-table.h"
-#include "string-util.h"
-#include "unit-name.h"
-#include "unit.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;
-
- (void) sd_event_source_set_description(s->event_source, "path");
-
- /* 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;
- }
-
- r = log_warning_errno(errno, "Failed to add watch on %s: %s", s->path, errno == ENOSPC ? "too many watches" : strerror(-r));
- 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) {
- r = log_error_errno(errno, "Failed to add watch on any of the components of %s: %m", s->path);
- /* 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), "Path unit lacks path setting. Refusing.");
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int path_add_default_dependencies(Path *p) {
- int r;
-
- assert(p);
-
- if (!UNIT(p)->default_dependencies)
- return 0;
-
- 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 == MANAGER_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;
-
- 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_unit_debug(UNIT(p), "Changed %s -> %s", path_state_to_string(old_state), path_state_to_string(state));
-
- unit_notify(UNIT(p), state_translation_table[old_state], state_translation_table[state], true);
-}
-
-static void path_enter_waiting(Path *p, bool initial, bool recheck);
-
-static int path_coldplug(Unit *u) {
- 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)
- path_enter_waiting(p, true, true);
- 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_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- Unit *trigger;
- int r;
-
- assert(p);
-
- /* Don't start job if we are supposed to go down */
- if (unit_stop_pending(UNIT(p)))
- return;
-
- trigger = UNIT_TRIGGER(UNIT(p));
- if (!trigger) {
- log_unit_error(UNIT(p), "Unit to trigger vanished.");
- path_enter_dead(p, TIMER_FAILURE_RESOURCES);
- return;
- }
-
- r = manager_add_job(UNIT(p)->manager, JOB_START, trigger, JOB_REPLACE, &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_unit_warning(UNIT(p), "Failed to queue unit startup job: %s", 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_unit_debug(UNIT(p), "Got triggered.");
- 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_unit_debug(UNIT(p), "Got triggered.");
- path_enter_running(p);
- return;
- }
-
- path_set_state(p, PATH_WAITING);
- return;
-
-fail:
- log_unit_warning_errno(UNIT(p), r, "Failed to enter waiting state: %m");
- 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);
- Unit *trigger;
-
- assert(p);
- assert(p->state == PATH_DEAD || p->state == PATH_FAILED);
-
- trigger = UNIT_TRIGGER(u);
- if (!trigger || trigger->load_state != UNIT_LOADED) {
- log_unit_error(u, "Refusing to start, unit to trigger not 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_unit_debug(u, "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_unit_debug(u, "Failed to parse result value: %s", value);
- else if (f != PATH_SUCCESS)
- p->result = f;
-
- } else
- log_unit_debug(u, "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), "Got notified about unit deactivation.");
-
- /* 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_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_vtable = bus_path_vtable
-};
diff --git a/src/core/path.h b/src/core/path.h
deleted file mode 100644
index bbbcebd78e..0000000000
--- a/src/core/path.h
+++ /dev/null
@@ -1,92 +0,0 @@
-#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 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_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 c5d0ecef04..0000000000
--- a/src/core/scope.c
+++ /dev/null
@@ -1,610 +0,0 @@
-/***
- 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 "alloc-util.h"
-#include "dbus-scope.h"
-#include "load-dropin.h"
-#include "log.h"
-#include "scope.h"
-#include "special.h"
-#include "string-table.h"
-#include "string-util.h"
-#include "strv.h"
-#include "unit-name.h"
-#include "unit.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;
-}
-
-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, usec_t usec) {
- int r;
-
- assert(s);
-
- if (s->timer_event_source) {
- r = sd_event_source_set_time(s->timer_event_source, usec);
- if (r < 0)
- return r;
-
- return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
- }
-
- if (usec == USEC_INFINITY)
- return 0;
-
- r = sd_event_add_time(
- UNIT(s)->manager->event,
- &s->timer_event_source,
- CLOCK_MONOTONIC,
- usec, 0,
- scope_dispatch_timer, s);
- if (r < 0)
- return r;
-
- (void) sd_event_source_set_description(s->timer_event_source, "scope-timer");
-
- return 0;
-}
-
-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);
-
- if (!UNIT(s)->default_dependencies)
- return 0;
-
- /* 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) &&
- !manager_is_reloading_or_reexecuting(UNIT(s)->manager) &&
- !unit_has_name(UNIT(s), SPECIAL_INIT_SCOPE)) {
- log_unit_error(UNIT(s), "Scope has no PIDs. Refusing.");
- 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 && !manager_is_reloading_or_reexecuting(u->manager))
- 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_set_default_slice(u);
- if (r < 0)
- return r;
-
- r = scope_add_default_dependencies(s);
- if (r < 0)
- return r;
-
- return scope_verify(s);
-}
-
-static int scope_coldplug(Unit *u) {
- Scope *s = SCOPE(u);
- int r;
-
- assert(s);
- assert(s->state == SCOPE_DEAD);
-
- if (s->deserialized_state == s->state)
- return 0;
-
- if (IN_SET(s->deserialized_state, SCOPE_STOP_SIGKILL, SCOPE_STOP_SIGTERM)) {
- r = scope_arm_timer(s, usec_add(u->state_change_timestamp.monotonic, s->timeout_stop_usec));
- 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, usec_add(now(CLOCK_MONOTONIC), s->timeout_stop_usec));
- 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_errno(UNIT(s), r, "Failed to kill processes: %m");
-
- scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
-}
-
-static int scope_start(Unit *u) {
- Scope *s = SCOPE(u);
- int r;
-
- assert(s);
-
- if (unit_has_name(u, SPECIAL_INIT_SCOPE))
- return -EPERM;
-
- if (s->state == SCOPE_FAILED)
- return -EPERM;
-
- /* We can't fulfill this right now, please try again later */
- if (s->state == SCOPE_STOP_SIGTERM ||
- s->state == SCOPE_STOP_SIGKILL)
- return -EAGAIN;
-
- assert(s->state == SCOPE_DEAD);
-
- if (!u->transient && !manager_is_reloading_or_reexecuting(u->manager))
- return -ENOENT;
-
- (void) unit_realize_cgroup(u);
- (void) unit_reset_cpu_usage(u);
-
- r = unit_attach_pids_to_cgroup(u);
- if (r < 0) {
- log_unit_warning_errno(UNIT(s), r, "Failed to add PIDs to scope's control group: %m");
- scope_enter_dead(s, SCOPE_FAILURE_RESOURCES);
- 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, usec_t *timeout) {
- Scope *s = SCOPE(u);
- usec_t t;
- int r;
-
- if (!s->timer_event_source)
- return 0;
-
- r = sd_event_source_get_time(s->timer_event_source, &t);
- if (r < 0)
- return r;
- if (t == USEC_INFINITY)
- return 0;
-
- *timeout = t;
- 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_unit_debug(u, "Failed to parse state value: %s", value);
- else
- s->deserialized_state = state;
-
- } else
- log_unit_debug(u, "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)
- return false;
-
- return cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path) <= 0;
-}
-
-static void scope_notify_cgroup_empty_event(Unit *u) {
- Scope *s = SCOPE(u);
- assert(u);
-
- log_unit_debug(u, "cgroup is empty");
-
- 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), "Stopping timed out. Killing.");
- scope_enter_signal(s, SCOPE_STOP_SIGKILL, SCOPE_FAILURE_TIMEOUT);
- } else {
- log_unit_warning(UNIT(s), "Stopping timed out. Skipping SIGKILL.");
- scope_enter_dead(s, SCOPE_FAILURE_TIMEOUT);
- }
-
- break;
-
- case SCOPE_STOP_SIGKILL:
- log_unit_warning(UNIT(s), "Still around after SIGKILL. Ignoring.");
- 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 (unit_has_name(UNIT(s), SPECIAL_INIT_SCOPE))
- return -EPERM;
-
- if (!IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED))
- return -ESTALE;
-
- s->controller = mfree(s->controller);
-
- /* 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 void scope_enumerate(Manager *m) {
- Unit *u;
- int r;
-
- assert(m);
-
- /* Let's unconditionally add the "init.scope" special unit
- * that encapsulates PID 1. Note that PID 1 already is in the
- * cgroup for this, we hence just need to allocate the object
- * for it and that's it. */
-
- u = manager_get_unit(m, SPECIAL_INIT_SCOPE);
- if (!u) {
- u = unit_new(m, sizeof(Scope));
- if (!u) {
- log_oom();
- return;
- }
-
- r = unit_add_name(u, SPECIAL_INIT_SCOPE);
- if (r < 0) {
- unit_free(u);
- log_error_errno(r, "Failed to add init.scope name");
- return;
- }
- }
-
- u->transient = true;
- u->default_dependencies = false;
- u->no_gc = true;
- u->ignore_on_isolate = true;
- u->refuse_manual_start = true;
- u->refuse_manual_stop = true;
- SCOPE(u)->deserialized_state = SCOPE_RUNNING;
- SCOPE(u)->kill_context.kill_signal = SIGRTMIN+14;
-
- /* Prettify things, if we can. */
- if (!u->description)
- u->description = strdup("System and Service Manager");
- if (!u->documentation)
- (void) strv_extend(&u->documentation, "man:systemd(1)");
-
- unit_add_to_load_queue(u);
- unit_add_to_dbus_queue(u);
-}
-
-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,
- .can_transient = 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_vtable = bus_scope_vtable,
- .bus_set_property = bus_scope_set_property,
- .bus_commit_properties = bus_scope_commit_properties,
-
- .enumerate = scope_enumerate,
-};
diff --git a/src/core/scope.h b/src/core/scope.h
deleted file mode 100644
index 2dc86325c5..0000000000
--- a/src/core/scope.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#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 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_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 2cdfcf7b5d..0000000000
--- a/src/core/selinux-access.c
+++ /dev/null
@@ -1,280 +0,0 @@
-/***
- 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 <errno.h>
-#include <selinux/avc.h>
-#include <selinux/selinux.h>
-#include <stdio.h>
-#ifdef HAVE_AUDIT
-#include <libaudit.h>
-#endif
-
-#include "sd-bus.h"
-
-#include "alloc-util.h"
-#include "audit-fd.h"
-#include "bus-util.h"
-#include "log.h"
-#include "path-util.h"
-#include "selinux-util.h"
-#include "stdio-util.h"
-#include "strv.h"
-#include "util.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;
-}
-
-static int callback_type_to_priority(int type) {
- switch(type) {
-
- case SELINUX_ERROR:
- return LOG_ERR;
-
- case SELINUX_WARNING:
- return LOG_WARNING;
-
- case SELINUX_INFO:
- return LOG_INFO;
-
- case SELINUX_AVC:
- default:
- return LOG_NOTICE;
- }
-}
-
-/*
- libselinux uses this callback when access gets denied or other
- events happen. If audit is turned on, messages will be reported
- using audit netlink, otherwise they will be logged using the usual
- channels.
-
- Code copied from dbus and modified.
-*/
-_printf_(2, 3) static int log_callback(int type, const char *fmt, ...) {
- va_list ap;
-
-#ifdef HAVE_AUDIT
- int fd;
-
- fd = get_audit_fd();
-
- if (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(fd, AUDIT_USER_AVC, buf, NULL, NULL, NULL, 0);
- return 0;
- }
- }
-#endif
-
- va_start(ap, fmt);
- log_internalv(LOG_AUTH | callback_type_to_priority(type), 0, __FILE__, __LINE__, __FUNCTION__, fmt, ap);
- va_end(ap);
-
- return 0;
-}
-
-static int access_init(sd_bus_error *error) {
-
- if (!mac_selinux_use())
- return 0;
-
- if (initialized)
- return 1;
-
- if (avc_open(NULL, 0) != 0) {
- int enforce, saved_errno = errno;
-
- enforce = security_getenforce();
- log_full_errno(enforce != 0 ? LOG_ERR : LOG_WARNING, saved_errno, "Failed to open the SELinux AVC: %m");
-
- /* If enforcement isn't on, then let's suppress this
- * error, and just don't do any AVC checks. The
- * warning we printed is hence all the admin will
- * see. */
- if (enforce == 0)
- return 0;
-
- /* Return an access denied error, if we couldn't load
- * the AVC but enforcing mode was on, or we couldn't
- * determine whether it is one. */
- return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to open the SELinux AVC: %s", strerror(saved_errno));
- }
-
- selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback) audit_callback);
- selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) log_callback);
-
- initialized = true;
- return 1;
-}
-
-/*
- 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) {
-
- _cleanup_(sd_bus_creds_unrefp) 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);
-
- r = 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;
-
- /* The SELinux context is something we really should have
- * gotten directly from the message or sender, and not be an
- * augmented field. If it was augmented we cannot use it for
- * authorization, since this is racy and vulnerable. Let's add
- * an extra check, just in case, even though this really
- * shouldn't be possible. */
- assert_return((sd_bus_creds_get_augmented_mask(creds) & SD_BUS_CREDS_SELINUX_CONTEXT) == 0, -EPERM);
-
- 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_raw(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_raw(&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(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
-
-int mac_selinux_generic_access_check(
- sd_bus_message *message,
- const char *path,
- const char *permission,
- sd_bus_error *error) {
-
- return 0;
-}
-
-#endif
diff --git a/src/core/selinux-access.h b/src/core/selinux-access.h
deleted file mode 100644
index 8f1f058a32..0000000000
--- a/src/core/selinux-access.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#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"
-
-int mac_selinux_generic_access_check(sd_bus_message *message, const char *path, 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 9a115a4387..0000000000
--- a/src/core/selinux-setup.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/***
- 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 <unistd.h>
-
-#ifdef HAVE_SELINUX
-#include <selinux/selinux.h>
-#endif
-
-#include "log.h"
-#include "macro.h"
-#include "selinux-setup.h"
-#include "selinux-util.h"
-#include "string-util.h"
-#include "util.h"
-
-#ifdef HAVE_SELINUX
-_printf_(2,3)
-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) {
- _cleanup_(mac_selinux_freep) char *label = NULL;
- char timespan[FORMAT_TIMESPAN_MAX];
-
- mac_selinux_retest();
-
- /* Transition to the new context */
- r = mac_selinux_get_create_label_from_exe(SYSTEMD_BINARY_PATH, &label);
- if (r < 0 || !label) {
- 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);
- }
-
- 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 7b613249b0..0000000000
--- a/src/core/selinux-setup.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#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 ac7e41d777..0000000000
--- a/src/core/service.c
+++ /dev/null
@@ -1,3366 +0,0 @@
-/***
- 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 "alloc-util.h"
-#include "async.h"
-#include "bus-error.h"
-#include "bus-kernel.h"
-#include "bus-util.h"
-#include "dbus-service.h"
-#include "def.h"
-#include "env-util.h"
-#include "escape.h"
-#include "exit-status.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "formats-util.h"
-#include "fs-util.h"
-#include "load-dropin.h"
-#include "load-fragment.h"
-#include "log.h"
-#include "manager.h"
-#include "parse-util.h"
-#include "path-util.h"
-#include "process-util.h"
-#include "service.h"
-#include "signal-util.h"
-#include "special.h"
-#include "string-table.h"
-#include "string-util.h"
-#include "strv.h"
-#include "unit-name.h"
-#include "unit-printf.h"
-#include "unit.h"
-#include "utf8.h"
-#include "util.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->runtime_max_usec = USEC_INFINITY;
- s->type = _SERVICE_TYPE_INVALID;
- s->socket_fd = -1;
- s->bus_endpoint_fd = -1;
- s->stdin_fd = s->stdout_fd = s->stderr_fd = -1;
- s->guess_main_pid = true;
-
- 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), "Stopping watch for PID file %s", s->pid_file_pathspec->path);
- path_spec_unwatch(s->pid_file_pathspec);
- path_spec_done(s->pid_file_pathspec);
- s->pid_file_pathspec = mfree(s->pid_file_pathspec);
-}
-
-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_process_ppid(pid, &ppid) >= 0 && ppid != getpid()) {
- log_unit_warning(UNIT(s), "Supervising process "PID_FMT" which is not our child. We'll most likely not notice when it exits.", 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, usec_add(s->watchdog_timestamp.monotonic, s->watchdog_usec));
- if (r < 0) {
- log_unit_warning_errno(UNIT(s), r, "Failed to reset watchdog timer: %m");
- 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,
- usec_add(s->watchdog_timestamp.monotonic, s->watchdog_usec), 0,
- service_dispatch_watchdog, s);
- if (r < 0) {
- log_unit_warning_errno(UNIT(s), r, "Failed to add watchdog timer: %m");
- return;
- }
-
- (void) sd_event_source_set_description(s->watchdog_event_source, "service-watchdog");
-
- /* 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), r, "Failed to install watchdog timer: %m");
-}
-
-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);
- }
-
- free(fs->fdname);
- safe_close(fs->fd);
- free(fs);
-}
-
-static void service_release_resources(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
-
- if (!s->fd_store && s->stdin_fd < 0 && s->stdout_fd < 0 && s->stderr_fd < 0)
- return;
-
- log_unit_debug(u, "Releasing all resources.");
-
- s->stdin_fd = safe_close(s->stdin_fd);
- s->stdout_fd = safe_close(s->stdout_fd);
- s->stderr_fd = safe_close(s->stderr_fd);
-
- 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);
-
- s->pid_file = mfree(s->pid_file);
- s->status_text = mfree(s->status_text);
-
- 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);
- s->bus_name = mfree(s->bus_name);
- }
-
- s->bus_name_owner = mfree(s->bus_name_owner);
-
- 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, const char *name) {
- 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 = same_fd(fs->fd, fd);
- 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;
- fs->fdname = strdup(name ?: "stored");
- if (!fs->fdname) {
- free(fs);
- return -ENOMEM;
- }
-
- r = sd_event_add_io(UNIT(s)->manager->event, &fs->event_source, fd, 0, on_fd_store_io, fs);
- if (r < 0) {
- free(fs->fdname);
- free(fs);
- return r;
- }
-
- (void) sd_event_source_set_description(fs->event_source, "service-fd-store");
-
- 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, const char *name) {
- 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, name);
- if (r < 0)
- return log_unit_error_errno(UNIT(s), r, "Couldn't add fd to fd store: %m");
- if (r > 0) {
- log_unit_debug(UNIT(s), "Added fd to fd store.");
- fd = -1;
- }
- }
-
- if (fdset_size(fds) > 0)
- log_unit_warning(UNIT(s), "Tried to store more fds than FileDescriptorStoreMax=%u allows, closing remaining.", 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, usec);
- if (r < 0)
- return r;
-
- return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
- }
-
- if (usec == USEC_INFINITY)
- return 0;
-
- r = sd_event_add_time(
- UNIT(s)->manager->event,
- &s->timer_event_source,
- CLOCK_MONOTONIC,
- usec, 0,
- service_dispatch_timer, s);
- if (r < 0)
- return r;
-
- (void) sd_event_source_set_description(s->timer_event_source, "service-timer");
-
- return 0;
-}
-
-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), "Service lacks both ExecStart= and ExecStop= setting. Refusing.");
- return -EINVAL;
- }
-
- if (s->type != SERVICE_ONESHOT && !s->exec_command[SERVICE_EXEC_START]) {
- log_unit_error(UNIT(s), "Service has no ExecStart= setting, which is only allowed for Type=oneshot services. Refusing.");
- return -EINVAL;
- }
-
- if (!s->remain_after_exit && !s->exec_command[SERVICE_EXEC_START]) {
- log_unit_error(UNIT(s), "Service has no ExecStart= setting, which is only allowed for RemainAfterExit=yes services. Refusing.");
- return -EINVAL;
- }
-
- if (s->type != SERVICE_ONESHOT && s->exec_command[SERVICE_EXEC_START]->command_next) {
- log_unit_error(UNIT(s), "Service has more than one ExecStart= setting, which is only allowed for Type=oneshot services. Refusing.");
- return -EINVAL;
- }
-
- if (s->type == SERVICE_ONESHOT && s->restart != SERVICE_RESTART_NO) {
- log_unit_error(UNIT(s), "Service has Restart= setting other than no, which isn't allowed for Type=oneshot services. Refusing.");
- return -EINVAL;
- }
-
- if (s->type == SERVICE_ONESHOT && !exit_status_set_is_empty(&s->restart_force_status)) {
- log_unit_error(UNIT(s), "Service has RestartForceStatus= set, which isn't allowed for Type=oneshot services. Refusing.");
- return -EINVAL;
- }
-
- if (s->type == SERVICE_DBUS && !s->bus_name) {
- log_unit_error(UNIT(s), "Service is of type D-Bus but no D-Bus service name has been specified. Refusing.");
- return -EINVAL;
- }
-
- if (s->bus_name && s->type != SERVICE_DBUS)
- log_unit_warning(UNIT(s), "Service has a D-Bus service name specified, but is not of type dbus. Ignoring.");
-
- 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), "Service has PAM enabled. Kill mode must be set to 'control-group' or 'mixed'. Refusing.");
- return -EINVAL;
- }
-
- if (s->usb_function_descriptors && !s->usb_function_strings)
- log_unit_warning(UNIT(s), "Service has USBFunctionDescriptors= setting, but no USBFunctionStrings=. Ignoring.");
-
- if (!s->usb_function_descriptors && s->usb_function_strings)
- log_unit_warning(UNIT(s), "Service has USBFunctionStrings= setting, but no USBFunctionDescriptors=. Ignoring.");
-
- if (s->runtime_max_usec != USEC_INFINITY && s->type == SERVICE_ONESHOT)
- log_unit_warning(UNIT(s), "MaxRuntimeSec= has no effect in combination with Type=oneshot. Ignoring.");
-
- return 0;
-}
-
-static int service_add_default_dependencies(Service *s) {
- int r;
-
- assert(s);
-
- if (!UNIT(s)->default_dependencies)
- return 0;
-
- /* Add a number of automatic dependencies useful for the
- * majority of services. */
-
- if (UNIT(s)->manager->running_as == MANAGER_SYSTEM) {
- /* First, pull in the really early boot stuff, and
- * require it, so that we fail if we can't acquire
- * it. */
-
- r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
- if (r < 0)
- return r;
- } else {
-
- /* In the --user instance there's no sysinit.target,
- * in that case require basic.target instead. */
-
- r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true);
- if (r < 0)
- return r;
- }
-
- /* Second, if the rest of the base system is in the same
- * transaction, order us after it, but do not pull it in or
- * even require it. */
- r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_BASIC_TARGET, NULL, true);
- if (r < 0)
- return r;
-
- /* Third, add us in for 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_setup_bus_name(Service *s) {
- int r;
-
- assert(s);
-
- if (!s->bus_name)
- return 0;
-
- if (is_kdbus_available()) {
- 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 log_unit_error_errno(UNIT(s), r, "Failed to add dependency to .busname unit: %m");
-
- } else {
- /* If kdbus is not available, we know the dbus socket is required, hence pull it in, and require it */
- r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true);
- if (r < 0)
- return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m");
- }
-
- /* Regardless if kdbus is used or not, we always want to be ordered against dbus.socket if both are in the transaction. */
- r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_DBUS_SOCKET, NULL, true);
- if (r < 0)
- return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m");
-
- r = unit_watch_bus_name(UNIT(s), s->bus_name);
- if (r == -EEXIST)
- return log_unit_error_errno(UNIT(s), r, "Two services allocated for the same bus name %s, refusing operation.", s->bus_name);
- if (r < 0)
- return log_unit_error_errno(UNIT(s), r, "Cannot watch bus name %s: %m", s->bus_name);
-
- return 0;
-}
-
-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 = USEC_INFINITY;
-
- 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_set_default_slice(UNIT(s));
- if (r < 0)
- return r;
-
- if (s->type == SERVICE_NOTIFY && s->notify_access == NOTIFY_NONE)
- s->notify_access = NOTIFY_MAIN;
-
- if (s->watchdog_usec > 0 && s->notify_access == NOTIFY_NONE)
- s->notify_access = NOTIFY_MAIN;
-
- r = service_add_default_dependencies(s);
- if (r < 0)
- return r;
-
- r = service_setup_bus_name(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_errno(UNIT(s), r, "PID file %s not readable (yet?) after %s: %m", 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), 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), "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), "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), "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_errno(UNIT(s), r, "Failed to watch PID "PID_FMT" for service: %m", pid);
- return r;
- }
-
- return 0;
-}
-
-static int service_search_main_pid(Service *s) {
- pid_t pid = 0;
- 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);
-
- r = unit_search_main_pid(UNIT(s), &pid);
- if (r < 0)
- return r;
-
- log_unit_debug(UNIT(s), "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_errno(UNIT(s), r, "Failed to watch PID "PID_FMT" from: %m", pid);
- 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_RUNNING,
- SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, 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_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, 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_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, 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_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
- 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_prune_cgroup(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), "Changed %s -> %s", service_state_to_string(old_state), service_state_to_string(state));
-
- unit_notify(UNIT(s), table[old_state], table[state], s->reload_result == SERVICE_SUCCESS);
-}
-
-static usec_t service_coldplug_timeout(Service *s) {
- assert(s);
-
- switch (s->deserialized_state) {
-
- case SERVICE_START_PRE:
- case SERVICE_START:
- case SERVICE_START_POST:
- case SERVICE_RELOAD:
- return usec_add(UNIT(s)->state_change_timestamp.monotonic, s->timeout_start_usec);
-
- case SERVICE_RUNNING:
- return usec_add(UNIT(s)->active_enter_timestamp.monotonic, s->runtime_max_usec);
-
- case SERVICE_STOP:
- case SERVICE_STOP_SIGABRT:
- case SERVICE_STOP_SIGTERM:
- case SERVICE_STOP_SIGKILL:
- case SERVICE_STOP_POST:
- case SERVICE_FINAL_SIGTERM:
- case SERVICE_FINAL_SIGKILL:
- return usec_add(UNIT(s)->state_change_timestamp.monotonic, s->timeout_stop_usec);
-
- case SERVICE_AUTO_RESTART:
- return usec_add(UNIT(s)->inactive_enter_timestamp.monotonic, s->restart_usec);
-
- default:
- return USEC_INFINITY;
- }
-}
-
-static int service_coldplug(Unit *u) {
- Service *s = SERVICE(u);
- int r;
-
- assert(s);
- assert(s->state == SERVICE_DEAD);
-
- if (s->deserialized_state == s->state)
- return 0;
-
- r = service_arm_timer(s, service_coldplug_timeout(s));
- if (r < 0)
- return r;
-
- if (s->main_pid > 0 &&
- 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_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) {
- r = unit_watch_pid(UNIT(s), s->main_pid);
- if (r < 0)
- return r;
- }
-
- if (s->control_pid > 0 &&
- 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_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, 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, char ***fd_names) {
- _cleanup_strv_free_ char **rfd_names = NULL;
- _cleanup_free_ int *rfds = NULL;
- int rn_fds = 0, r;
-
- assert(s);
- assert(fds);
- assert(fd_names);
-
- if (s->socket_fd >= 0) {
-
- /* Pass the per-connection socket */
-
- rfds = new(int, 1);
- if (!rfds)
- return -ENOMEM;
- rfds[0] = s->socket_fd;
-
- rfd_names = strv_new("connection", NULL);
- if (!rfd_names)
- return -ENOMEM;
-
- rn_fds = 1;
- } else {
- Iterator i;
- Unit *u;
-
- /* Pass all our configured sockets for singleton services */
-
- SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) {
- _cleanup_free_ int *cfds = NULL;
- Socket *sock;
- int cn_fds;
-
- if (u->type != UNIT_SOCKET)
- continue;
-
- sock = SOCKET(u);
-
- cn_fds = socket_collect_fds(sock, &cfds);
- if (cn_fds < 0)
- return cn_fds;
-
- if (cn_fds <= 0)
- continue;
-
- if (!rfds) {
- rfds = cfds;
- rn_fds = cn_fds;
-
- cfds = NULL;
- } else {
- int *t;
-
- t = realloc(rfds, (rn_fds + cn_fds) * sizeof(int));
- if (!t)
- return -ENOMEM;
-
- memcpy(t + rn_fds, cfds, cn_fds * sizeof(int));
-
- rfds = t;
- rn_fds += cn_fds;
- }
-
- r = strv_extend_n(&rfd_names, socket_fdname(sock), cn_fds);
- if (r < 0)
- return r;
- }
- }
-
- if (s->n_fd_store > 0) {
- ServiceFDStore *fs;
- char **nl;
- int *t;
-
- t = realloc(rfds, (rn_fds + s->n_fd_store) * sizeof(int));
- if (!t)
- return -ENOMEM;
-
- rfds = t;
-
- nl = realloc(rfd_names, (rn_fds + s->n_fd_store + 1) * sizeof(char*));
- if (!nl)
- return -ENOMEM;
-
- rfd_names = nl;
-
- LIST_FOREACH(fd_store, fs, s->fd_store) {
- rfds[rn_fds] = fs->fd;
- rfd_names[rn_fds] = strdup(strempty(fs->fdname));
- if (!rfd_names[rn_fds])
- return -ENOMEM;
-
- rn_fds++;
- }
-
- rfd_names[rn_fds] = NULL;
- }
-
- *fds = rfds;
- *fd_names = rfd_names;
-
- rfds = NULL;
- rfd_names = NULL;
-
- return rn_fds;
-}
-
-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) {
-
- _cleanup_strv_free_ char **argv = NULL, **final_env = NULL, **our_env = NULL, **fd_names = NULL;
- _cleanup_free_ char *bus_endpoint_path = NULL;
- _cleanup_free_ int *fds = NULL;
- unsigned n_fds = 0, n_env = 0;
- const char *path;
- pid_t pid;
-
- ExecParameters exec_params = {
- .apply_permissions = apply_permissions,
- .apply_chroot = apply_chroot,
- .apply_tty_stdin = apply_tty_stdin,
- .bus_endpoint_fd = -1,
- .stdin_fd = -1,
- .stdout_fd = -1,
- .stderr_fd = -1,
- };
-
- int r;
-
- 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)
- return r;
-
- 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) {
-
- r = service_collect_fds(s, &fds, &fd_names);
- if (r < 0)
- return r;
-
- n_fds = r;
- }
-
- r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), timeout));
- if (r < 0)
- return r;
-
- r = unit_full_printf_strv(UNIT(s), c->argv, &argv);
- if (r < 0)
- return r;
-
- our_env = new0(char*, 6);
- if (!our_env)
- return -ENOMEM;
-
- 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)
- return -ENOMEM;
-
- if (s->main_pid > 0)
- if (asprintf(our_env + n_env++, "MAINPID="PID_FMT, s->main_pid) < 0)
- return -ENOMEM;
-
- if (UNIT(s)->manager->running_as != MANAGER_SYSTEM)
- if (asprintf(our_env + n_env++, "MANAGERPID="PID_FMT, getpid()) < 0)
- return -ENOMEM;
-
- if (s->socket_fd >= 0) {
- union sockaddr_union sa;
- socklen_t salen = sizeof(sa);
-
- r = getpeername(s->socket_fd, &sa.sa, &salen);
- if (r < 0)
- return -errno;
-
- 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)
- return r;
-
- t = strappend("REMOTE_ADDR=", addr);
- if (!t)
- return -ENOMEM;
- our_env[n_env++] = t;
-
- port = sockaddr_port(&sa.sa);
- if (port < 0)
- return port;
-
- if (asprintf(&t, "REMOTE_PORT=%u", port) < 0)
- return -ENOMEM;
- our_env[n_env++] = t;
- }
- }
-
- final_env = strv_env_merge(2, UNIT(s)->manager->environment, our_env, NULL);
- if (!final_env)
- return -ENOMEM;
-
- if (is_control && UNIT(s)->cgroup_path) {
- path = strjoina(UNIT(s)->cgroup_path, "/control");
- (void) cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
- } else
- path = UNIT(s)->cgroup_path;
-
- if (s->exec_context.bus_endpoint) {
- r = bus_kernel_create_endpoint(UNIT(s)->manager->running_as == MANAGER_SYSTEM ? "system" : "user",
- UNIT(s)->id, &bus_endpoint_path);
- if (r < 0)
- return r;
-
- /* 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;
- }
-
- exec_params.argv = argv;
- exec_params.fds = fds;
- exec_params.fd_names = fd_names;
- 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.watchdog_usec = s->watchdog_usec;
- exec_params.bus_endpoint_path = bus_endpoint_path;
- exec_params.selinux_context_net = s->socket_fd_selinux_context_net;
- if (s->type == SERVICE_IDLE)
- exec_params.idle_pipe = UNIT(s)->manager->idle_pipe;
- exec_params.stdin_fd = s->stdin_fd;
- exec_params.stdout_fd = s->stdout_fd;
- exec_params.stderr_fd = s->stderr_fd;
-
- r = exec_spawn(UNIT(s),
- c,
- &s->exec_context,
- &exec_params,
- s->exec_runtime,
- &pid);
- if (r < 0)
- return r;
-
- r = unit_watch_pid(UNIT(s), pid);
- if (r < 0)
- /* FIXME: we need to do something here */
- return r;
-
- *_pid = pid;
-
- return 0;
-}
-
-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 let's 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);
- if (r < 0)
- return r;
-
- return !r;
-}
-
-static bool service_shall_restart(Service *s) {
- assert(s);
-
- /* Don't restart after manual stops */
- if (s->forbid_restart)
- return false;
-
- /* Never restart if this is configured as special exception */
- if (exit_status_set_test(&s->restart_prevent_status, s->main_exec_status.code, s->main_exec_status.status))
- return false;
-
- /* Restart if the exit code/status are configured as restart triggers */
- if (exit_status_set_test(&s->restart_force_status, s->main_exec_status.code, s->main_exec_status.status))
- return true;
-
- switch (s->restart) {
-
- case SERVICE_RESTART_NO:
- return false;
-
- case SERVICE_RESTART_ALWAYS:
- return true;
-
- case SERVICE_RESTART_ON_SUCCESS:
- return s->result == SERVICE_SUCCESS;
-
- case SERVICE_RESTART_ON_FAILURE:
- return s->result != SERVICE_SUCCESS;
-
- case SERVICE_RESTART_ON_ABNORMAL:
- return !IN_SET(s->result, SERVICE_SUCCESS, SERVICE_FAILURE_EXIT_CODE);
-
- case SERVICE_RESTART_ON_WATCHDOG:
- return s->result == SERVICE_FAILURE_WATCHDOG;
-
- case SERVICE_RESTART_ON_ABORT:
- return IN_SET(s->result, SERVICE_FAILURE_SIGNAL, SERVICE_FAILURE_CORE_DUMP);
-
- default:
- assert_not_reached("unknown restart setting");
- }
-}
-
-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), "Failed with result '%s'.", service_result_to_string(s->result));
- failure_action(UNIT(s)->manager, s->failure_action, UNIT(s)->reboot_arg);
- }
-
- if (allow_restart && service_shall_restart(s)) {
-
- r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->restart_usec));
- if (r < 0)
- goto fail;
-
- service_set_state(s, SERVICE_AUTO_RESTART);
- }
-
- /* The next restart might not be a manual stop, hence reset the flag indicating manual stops */
- 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)
- (void) unlink(s->pid_file);
-
- return;
-
-fail:
- log_unit_warning_errno(UNIT(s), r, "Failed to run install restart timer: %m");
- 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), r, "Failed to run 'stop-post' task: %m");
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
-}
-
-static int state_to_kill_operation(ServiceState state) {
- switch (state) {
-
- case SERVICE_STOP_SIGABRT:
- return KILL_ABORT;
-
- case SERVICE_STOP_SIGTERM:
- case SERVICE_FINAL_SIGTERM:
- return KILL_TERMINATE;
-
- case SERVICE_STOP_SIGKILL:
- case SERVICE_FINAL_SIGKILL:
- return KILL_KILL;
-
- default:
- return _KILL_OPERATION_INVALID;
- }
-}
-
-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_to_kill_operation(state),
- s->main_pid,
- s->control_pid,
- s->main_pid_alien);
-
- if (r < 0)
- goto fail;
-
- if (r > 0) {
- r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_stop_usec));
- if (r < 0)
- goto fail;
-
- service_set_state(s, state);
- } else if (IN_SET(state, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM) && s->kill_context.send_sigkill)
- service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_SUCCESS);
- else if (IN_SET(state, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL))
- service_enter_stop_post(s, SERVICE_SUCCESS);
- else if (state == SERVICE_FINAL_SIGTERM && s->kill_context.send_sigkill)
- 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), r, "Failed to kill processes: %m");
-
- if (IN_SET(state, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL))
- 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));
-
- service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), 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), r, "Failed to run 'stop' task: %m");
- service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
-}
-
-static bool service_good(Service *s) {
- int main_pid_ok;
- assert(s);
-
- if (s->type == SERVICE_DBUS && !s->bus_name_good)
- return false;
-
- main_pid_ok = main_pid_good(s);
- if (main_pid_ok > 0) /* It's alive */
- return true;
- if (main_pid_ok == 0) /* It's dead */
- return false;
-
- /* OK, we don't know anything about the main PID, maybe
- * because there is none. Let's check the control group
- * instead. */
-
- return cgroup_good(s) != 0;
-}
-
-static void service_enter_running(Service *s, ServiceResult f) {
- assert(s);
-
- if (f != SERVICE_SUCCESS)
- s->result = f;
-
- service_unwatch_control_pid(s);
-
- if (service_good(s)) {
-
- /* 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);
- service_arm_timer(s, usec_add(UNIT(s)->active_enter_timestamp.monotonic, s->runtime_max_usec));
- }
-
- } 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), r, "Failed to run 'start-post' task: %m");
- 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;
- usec_t timeout;
- 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;
- }
-
- if (IN_SET(s->type, SERVICE_SIMPLE, SERVICE_IDLE))
- /* For simple + idle this is the main process. We don't apply any timeout here, but
- * service_enter_running() will later apply the .runtime_max_usec timeout. */
- timeout = USEC_INFINITY;
- else
- timeout = s->timeout_start_usec;
-
- r = service_spawn(s,
- c,
- timeout,
- true,
- true,
- true,
- true,
- false,
- &pid);
- if (r < 0)
- goto fail;
-
- if (IN_SET(s->type, SERVICE_SIMPLE, 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 (IN_SET(s->type, SERVICE_ONESHOT, SERVICE_DBUS, 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), r, "Failed to run 'start' task: %m");
- 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), r, "Failed to run 'start-pre' task: %m");
- service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
-}
-
-static void service_enter_restart(Service *s) {
- _cleanup_(sd_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), "Stop job pending for unit, delaying automatic restart.");
-
- r = service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), 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, &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), "Scheduled restart job.");
- return;
-
-fail:
- log_unit_warning(UNIT(s), "Failed to schedule restart job: %s", bus_error_message(&error, -r));
- service_enter_dead(s, SERVICE_FAILURE_RESOURCES, false);
-}
-
-static void service_enter_reload_by_notify(Service *s) {
- assert(s);
-
- service_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), 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->reload_result = SERVICE_SUCCESS;
-
- 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), r, "Failed to run 'reload' task: %m");
- s->reload_result = SERVICE_FAILURE_RESOURCES;
- service_enter_running(s, SERVICE_SUCCESS);
-}
-
-static void service_run_next_control(Service *s) {
- usec_t timeout;
- 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);
-
- if (IN_SET(s->state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
- timeout = s->timeout_start_usec;
- else
- timeout = s->timeout_stop_usec;
-
- r = service_spawn(s,
- s->control_command,
- timeout,
- 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), r, "Failed to run next control task: %m");
-
- 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), r, "Failed to run next main task: %m");
- service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
-}
-
-static int service_start(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
-
- /* We cannot fulfill this request right now, try again later
- * please! */
- if (IN_SET(s->state,
- SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))
- return -EAGAIN;
-
- /* Already on it! */
- if (IN_SET(s->state, SERVICE_START_PRE, SERVICE_START, 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(IN_SET(s->state, SERVICE_DEAD, SERVICE_FAILED));
-
- 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;
-
- s->status_text = mfree(s->status_text);
- 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 manual stops. */
- s->forbid_restart = true;
-
- /* Already on it */
- if (IN_SET(s->state,
- SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, 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 (IN_SET(s->state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD)) {
- service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_SUCCESS);
- return 0;
- }
-
- assert(IN_SET(s->state, SERVICE_RUNNING, 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 1;
-}
-
-_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;
- int r;
-
- 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));
- unit_serialize_item(u, f, "bus-name-good", yes_no(s->bus_name_good));
- unit_serialize_item(u, f, "bus-name-owner", s->bus_name_owner);
-
- r = unit_serialize_item_escaped(u, f, "status-text", s->status_text);
- if (r < 0)
- return r;
-
- /* 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));
-
- r = unit_serialize_item_fd(u, f, fds, "stdin-fd", s->stdin_fd);
- if (r < 0)
- return r;
- r = unit_serialize_item_fd(u, f, fds, "stdout-fd", s->stdout_fd);
- if (r < 0)
- return r;
- r = unit_serialize_item_fd(u, f, fds, "stderr-fd", s->stderr_fd);
- if (r < 0)
- return r;
-
- r = unit_serialize_item_fd(u, f, fds, "socket-fd", s->socket_fd);
- if (r < 0)
- return r;
- r = unit_serialize_item_fd(u, f, fds, "endpoint-fd", s->bus_endpoint_fd);
- if (r < 0)
- return r;
-
- LIST_FOREACH(fd_store, fs, s->fd_store) {
- _cleanup_free_ char *c = NULL;
- int copy;
-
- copy = fdset_put_dup(fds, fs->fd);
- if (copy < 0)
- return copy;
-
- c = cescape(fs->fdname);
-
- unit_serialize_item_format(u, f, "fd-store-fd", "%i %s", copy, strempty(c));
- }
-
- 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);
-
- 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, "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, "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, "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, "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, "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, "Failed to parse main-pid-known value: %s", value);
- else
- s->main_pid_known = b;
- } else if (streq(key, "bus-name-good")) {
- int b;
-
- b = parse_boolean(value);
- if (b < 0)
- log_unit_debug(u, "Failed to parse bus-name-good value: %s", value);
- else
- s->bus_name_good = b;
- } else if (streq(key, "bus-name-owner")) {
- r = free_and_strdup(&s->bus_name_owner, value);
- if (r < 0)
- log_unit_error_errno(u, r, "Unable to deserialize current bus owner %s: %m", value);
- } else if (streq(key, "status-text")) {
- char *t;
-
- r = cunescape(value, 0, &t);
- if (r < 0)
- log_unit_debug_errno(u, r, "Failed to unescape status text: %s", value);
- 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, "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, "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, "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")) {
- const char *fdv;
- size_t pf;
- int fd;
-
- pf = strcspn(value, WHITESPACE);
- fdv = strndupa(value, pf);
-
- if (safe_atoi(fdv, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u, "Failed to parse fd-store-fd value: %s", value);
- else {
- _cleanup_free_ char *t = NULL;
- const char *fdn;
-
- fdn = value + pf;
- fdn += strspn(fdn, WHITESPACE);
- (void) cunescape(fdn, 0, &t);
-
- r = service_add_fd_store(s, fd, t);
- if (r < 0)
- log_unit_error_errno(u, 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, "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, "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, "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, "Failed to parse forbid-restart value: %s", value);
- else
- s->forbid_restart = b;
- } else if (streq(key, "stdin-fd")) {
- int fd;
-
- if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u, "Failed to parse stdin-fd value: %s", value);
- else {
- asynchronous_close(s->stdin_fd);
- s->stdin_fd = fdset_remove(fds, fd);
- s->exec_context.stdio_as_fds = true;
- }
- } else if (streq(key, "stdout-fd")) {
- int fd;
-
- if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u, "Failed to parse stdout-fd value: %s", value);
- else {
- asynchronous_close(s->stdout_fd);
- s->stdout_fd = fdset_remove(fds, fd);
- s->exec_context.stdio_as_fds = true;
- }
- } else if (streq(key, "stderr-fd")) {
- int fd;
-
- if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u, "Failed to parse stderr-fd value: %s", value);
- else {
- asynchronous_close(s->stderr_fd);
- s->stderr_fd = fdset_remove(fds, fd);
- s->exec_context.stdio_as_fds = true;
- }
- } else
- log_unit_debug(u, "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;
-}
-
-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), "Setting watch for PID file %s", 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), "Trying to read PID file %s in case it changed", s->pid_file_pathspec->path);
- service_retry_pid_file(s);
-
- return 0;
-fail:
- log_unit_error_errno(UNIT(s), r, "Failed to set a watch for PID file %s: %m", 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), "inotify event");
-
- 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, "cgroup is empty");
-
- 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, "Daemon never wrote its PID file. Failing.");
-
- 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_struct(f == SERVICE_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
- LOG_UNIT_ID(u),
- LOG_UNIT_MESSAGE(u, "Main process exited, code=%s, status=%i/%s",
- 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, "Running next main command for state %s.", 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, f == SERVICE_SUCCESS ? LOG_DEBUG : LOG_NOTICE, 0,
- "Control process exited, code=%s status=%i",
- 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, "Running next control command for state %s.", 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, "Got final SIGCHLD for state %s.", 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
- (void) service_search_main_pid(s);
-
- service_enter_start_post(s);
- break;
-
- case SERVICE_START_POST:
- if (f != SERVICE_SUCCESS) {
- service_enter_signal(s, SERVICE_STOP_SIGTERM, 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
- (void) 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);
- (void) 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), "%s operation timed out. Terminating.", 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), "Start-post operation timed out. Stopping.");
- service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
- break;
-
- case SERVICE_RUNNING:
- log_unit_warning(UNIT(s), "Service reached runtime time limit. Stopping.");
- service_enter_stop(s, SERVICE_FAILURE_TIMEOUT);
- break;
-
- case SERVICE_RELOAD:
- log_unit_warning(UNIT(s), "Reload operation timed out. Killing reload process.");
- service_kill_control_processes(s);
- s->reload_result = SERVICE_FAILURE_TIMEOUT;
- service_enter_running(s, SERVICE_SUCCESS);
- break;
-
- case SERVICE_STOP:
- log_unit_warning(UNIT(s), "Stopping timed out. Terminating.");
- service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
- break;
-
- case SERVICE_STOP_SIGABRT:
- log_unit_warning(UNIT(s), "State 'stop-sigabrt' timed out. Terminating.");
- service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
- break;
-
- case SERVICE_STOP_SIGTERM:
- if (s->kill_context.send_sigkill) {
- log_unit_warning(UNIT(s), "State 'stop-sigterm' timed out. Killing.");
- service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT);
- } else {
- log_unit_warning(UNIT(s), "State 'stop-sigterm' timed out. Skipping SIGKILL.");
- 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), "Processes still around after SIGKILL. Ignoring.");
- service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT);
- break;
-
- case SERVICE_STOP_POST:
- log_unit_warning(UNIT(s), "State 'stop-post' timed out. Terminating.");
- 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), "State 'stop-final-sigterm' timed out. Killing.");
- service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_FAILURE_TIMEOUT);
- } else {
- log_unit_warning(UNIT(s), "State 'stop-final-sigterm' timed out. Skipping SIGKILL. Entering failed mode.");
- service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, false);
- }
-
- break;
-
- case SERVICE_FINAL_SIGKILL:
- log_unit_warning(UNIT(s), "Processes still around after final SIGKILL. Entering failed mode.");
- service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, true);
- break;
-
- case SERVICE_AUTO_RESTART:
- log_unit_info(UNIT(s),
- s->restart_usec > 0 ?
- "Service hold-off time over, scheduling restart." :
- "Service has no hold-off time, scheduling restart.");
- 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), "Watchdog timeout (limit %s)!",
- 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, ", ");
-
- if (s->notify_access == NOTIFY_NONE) {
- log_unit_warning(u, "Got notification message from PID "PID_FMT", but reception is disabled.", pid);
- return;
- } else if (s->notify_access == NOTIFY_MAIN && pid != s->main_pid) {
- if (s->main_pid != 0)
- log_unit_warning(u, "Got notification message from PID "PID_FMT", but reception only permitted for main PID "PID_FMT, pid, s->main_pid);
- else
- log_unit_debug(u, "Got notification message from PID "PID_FMT", but reception only permitted for main PID which is currently not known", pid);
- return;
- } else
- log_unit_debug(u, "Got notification message from PID "PID_FMT" (%s)", pid, isempty(cc) ? "n/a" : cc);
-
- /* 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, "Failed to parse MAINPID= field in notification message: %s", e);
- else {
- service_set_main_pid(s, pid);
- unit_watch_pid(UNIT(s), pid);
- notify_dbus = true;
- }
- }
-
- /* Interpret RELOADING= */
- if (strv_find(tags, "RELOADING=1")) {
-
- 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")) {
-
- 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")) {
-
- 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, "Status message in notification message is not UTF-8 clean.");
- else {
- 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, "Failed to parse ERRNO= field in notification message: %s", e);
- else {
- if (s->status_errno != status_errno) {
- s->status_errno = status_errno;
- notify_dbus = true;
- }
- }
- }
-
- /* Interpret WATCHDOG= */
- if (strv_find(tags, "WATCHDOG=1"))
- service_reset_watchdog(s);
-
- if (strv_find(tags, "FDSTORE=1")) {
- const char *name;
-
- name = strv_find_startswith(tags, "FDNAME=");
- if (name && !fdname_is_valid(name)) {
- log_unit_warning(u, "Passed FDNAME= name is invalid, ignoring.");
- name = NULL;
- }
-
- service_add_fd_store_set(s, fds, name);
- }
-
- /* Notify clients about changed status or main pid */
- if (notify_dbus)
- unit_add_to_dbus_queue(u);
-}
-
-static int service_get_timeout(Unit *u, usec_t *timeout) {
- Service *s = SERVICE(u);
- uint64_t t;
- int r;
-
- if (!s->timer_event_source)
- return 0;
-
- r = sd_event_source_get_time(s->timer_event_source, &t);
- if (r < 0)
- return r;
- if (t == USEC_INFINITY)
- return 0;
-
- *timeout = t;
- 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, "D-Bus name %s changed owner from %s to %s", name, old_owner, new_owner);
- else if (old_owner)
- log_unit_debug(u, "D-Bus name %s no longer registered by %s", name, old_owner);
- else
- log_unit_debug(u, "D-Bus name %s now registered by %s", name, new_owner);
-
- s->bus_name_good = !!new_owner;
-
- /* Track the current owner, so we can reconstruct changes after a daemon reload */
- r = free_and_strdup(&s->bus_name_owner, new_owner);
- if (r < 0) {
- log_unit_error_errno(u, r, "Unable to set new bus name owner %s: %m", new_owner);
- return;
- }
-
- 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_(sd_bus_creds_unrefp) 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, "D-Bus name %s is now owned by process %u", 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, true, &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;
-}
-
-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_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",
-};
-
-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,
-
- .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_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.",
- },
- .finished_stop_job = {
- [JOB_DONE] = "Stopped %s.",
- [JOB_FAILED] = "Stopped (with error) %s.",
- },
- },
-};
diff --git a/src/core/service.h b/src/core/service.h
deleted file mode 100644
index d342e000bb..0000000000
--- a/src/core/service.h
+++ /dev/null
@@ -1,220 +0,0 @@
-#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 "exit-status.h"
-#include "kill.h"
-#include "path.h"
-#include "ratelimit.h"
-
-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_RESULT_MAX,
- _SERVICE_RESULT_INVALID = -1
-} ServiceResult;
-
-struct ServiceFDStore {
- Service *service;
-
- int fd;
- char *fdname;
- 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;
- usec_t runtime_max_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 *bus_name_owner; /* unique name of the current owner */
-
- char *status_text;
- int status_errno;
-
- FailureAction failure_action;
-
- 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;
-
- char *usb_function_descriptors;
- char *usb_function_strings;
-
- int stdin_fd;
- int stdout_fd;
- int stderr_fd;
-};
-
-extern const UnitVTable service_vtable;
-
-int service_set_socket_fd(Service *s, int fd, struct Socket *socket, bool selinux_context_net);
-
-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 59ebdc7219..0000000000
--- a/src/core/show-status.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2014 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "alloc-util.h"
-#include "fd-util.h"
-#include "io-util.h"
-#include "parse-util.h"
-#include "show-status.h"
-#include "string-util.h"
-#include "terminal-util.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;
-}
-
-int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) {
- static const char status_indent[] = " "; /* "[" STATUS "] " */
- _cleanup_free_ char *s = NULL;
- _cleanup_close_ int fd = -1;
- struct iovec iovec[6] = {};
- int n = 0;
- static bool prev_ephemeral;
-
- assert(format);
-
- /* This is independent of logging, as status messages are
- * optional and go exclusively to the console. */
-
- if (vasprintf(&s, format, ap) < 0)
- return log_oom();
-
- fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
- if (fd < 0)
- return fd;
-
- if (ellipse) {
- char *e;
- size_t emax, sl;
- int c;
-
- c = fd_columns(fd);
- if (c <= 0)
- c = 80;
-
- sl = status ? sizeof(status_indent)-1 : 0;
-
- emax = c - sl - 1;
- if (emax < 3)
- emax = 3;
-
- e = ellipsize(s, emax, 50);
- if (e) {
- free(s);
- s = e;
- }
- }
-
- if (prev_ephemeral)
- IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE);
- prev_ephemeral = ephemeral;
-
- if (status) {
- if (!isempty(status)) {
- IOVEC_SET_STRING(iovec[n++], "[");
- IOVEC_SET_STRING(iovec[n++], status);
- IOVEC_SET_STRING(iovec[n++], "] ");
- } else
- IOVEC_SET_STRING(iovec[n++], status_indent);
- }
-
- IOVEC_SET_STRING(iovec[n++], s);
- if (!ephemeral)
- IOVEC_SET_STRING(iovec[n++], "\n");
-
- if (writev(fd, iovec, n) < 0)
- return -errno;
-
- return 0;
-}
-
-int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) {
- va_list ap;
- int r;
-
- assert(format);
-
- va_start(ap, format);
- r = status_vprintf(status, ellipse, ephemeral, format, ap);
- va_end(ap);
-
- return r;
-}
diff --git a/src/core/show-status.h b/src/core/show-status.h
deleted file mode 100644
index 9a29e72645..0000000000
--- a/src/core/show-status.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2014 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-
-#include "macro.h"
-
-/* 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);
-
-int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) _printf_(4,0);
-int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) _printf_(4,5);
diff --git a/src/core/shutdown.c b/src/core/shutdown.c
deleted file mode 100644
index 6296b4c94a..0000000000
--- a/src/core/shutdown.c
+++ /dev/null
@@ -1,435 +0,0 @@
-/***
- 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 <getopt.h>
-#include <linux/reboot.h>
-#include <signal.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <sys/mman.h>
-#include <sys/mount.h>
-#include <sys/reboot.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "alloc-util.h"
-#include "cgroup-util.h"
-#include "def.h"
-#include "fileio.h"
-#include "killall.h"
-#include "log.h"
-#include "missing.h"
-#include "parse-util.h"
-#include "process-util.h"
-#include "string-util.h"
-#include "switch-root.h"
-#include "terminal-util.h"
-#include "umount.h"
-#include "util.h"
-#include "virt.h"
-#include "watchdog.h"
-
-#define FINALIZE_ATTEMPTS 50
-
-static char* arg_verb;
-static uint8_t arg_exit_code;
-
-static int parse_argv(int argc, char *argv[]) {
- enum {
- ARG_LOG_LEVEL = 0x100,
- ARG_LOG_TARGET,
- ARG_LOG_COLOR,
- ARG_LOG_LOCATION,
- ARG_EXIT_CODE,
- };
-
- 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 },
- { "exit-code", required_argument, NULL, ARG_EXIT_CODE },
- {}
- };
-
- 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 ARG_EXIT_CODE:
- r = safe_atou8(optarg, &arg_exit_code);
- if (r < 0)
- log_error("Failed to parse exit code %s, ignoring", optarg);
-
- 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 if (streq(arg_verb, "exit"))
- cmd = 0; /* ignored, just checking that arg_verb is valid */
- 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() > 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();
-
- if (streq(arg_verb, "exit")) {
- if (in_container)
- exit(arg_exit_code);
- else {
- /* We cannot exit() on the host, fallback on another
- * method. */
- cmd = RB_POWER_OFF;
- }
- }
-
- 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);
- }
-
- r = log_error_errno(errno, "Failed to invoke reboot(): %m");
-
- 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 d65364c6f4..0000000000
--- a/src/core/slice.c
+++ /dev/null
@@ -1,339 +0,0 @@
-/***
- 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 "alloc-util.h"
-#include "dbus-slice.h"
-#include "log.h"
-#include "slice.h"
-#include "special.h"
-#include "string-util.h"
-#include "strv.h"
-#include "unit-name.h"
-#include "unit.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);
-
- if (!UNIT(s)->default_dependencies)
- return 0;
-
- /* 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) {
- _cleanup_free_ char *parent = NULL;
- int r;
-
- assert(s);
-
- if (UNIT(s)->load_state != UNIT_LOADED)
- return 0;
-
- if (!slice_name_is_valid(UNIT(s)->id)) {
- log_unit_error(UNIT(s), "Slice name %s is not valid. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
-
- r = slice_build_parent_slice(UNIT(s)->id, &parent);
- if (r < 0)
- return log_unit_error_errno(UNIT(s), r, "Failed to determine parent slice: %m");
-
- if (parent ? !unit_has_name(UNIT_DEREF(UNIT(s)->slice), parent) : UNIT_ISSET(UNIT(s)->slice)) {
- log_unit_error(UNIT(s), "Located outside of parent slice. Refusing.");
- return -EINVAL;
- }
-
- return 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;
-
- r = slice_add_default_dependencies(s);
- if (r < 0)
- return r;
- }
-
- return slice_verify(s);
-}
-
-static int slice_coldplug(Unit *u) {
- 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 void slice_enumerate(Manager *m) {
- Unit *u;
- int r;
-
- assert(m);
-
- u = manager_get_unit(m, SPECIAL_ROOT_SLICE);
- if (!u) {
- u = unit_new(m, sizeof(Slice));
- if (!u) {
- log_oom();
- return;
- }
-
- r = unit_add_name(u, SPECIAL_ROOT_SLICE);
- if (r < 0) {
- unit_free(u);
- log_error_errno(r, "Failed to add -.slice name");
- return;
- }
- }
-
- u->default_dependencies = false;
- u->no_gc = true;
- u->ignore_on_isolate = true;
- u->refuse_manual_start = true;
- u->refuse_manual_stop = true;
- SLICE(u)->deserialized_state = SLICE_ACTIVE;
-
- if (!u->description)
- u->description = strdup("Root Slice");
- if (!u->documentation)
- (void) strv_extend(&u->documentation, "man:systemd.special(7)");
-
- unit_add_to_load_queue(u);
- unit_add_to_dbus_queue(u);
-}
-
-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,
- .can_transient = 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_vtable = bus_slice_vtable,
- .bus_set_property = bus_slice_set_property,
- .bus_commit_properties = bus_slice_commit_properties,
-
- .enumerate = slice_enumerate,
-
- .status_message_formats = {
- .finished_start_job = {
- [JOB_DONE] = "Created slice %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 c9f3f61067..0000000000
--- a/src/core/slice.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#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;
-
-struct Slice {
- Unit meta;
-
- SliceState state, deserialized_state;
-
- CGroupContext cgroup_context;
-};
-
-extern const UnitVTable slice_vtable;
diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c
deleted file mode 100644
index 0c26e85460..0000000000
--- a/src/core/smack-setup.c
+++ /dev/null
@@ -1,346 +0,0 @@
-/***
- 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 <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "alloc-util.h"
-#include "dirent-util.h"
-#include "fd-util.h"
-#include "fileio.h"
-#include "log.h"
-#include "macro.h"
-#include "smack-setup.h"
-#include "string-util.h"
-#include "util.h"
-
-#ifdef HAVE_SMACK
-
-static int write_access2_rules(const char* srcdir) {
- _cleanup_close_ int load2_fd = -1, change_fd = -1;
- _cleanup_closedir_ DIR *dir = NULL;
- struct dirent *entry;
- char buf[NAME_MAX];
- int dfd = -1;
- int r = 0;
-
- load2_fd = open("/sys/fs/smackfs/load2", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
- if (load2_fd < 0) {
- if (errno != ENOENT)
- log_warning_errno(errno, "Failed to open '/sys/fs/smackfs/load2': %m");
- return -errno; /* negative error */
- }
-
- change_fd = open("/sys/fs/smackfs/change-rule", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
- if (change_fd < 0) {
- if (errno != ENOENT)
- log_warning_errno(errno, "Failed to open '/sys/fs/smackfs/change-rule': %m");
- return -errno; /* negative error */
- }
-
- /* write rules to load2 or change-rule 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;
-
- if (!dirent_is_file(entry))
- continue;
-
- 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)) {
-
- _cleanup_free_ char *sbj = NULL, *obj = NULL, *acc1 = NULL, *acc2 = NULL;
-
- if (isempty(truncate_nl(buf)))
- continue;
-
- /* if 3 args -> load rule : subject object access1 */
- /* if 4 args -> change rule : subject object access1 access2 */
- if (sscanf(buf, "%ms %ms %ms %ms", &sbj, &obj, &acc1, &acc2) < 3) {
- log_error_errno(errno, "Failed to parse rule '%s' in '%s', ignoring.", buf, entry->d_name);
- continue;
- }
-
- if (write(isempty(acc2) ? load2_fd : change_fd, buf, strlen(buf)) < 0) {
- if (r == 0)
- r = -errno;
- log_error_errno(errno, "Failed to write '%s' to '%s' in '%s'",
- buf, isempty(acc2) ? "/sys/fs/smackfs/load2" : "/sys/fs/smackfs/change-rule", entry->d_name);
- }
- }
- }
-
- return r;
-}
-
-static int write_cipso2_rules(const char* srcdir) {
- _cleanup_close_ int cipso2_fd = -1;
- _cleanup_closedir_ DIR *dir = NULL;
- struct dirent *entry;
- char buf[NAME_MAX];
- int dfd = -1;
- int r = 0;
-
- cipso2_fd = open("/sys/fs/smackfs/cipso2", O_RDWR|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
- if (cipso2_fd < 0) {
- if (errno != ENOENT)
- log_warning_errno(errno, "Failed to open '/sys/fs/smackfs/cipso2': %m");
- return -errno; /* negative error */
- }
-
- /* write rules to cipso2 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;
-
- if (!dirent_is_file(entry))
- continue;
-
- fd = openat(dfd, entry->d_name, O_RDONLY|O_CLOEXEC);
- if (fd < 0) {
- if (r == 0)
- r = -errno;
- log_error_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;
- }
-
- /* cipso2 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 (isempty(truncate_nl(buf)))
- continue;
-
- if (write(cipso2_fd, buf, strlen(buf)) < 0) {
- if (r == 0)
- r = -errno;
- log_error_errno(errno, "Failed to write '%s' to '/sys/fs/smackfs/cipso2' in '%s'",
- buf, entry->d_name);
- break;
- }
- }
- }
-
- return r;
-}
-
-static int write_netlabel_rules(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("/sys/fs/smackfs/netlabel", "we");
- if (!dst) {
- if (errno != ENOENT)
- log_warning_errno(errno, "Failed to open /sys/fs/smackfs/netlabel: %m");
- 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_errno(errno, "Failed to write line to /sys/fs/smackfs/netlabel");
- break;
- }
- if (fflush(dst)) {
- if (r == 0)
- r = -errno;
- log_error_errno(errno, "Failed to flush writes to /sys/fs/smackfs/netlabel: %m");
- break;
- }
- }
- }
-
- return r;
-}
-
-#endif
-
-int mac_smack_setup(bool *loaded_policy) {
-
-#ifdef HAVE_SMACK
-
- int r;
-
- assert(loaded_policy);
-
- r = write_access2_rules("/etc/smack/accesses.d/");
- switch(r) {
- case -ENOENT:
- log_debug("Smack is not enabled in the kernel.");
- return 0;
- case ENOENT:
- log_debug("Smack access rules directory '/etc/smack/accesses.d/' not found");
- return 0;
- case 0:
- log_info("Successfully loaded Smack policies.");
- break;
- default:
- log_warning_errno(r, "Failed to load Smack access rules, ignoring: %m");
- return 0;
- }
-
-#ifdef SMACK_RUN_LABEL
- r = write_string_file("/proc/self/attr/current", SMACK_RUN_LABEL, 0);
- if (r < 0)
- log_warning_errno(r, "Failed to set SMACK label \"" SMACK_RUN_LABEL "\" on self: %m");
- r = write_string_file("/sys/fs/smackfs/ambient", SMACK_RUN_LABEL, 0);
- if (r < 0)
- log_warning_errno(r, "Failed to set SMACK ambient label \"" SMACK_RUN_LABEL "\": %m");
- r = write_string_file("/sys/fs/smackfs/netlabel",
- "0.0.0.0/0 " SMACK_RUN_LABEL, 0);
- if (r < 0)
- log_warning_errno(r, "Failed to set SMACK netlabel rule \"0.0.0.0/0 " SMACK_RUN_LABEL "\": %m");
- r = write_string_file("/sys/fs/smackfs/netlabel", "127.0.0.1 -CIPSO", 0);
- if (r < 0)
- log_warning_errno(r, "Failed to set SMACK netlabel rule \"127.0.0.1 -CIPSO\": %m");
-#endif
-
- r = write_cipso2_rules("/etc/smack/cipso.d/");
- 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 '/etc/smack/cipso.d/' not found");
- break;
- case 0:
- log_info("Successfully loaded Smack/CIPSO policies.");
- break;
- default:
- log_warning_errno(r, "Failed to load Smack/CIPSO access rules, ignoring: %m");
- break;
- }
-
- r = write_netlabel_rules("/etc/smack/netlabel.d/");
- switch(r) {
- case -ENOENT:
- log_debug("Smack/CIPSO is not enabled in the kernel.");
- return 0;
- case ENOENT:
- log_debug("Smack network host rules directory '/etc/smack/netlabel.d/' not found");
- break;
- case 0:
- log_info("Successfully loaded Smack network host rules.");
- break;
- default:
- log_warning_errno(r, "Failed to load Smack network host rules: %m, ignoring.");
- break;
- }
-
- *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 78164c85e6..0000000000
--- a/src/core/smack-setup.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#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/socket.c b/src/core/socket.c
deleted file mode 100644
index 976687af41..0000000000
--- a/src/core/socket.c
+++ /dev/null
@@ -1,2866 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <arpa/inet.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <mqueue.h>
-#include <netinet/tcp.h>
-#include <signal.h>
-#include <sys/epoll.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <linux/sctp.h>
-
-#include "sd-event.h"
-#include "alloc-util.h"
-#include "bus-error.h"
-#include "bus-util.h"
-#include "copy.h"
-#include "dbus-socket.h"
-#include "def.h"
-#include "exit-status.h"
-#include "fd-util.h"
-#include "formats-util.h"
-#include "label.h"
-#include "log.h"
-#include "missing.h"
-#include "mkdir.h"
-#include "parse-util.h"
-#include "path-util.h"
-#include "process-util.h"
-#include "selinux-util.h"
-#include "signal-util.h"
-#include "smack-util.h"
-#include "socket.h"
-#include "special.h"
-#include "string-table.h"
-#include "string-util.h"
-#include "strv.h"
-#include "unit-name.h"
-#include "unit-printf.h"
-#include "unit.h"
-#include "user-util.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;
-}
-
-static void socket_cleanup_fd_list(SocketPort *p) {
- assert(p);
-
- close_many(p->auxiliary_fds, p->n_auxiliary_fds);
- p->auxiliary_fds = mfree(p->auxiliary_fds);
- p->n_auxiliary_fds = 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);
-
- socket_cleanup_fd_list(p);
- 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);
-
- s->tcp_congestion = mfree(s->tcp_congestion);
- s->bind_to_device = mfree(s->bind_to_device);
-
- s->smack = mfree(s->smack);
- s->smack_ip_in = mfree(s->smack_ip_in);
- s->smack_ip_out = mfree(s->smack_ip_out);
-
- strv_free(s->symlinks);
-
- s->user = mfree(s->user);
- s->group = mfree(s->group);
-
- s->fdname = mfree(s->fdname);
-
- s->timer_event_source = sd_event_source_unref(s->timer_event_source);
-}
-
-static int socket_arm_timer(Socket *s, usec_t usec) {
- int r;
-
- assert(s);
-
- if (s->timer_event_source) {
- r = sd_event_source_set_time(s->timer_event_source, usec);
- if (r < 0)
- return r;
-
- return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
- }
-
- if (usec == USEC_INFINITY)
- return 0;
-
- r = sd_event_add_time(
- UNIT(s)->manager->event,
- &s->timer_event_source,
- CLOCK_MONOTONIC,
- usec, 0,
- socket_dispatch_timer, s);
- if (r < 0)
- return r;
-
- (void) sd_event_source_set_description(s->timer_event_source, "socket-timer");
-
- return 0;
-}
-
-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))
- return 0;
-
- if (!s->accept)
- return 0;
-
- r = unit_name_to_prefix(UNIT(s)->id, &prefix);
- if (r < 0)
- return r;
-
- 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 (IN_SET(p->type, SOCKET_FIFO, SOCKET_SPECIAL, SOCKET_USB_FUNCTION))
- 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, UNIT_BINDS_TO);
-}
-
-static int socket_add_default_dependencies(Socket *s) {
- int r;
- assert(s);
-
- if (!UNIT(s)->default_dependencies)
- return 0;
-
- 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 == MANAGER_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_set_default_slice(u);
- if (r < 0)
- return r;
- }
-
- 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), "Unit lacks Listen setting. Refusing.");
- return -EINVAL;
- }
-
- if (s->accept && have_non_accept_socket(s)) {
- log_unit_error(UNIT(s), "Unit configured for accepting sockets, but sockets are non-accepting. Refusing.");
- return -EINVAL;
- }
-
- if (s->accept && s->max_connections <= 0) {
- log_unit_error(UNIT(s), "MaxConnection= setting too small. Refusing.");
- return -EINVAL;
- }
-
- if (s->accept && UNIT_DEREF(s->service)) {
- log_unit_error(UNIT(s), "Explicit service configuration for accepting socket units not supported. Refusing.");
- return -EINVAL;
- }
-
- if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) {
- log_unit_error(UNIT(s), "Unit has PAM enabled. Kill mode must be set to 'control-group'. Refusing.");
- return -EINVAL;
- }
-
- if (!strv_isempty(s->symlinks) && !socket_find_symlink_target(s)) {
- log_unit_error(UNIT(s), "Unit has symlinks set but none or more than one node in the file system. Refusing.");
- return -EINVAL;
- }
-
- return 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"
- "%sWritable: %s\n"
- "%sFDName: %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->writable),
- prefix, socket_fdname(s),
- 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;
-
- r = socket_address_print(&p->address, &k);
- if (r < 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_USB_FUNCTION)
- fprintf(f, "%sListenUSBFunction: %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);
- socket_cleanup_fd_list(p);
-
- /* 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_errno(UNIT(s), errno, "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_errno(UNIT(s), errno, "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_errno(UNIT(s), errno, "TCP_KEEPINTVL failed: %m");
- }
-
- if (s->keep_alive_cnt) {
- int value = s->keep_alive_cnt;
- if (setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &value, sizeof(value)) < 0)
- log_unit_warning_errno(UNIT(s), errno, "TCP_KEEPCNT failed: %m");
- }
-
- if (s->defer_accept) {
- int value = s->defer_accept / USEC_PER_SEC;
- if (setsockopt(fd, SOL_TCP, TCP_DEFER_ACCEPT, &value, sizeof(value)) < 0)
- log_unit_warning_errno(UNIT(s), errno, "TCP_DEFER_ACCEPT failed: %m");
- }
-
- if (s->no_delay) {
- int b = s->no_delay;
-
- if (s->socket_protocol == IPPROTO_SCTP) {
- if (setsockopt(fd, SOL_SCTP, SCTP_NODELAY, &b, sizeof(b)) < 0)
- log_unit_warning_errno(UNIT(s), errno, "SCTP_NODELAY failed: %m");
- } else {
- if (setsockopt(fd, SOL_TCP, TCP_NODELAY, &b, sizeof(b)) < 0)
- log_unit_warning_errno(UNIT(s), errno, "TCP_NODELAY failed: %m");
- }
- }
-
- if (s->broadcast) {
- int one = 1;
- if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)) < 0)
- log_unit_warning_errno(UNIT(s), errno, "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_errno(UNIT(s), errno, "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_errno(UNIT(s), errno, "SO_PASSSEC failed: %m");
- }
-
- if (s->priority >= 0)
- if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &s->priority, sizeof(s->priority)) < 0)
- log_unit_warning_errno(UNIT(s), errno, "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_errno(UNIT(s), errno, "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_errno(UNIT(s), errno, "SO_SNDBUF failed: %m");
- }
-
- if (s->mark >= 0)
- if (setsockopt(fd, SOL_SOCKET, SO_MARK, &s->mark, sizeof(s->mark)) < 0)
- log_unit_warning_errno(UNIT(s), errno, "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_errno(UNIT(s), errno, "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_errno(UNIT(s), errno, "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_errno(UNIT(s), errno, "TCP_CONGESTION failed: %m");
-
- if (s->smack_ip_in) {
- r = mac_smack_apply_fd(fd, SMACK_ATTR_IPIN, s->smack_ip_in);
- if (r < 0)
- log_unit_error_errno(UNIT(s), r, "mac_smack_apply_ip_in_fd: %m");
- }
-
- if (s->smack_ip_out) {
- r = mac_smack_apply_fd(fd, SMACK_ATTR_IPOUT, s->smack_ip_out);
- if (r < 0)
- log_unit_error_errno(UNIT(s), 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_errno(UNIT(s), errno, "Setting pipe size failed, ignoring: %m");
-
- if (s->smack) {
- r = mac_smack_apply_fd(fd, SMACK_ATTR_ACCESS, s->smack);
- if (r < 0)
- log_unit_error_errno(UNIT(s), r, "SMACK relabelling failed, ignoring: %m");
- }
-}
-
-static int fifo_address_create(
- const char *path,
- mode_t directory_mode,
- mode_t socket_mode) {
-
- _cleanup_close_ int fd = -1;
- mode_t old_mask;
- struct stat st;
- int r;
-
- assert(path);
-
- mkdir_parents_label(path, directory_mode);
-
- r = mac_selinux_create_file_prepare(path, S_IFIFO);
- if (r < 0)
- return r;
-
- /* Enforce the right access mode for the fifo */
- old_mask = umask(~ socket_mode);
-
- /* Include the original umask in our mask */
- (void) umask(~socket_mode | old_mask);
-
- r = mkfifo(path, socket_mode);
- (void) umask(old_mask);
-
- if (r < 0 && errno != EEXIST) {
- r = -errno;
- goto fail;
- }
-
- fd = open(path, O_RDWR | O_CLOEXEC | O_NOCTTY | O_NONBLOCK | O_NOFOLLOW);
- if (fd < 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;
- }
-
- r = fd;
- fd = -1;
-
- return r;
-
-fail:
- mac_selinux_create_file_clear();
- return r;
-}
-
-static int special_address_create(const char *path, bool writable) {
- _cleanup_close_ int fd = -1;
- struct stat st;
- int r;
-
- assert(path);
-
- fd = open(path, (writable ? O_RDWR : O_RDONLY)|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW);
- if (fd < 0)
- return -errno;
-
- if (fstat(fd, &st) < 0)
- return -errno;
-
- /* Check whether this is a /proc, /sys or /dev file or char device */
- if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode))
- return -EEXIST;
-
- r = fd;
- fd = -1;
-
- return r;
-}
-
-static int usbffs_address_create(const char *path) {
- _cleanup_close_ int fd = -1;
- struct stat st;
- int r;
-
- assert(path);
-
- fd = open(path, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW);
- if (fd < 0)
- return -errno;
-
- if (fstat(fd, &st) < 0)
- return -errno;
-
- /* Check whether this is a regular file (ffs endpoint)*/
- if (!S_ISREG(st.st_mode))
- return -EEXIST;
-
- r = fd;
- fd = -1;
-
- return r;
-}
-
-static int mq_address_create(
- const char *path,
- mode_t mq_mode,
- long maxmsg,
- long msgsize) {
-
- _cleanup_close_ int fd = -1;
- struct stat st;
- mode_t old_mask;
- struct mq_attr _attr, *attr = NULL;
- int r;
-
- assert(path);
-
- if (maxmsg > 0 && msgsize > 0) {
- _attr = (struct mq_attr) {
- .mq_flags = O_NONBLOCK,
- .mq_maxmsg = maxmsg,
- .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 */
- (void) umask(~mq_mode | old_mask);
- fd = mq_open(path, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_CREAT, mq_mode, attr);
- (void) umask(old_mask);
-
- if (fd < 0)
- return -errno;
-
- if (fstat(fd, &st) < 0)
- return -errno;
-
- if ((st.st_mode & 0777) != (mq_mode & ~old_mask) ||
- st.st_uid != getuid() ||
- st.st_gid != getgid())
- return -EEXIST;
-
- r = fd;
- fd = -1;
-
- 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 usbffs_write_descs(int fd, Service *s) {
- int r;
-
- if (!s->usb_function_descriptors || !s->usb_function_strings)
- return -EINVAL;
-
- r = copy_file_fd(s->usb_function_descriptors, fd, false);
- if (r < 0)
- return r;
-
- return copy_file_fd(s->usb_function_strings, fd, false);
-}
-
-static int usbffs_select_ep(const struct dirent *d) {
- return d->d_name[0] != '.' && !streq(d->d_name, "ep0");
-}
-
-static int usbffs_dispatch_eps(SocketPort *p) {
- _cleanup_free_ struct dirent **ent = NULL;
- _cleanup_free_ char *path = NULL;
- int r, i, n, k;
-
- path = dirname_malloc(p->path);
- if (!path)
- return -ENOMEM;
-
- r = scandir(path, &ent, usbffs_select_ep, alphasort);
- if (r < 0)
- return -errno;
-
- n = r;
- p->auxiliary_fds = new(int, n);
- if (!p->auxiliary_fds)
- return -ENOMEM;
-
- p->n_auxiliary_fds = n;
-
- k = 0;
- for (i = 0; i < n; ++i) {
- _cleanup_free_ char *ep = NULL;
-
- ep = path_make_absolute(ent[i]->d_name, path);
- if (!ep)
- return -ENOMEM;
-
- path_kill_slashes(ep);
-
- r = usbffs_address_create(ep);
- if (r < 0)
- goto fail;
-
- p->auxiliary_fds[k] = r;
-
- ++k;
- free(ent[i]);
- }
-
- return r;
-
-fail:
- close_many(p->auxiliary_fds, k);
- p->auxiliary_fds = mfree(p->auxiliary_fds);
- p->n_auxiliary_fds = 0;
-
- return r;
-}
-
-static int socket_open_fds(Socket *s) {
- _cleanup_(mac_selinux_freep) char *label = NULL;
- bool know_label = false;
- SocketPort *p;
- int r;
-
- assert(s);
-
- LIST_FOREACH(port, p, s->ports) {
-
- if (p->fd >= 0)
- continue;
-
- switch (p->type) {
-
- case 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;
- }
-
- /* Apply the socket protocol */
- switch(p->address.type) {
- case SOCK_STREAM:
- case SOCK_SEQPACKET:
- if (p->socket->socket_protocol == IPPROTO_SCTP)
- p->address.protocol = p->socket->socket_protocol;
- break;
- case SOCK_DGRAM:
- if (p->socket->socket_protocol == IPPROTO_UDPLITE)
- p->address.protocol = p->socket->socket_protocol;
- break;
- }
-
- r = socket_address_listen(
- &p->address,
- SOCK_CLOEXEC|SOCK_NONBLOCK,
- s->backlog,
- s->bind_ipv6_only,
- s->bind_to_device,
- s->reuse_port,
- 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);
- break;
-
- case SOCKET_SPECIAL:
-
- p->fd = special_address_create(p->path, s->writable);
- if (p->fd < 0) {
- r = p->fd;
- goto rollback;
- }
- break;
-
- case SOCKET_FIFO:
-
- p->fd = fifo_address_create(
- p->path,
- s->directory_mode,
- s->socket_mode);
- if (p->fd < 0) {
- r = p->fd;
- goto rollback;
- }
-
- socket_apply_fifo_options(s, p->fd);
- socket_symlink(s);
- break;
-
- case SOCKET_MQUEUE:
-
- p->fd = mq_address_create(
- p->path,
- s->socket_mode,
- s->mq_maxmsg,
- s->mq_msgsize);
- if (p->fd < 0) {
- r = p->fd;
- goto rollback;
- }
- break;
-
- case SOCKET_USB_FUNCTION:
-
- p->fd = usbffs_address_create(p->path);
- if (p->fd < 0) {
- r = p->fd;
- goto rollback;
- }
-
- r = usbffs_write_descs(p->fd, SERVICE(UNIT_DEREF(s->service)));
- if (r < 0)
- goto rollback;
-
- r = usbffs_dispatch_eps(p);
- if (r < 0)
- goto rollback;
-
- break;
-
- default:
- assert_not_reached("Unknown port type");
- }
- }
-
- return 0;
-
-rollback:
- socket_close_fds(s);
- 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_errno(UNIT(s), r, "Failed to disable event source: %m");
- }
-}
-
-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);
- if (r < 0)
- goto fail;
- } else {
- r = sd_event_add_io(UNIT(s)->manager->event, &p->event_source, p->fd, EPOLLIN, socket_dispatch_io, p);
- if (r < 0)
- goto fail;
-
- (void) sd_event_source_set_description(p->event_source, "socket-port-io");
- }
- }
-
- return 0;
-
-fail:
- log_unit_warning_errno(UNIT(s), r, "Failed to watch listening fds: %m");
- 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), "Changed %s -> %s", socket_state_to_string(old_state), socket_state_to_string(state));
-
- unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
-}
-
-static int socket_coldplug(Unit *u) {
- Socket *s = SOCKET(u);
- int r;
-
- assert(s);
- assert(s->state == SOCKET_DEAD);
-
- if (s->deserialized_state == s->state)
- return 0;
-
- if (s->control_pid > 0 &&
- pid_is_unwaited(s->control_pid) &&
- 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)) {
-
- r = unit_watch_pid(UNIT(s), s->control_pid);
- if (r < 0)
- return r;
-
- r = socket_arm_timer(s, usec_add(u->state_change_timestamp.monotonic, s->timeout_usec));
- 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,
- .bus_endpoint_fd = -1,
- .stdin_fd = -1,
- .stdout_fd = -1,
- .stderr_fd = -1,
- };
-
- 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)
- return r;
-
- r = socket_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec));
- if (r < 0)
- return r;
-
- r = unit_full_printf_strv(UNIT(s), c->argv, &argv);
- if (r < 0)
- return r;
-
- 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);
-
- r = exec_spawn(UNIT(s),
- c,
- &s->exec_context,
- &exec_params,
- s->exec_runtime,
- &pid);
- if (r < 0)
- return r;
-
- r = unit_watch_pid(UNIT(s), pid);
- if (r < 0)
- /* FIXME: we need to do something here */
- return r;
-
- *_pid = pid;
- return 0;
-}
-
-static int socket_chown(Socket *s, pid_t *_pid) {
- pid_t pid;
- int r;
-
- r = socket_arm_timer(s, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec));
- 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;
-
- (void) default_signals(SIGNALS_CRASH_HANDLER, SIGNALS_IGNORE, -1);
- (void) 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_errno(UNIT(s), r, "Failed to run 'stop-post' task: %m");
- 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, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec));
- 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), r, "Failed to kill processes: %m");
-
- 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), r, "Failed to run 'stop-pre' task: %m");
- 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), r, "Failed to watch sockets: %m");
- 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), r, "Failed to run 'start-post' task: %m");
- 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), r, "Failed to listen on sockets: %m");
- 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), r, "Failed to fork 'start-chown' task: %m");
- 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), r, "Failed to run 'start-pre' task: %m");
- 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_(sd_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), "Suppressing connection request since unit stop is scheduled.");
-
- 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), r, "Failed to listen on sockets: %m");
- socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
- return;
- }
-
- r = socket_watch_fds(s);
- if (r < 0) {
- log_unit_warning_errno(UNIT(s), r, "Failed to watch sockets: %m");
- 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), "Service to activate vanished, refusing activation.");
- r = -ENOENT;
- goto fail;
- }
-
- r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT_DEREF(s->service), JOB_REPLACE, &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), "Too many incoming connections (%u)", 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;
- }
-
- r = unit_name_to_prefix(UNIT(s)->id, &prefix);
- if (r < 0)
- goto fail;
-
- r = unit_name_build(prefix, instance, ".service", &name);
- if (r < 0)
- 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, &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), "Failed to queue service startup job (Maybe the service file is missing or not a %s unit?): %s",
- 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), r, "Failed to run next task: %m");
-
- 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, "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, "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 if (p->type == SOCKET_USB_FUNCTION)
- unit_serialize_item_format(u, f, "ffs", "%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, "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, "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, "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, "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, "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, "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, "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, "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, "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, "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 if (streq(key, "ffs")) {
- int fd, skip = 0;
- SocketPort *p;
-
- if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd))
- log_unit_debug(u, "Failed to parse ffs value: %s", value);
- else {
-
- LIST_FOREACH(port, p, s->ports)
- if (p->type == SOCKET_USB_FUNCTION &&
- path_equal_or_files_same(p->path, value+skip))
- break;
-
- if (p) {
- safe_close(p->fd);
- p->fd = fdset_remove(fds, fd);
- }
- }
-
- } else
- log_unit_debug(UNIT(s), "Unknown serialization key: %s", key);
-
- return 0;
-}
-
-static void 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;
- }
- }
- }
-}
-
-_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";
-
- case SOCKET_USB_FUNCTION:
- return "USBFunction";
-
- 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), "Incoming traffic");
-
- if (revents != EPOLLIN) {
-
- if (revents & EPOLLHUP)
- log_unit_error(UNIT(p->socket), "Got POLLHUP on a listening socket. The service probably invoked shutdown() on it, and should better not do that.");
- else
- log_unit_error(UNIT(p->socket), "Got unexpected poll event (0x%x) on socket.", 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_errno(UNIT(p->socket), errno, "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, f == SOCKET_SUCCESS ? LOG_DEBUG : LOG_NOTICE, 0,
- "Control process exited, code=%s status=%i",
- 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, "Running next command for state %s", 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, "Got final SIGCHLD for state %s", 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), "Starting timed out. Terminating.");
- socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_TIMEOUT);
- break;
-
- case SOCKET_START_CHOWN:
- case SOCKET_START_POST:
- log_unit_warning(UNIT(s), "Starting timed out. Stopping.");
- socket_enter_stop_pre(s, SOCKET_FAILURE_TIMEOUT);
- break;
-
- case SOCKET_STOP_PRE:
- log_unit_warning(UNIT(s), "Stopping timed out. Terminating.");
- 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), "Stopping timed out. Killing.");
- socket_enter_signal(s, SOCKET_STOP_PRE_SIGKILL, SOCKET_FAILURE_TIMEOUT);
- } else {
- log_unit_warning(UNIT(s), "Stopping timed out. Skipping SIGKILL. Ignoring.");
- socket_enter_stop_post(s, SOCKET_FAILURE_TIMEOUT);
- }
- break;
-
- case SOCKET_STOP_PRE_SIGKILL:
- log_unit_warning(UNIT(s), "Processes still around after SIGKILL. Ignoring.");
- socket_enter_stop_post(s, SOCKET_FAILURE_TIMEOUT);
- break;
-
- case SOCKET_STOP_POST:
- log_unit_warning(UNIT(s), "Stopping timed out (2). Terminating.");
- 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), "Stopping timed out (2). Killing.");
- socket_enter_signal(s, SOCKET_FINAL_SIGKILL, SOCKET_FAILURE_TIMEOUT);
- } else {
- log_unit_warning(UNIT(s), "Stopping timed out (2). Skipping SIGKILL. Ignoring.");
- socket_enter_dead(s, SOCKET_FAILURE_TIMEOUT);
- }
- break;
-
- case SOCKET_FINAL_SIGKILL:
- log_unit_warning(UNIT(s), "Still around after SIGKILL (2). Entering failed mode.");
- 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) {
- int *rfds, k = 0, n = 0;
- SocketPort *p;
-
- assert(s);
- assert(fds);
-
- /* Called from the service code for requesting our fds */
-
- LIST_FOREACH(port, p, s->ports) {
- if (p->fd >= 0)
- n++;
- n += p->n_auxiliary_fds;
- }
-
- if (n <= 0) {
- *fds = NULL;
- return 0;
- }
-
- rfds = new(int, n);
- if (!rfds)
- return -ENOMEM;
-
- LIST_FOREACH(port, p, s->ports) {
- int i;
-
- if (p->fd >= 0)
- rfds[k++] = p->fd;
- for (i = 0; i < p->n_auxiliary_fds; ++i)
- rfds[k++] = p->auxiliary_fds[i];
- }
-
- assert(k == n);
-
- *fds = rfds;
- return n;
-}
-
-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;
-}
-
-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), "One connection closed, %u left.", s->n_connections);
-}
-
-static void socket_trigger_notify(Unit *u, Unit *other) {
- Socket *s = SOCKET(u);
-
- assert(u);
- assert(other);
-
- /* Don't propagate state changes from the service if we are
- already down or accepting connections */
- if (!IN_SET(s->state, SOCKET_RUNNING, SOCKET_LISTENING) || s->accept)
- return;
-
- if (other->start_limit_hit) {
- socket_enter_stop_pre(s, SOCKET_FAILURE_SERVICE_START_LIMIT_HIT);
- return;
- }
-
- if (other->load_state != UNIT_LOADED || other->type != UNIT_SERVICE)
- return;
-
- if (IN_SET(SERVICE(other)->state,
- SERVICE_DEAD, SERVICE_FAILED,
- SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
- SERVICE_AUTO_RESTART))
- socket_enter_listening(s);
-
- if (SERVICE(other)->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, usec_t *timeout) {
- Socket *s = SOCKET(u);
- usec_t t;
- int r;
-
- if (!s->timer_event_source)
- return 0;
-
- r = sd_event_source_get_time(s->timer_event_source, &t);
- if (r < 0)
- return r;
- if (t == USEC_INFINITY)
- return 0;
-
- *timeout = t;
- return 1;
-}
-
-char *socket_fdname(Socket *s) {
- assert(s);
-
- /* Returns the name to use for $LISTEN_NAMES. If the user
- * didn't specify anything specifically, use the socket unit's
- * name as fallback. */
-
- if (s->fdname)
- return s->fdname;
-
- return UNIT(s)->id;
-}
-
-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_START_LIMIT_HIT] = "service-start-limit-hit"
-};
-
-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_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_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 b537b026a7..0000000000
--- a/src/core/socket.h
+++ /dev/null
@@ -1,181 +0,0 @@
-#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 "mount.h"
-#include "service.h"
-#include "socket-util.h"
-
-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_USB_FUNCTION,
- _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_START_LIMIT_HIT,
- _SOCKET_RESULT_MAX,
- _SOCKET_RESULT_INVALID = -1
-} SocketResult;
-
-typedef struct SocketPort {
- Socket *socket;
-
- SocketType type;
- int fd;
- int *auxiliary_fds;
- int n_auxiliary_fds;
-
- 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;
- bool writable;
-
- int socket_protocol;
-
- /* 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;
-
- char *fdname;
-};
-
-/* Called from the service code when collecting fds */
-int socket_collect_fds(Socket *s, int **fds);
-
-/* Called from the service code when a per-connection service ended */
-void socket_connection_unref(Socket *s);
-
-void socket_free_ports(Socket *s);
-
-int socket_instantiate_service(Socket *s);
-
-char *socket_fdname(Socket *s);
-
-extern const UnitVTable socket_vtable;
-
-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_;
diff --git a/src/core/swap.c b/src/core/swap.c
deleted file mode 100644
index 1bf0c0a808..0000000000
--- a/src/core/swap.c
+++ /dev/null
@@ -1,1518 +0,0 @@
-/***
- 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 <sys/stat.h>
-#include <unistd.h>
-
-#include "libudev.h"
-
-#include "alloc-util.h"
-#include "dbus-swap.h"
-#include "escape.h"
-#include "exit-status.h"
-#include "fd-util.h"
-#include "formats-util.h"
-#include "fstab-util.h"
-#include "parse-util.h"
-#include "path-util.h"
-#include "process-util.h"
-#include "special.h"
-#include "string-table.h"
-#include "string-util.h"
-#include "swap.h"
-#include "udev-util.h"
-#include "unit-name.h"
-#include "unit.h"
-#include "virt.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;
-
- s->parameters_proc_swaps.what = mfree(s->parameters_proc_swaps.what);
-
- 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);
-
- s->devnode = mfree(s->devnode);
- }
-
- 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);
-
- s->what = mfree(s->what);
- s->parameters_fragment.what = mfree(s->parameters_fragment.what);
- s->parameters_fragment.options = mfree(s->parameters_fragment.options);
-
- 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, usec_t usec) {
- int r;
-
- assert(s);
-
- if (s->timer_event_source) {
- r = sd_event_source_set_time(s->timer_event_source, usec);
- if (r < 0)
- return r;
-
- return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
- }
-
- if (usec == USEC_INFINITY)
- return 0;
-
- r = sd_event_add_time(
- UNIT(s)->manager->event,
- &s->timer_event_source,
- CLOCK_MONOTONIC,
- usec, 0,
- swap_dispatch_timer, s);
- if (r < 0)
- return r;
-
- (void) sd_event_source_set_description(s->timer_event_source, "swap-timer");
-
- return 0;
-}
-
-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 == MANAGER_SYSTEM, UNIT_BINDS_TO);
- 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) {
- int r;
-
- assert(s);
-
- if (!UNIT(s)->default_dependencies)
- return 0;
-
- if (UNIT(s)->manager->running_as != MANAGER_SYSTEM)
- return 0;
-
- if (detect_container() > 0)
- return 0;
-
- /* swap units generated for the swap dev links are missing the
- * ordering dep against the swap target. */
- r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SWAP_TARGET, NULL, true);
- if (r < 0)
- return r;
-
- return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
-}
-
-static int swap_verify(Swap *s) {
- _cleanup_free_ char *e = NULL;
- int r;
-
- if (UNIT(s)->load_state != UNIT_LOADED)
- return 0;
-
- r = unit_name_from_path(s->what, ".swap", &e);
- if (r < 0)
- return log_unit_error_errno(UNIT(s), r, "Failed to generate unit name from path: %m");
-
- if (!unit_has_name(UNIT(s), e)) {
- log_unit_error(UNIT(s), "Value of What= and unit name do not match, not loading.");
- return -EINVAL;
- }
-
- if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) {
- log_unit_error(UNIT(s), "Unit has PAM enabled. Kill mode must be set to 'control-group'. Refusing to load.");
- return -EINVAL;
- }
-
- return 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 {
- r = unit_name_to_path(u->id, &s->what);
- if (r < 0)
- return r;
- }
-
- 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_set_default_slice(u);
- if (r < 0)
- return r;
-
- 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);
-
- r = unit_name_from_path(what, ".swap", &e);
- if (r < 0)
- return log_unit_error_errno(u, r, "Failed to generate unit name from path: %m");
-
- 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(u, 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), "Changed %s -> %s", swap_state_to_string(old_state), swap_state_to_string(state));
-
- unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
-
- /* 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) {
- 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 (s->control_pid > 0 &&
- pid_is_unwaited(s->control_pid) &&
- IN_SET(new_state,
- SWAP_ACTIVATING,
- SWAP_ACTIVATING_SIGTERM,
- SWAP_ACTIVATING_SIGKILL,
- SWAP_ACTIVATING_DONE,
- SWAP_DEACTIVATING,
- SWAP_DEACTIVATING_SIGTERM,
- SWAP_DEACTIVATING_SIGKILL)) {
-
- r = unit_watch_pid(UNIT(s), s->control_pid);
- if (r < 0)
- return r;
-
- r = swap_arm_timer(s, usec_add(u->state_change_timestamp.monotonic, s->timeout_usec));
- 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,
- .bus_endpoint_fd = -1,
- .stdin_fd = -1,
- .stdout_fd = -1,
- .stderr_fd = -1,
- };
-
- 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, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec));
- 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);
-
- r = exec_spawn(UNIT(s),
- 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, usec_add(now(CLOCK_MONOTONIC), s->timeout_usec));
- 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), r, "Failed to kill processes: %m");
- swap_enter_dead(s, SWAP_FAILURE_RESOURCES);
-}
-
-static void swap_enter_activating(Swap *s) {
- _cleanup_free_ char *opts = NULL;
- int r;
-
- assert(s);
-
- s->control_command_id = SWAP_EXEC_ACTIVATE;
- s->control_command = s->exec_command + SWAP_EXEC_ACTIVATE;
-
- if (s->from_fragment) {
- int priority = -1;
-
- r = fstab_find_pri(s->parameters_fragment.options, &priority);
- if (r < 0)
- log_warning_errno(r, "Failed to parse swap priority \"%s\", ignoring: %m", s->parameters_fragment.options);
- else if (r == 1 && s->parameters_fragment.priority >= 0)
- log_warning("Duplicate swap priority configuration by Priority and Options fields.");
-
- if (r <= 0 && s->parameters_fragment.priority >= 0) {
- if (s->parameters_fragment.options)
- r = asprintf(&opts, "%s,pri=%i", s->parameters_fragment.options, s->parameters_fragment.priority);
- else
- r = asprintf(&opts, "pri=%i", s->parameters_fragment.priority);
- if (r < 0)
- goto fail;
- }
- }
-
- r = exec_command_set(s->control_command, "/sbin/swapon", NULL);
- if (r < 0)
- goto fail;
-
- if (s->parameters_fragment.options || opts) {
- r = exec_command_append(s->control_command, "-o",
- opts ? : s->parameters_fragment.options, 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), r, "Failed to run 'swapon' task: %m");
- 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), r, "Failed to run 'swapoff' task: %m");
- 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() > 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() > 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, "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, "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, "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, "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, "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, f == SWAP_SUCCESS ? LOG_DEBUG : LOG_NOTICE, 0,
- "Swap process exited, code=%s status=%i", 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), "Activation timed out. Stopping.");
- swap_enter_signal(s, SWAP_ACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT);
- break;
-
- case SWAP_DEACTIVATING:
- log_unit_warning(UNIT(s), "Deactivation timed out. Stopping.");
- 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), "Activation timed out. Killing.");
- swap_enter_signal(s, SWAP_ACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT);
- } else {
- log_unit_warning(UNIT(s), "Activation timed out. Skipping SIGKILL. Ignoring.");
- swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
- }
- break;
-
- case SWAP_DEACTIVATING_SIGTERM:
- if (s->kill_context.send_sigkill) {
- log_unit_warning(UNIT(s), "Deactivation timed out. Killing.");
- swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT);
- } else {
- log_unit_warning(UNIT(s), "Deactivation timed out. Skipping SIGKILL. Ignoring.");
- swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
- }
- break;
-
- case SWAP_ACTIVATING_SIGKILL:
- case SWAP_DEACTIVATING_SIGKILL:
- log_unit_warning(UNIT(s), "Swap process still around after SIGKILL. Ignoring.");
- 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;
- }
-
- if (cunescape(dev, UNESCAPE_RELAX, &d) < 0)
- 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);
-
- m->proc_swaps = safe_fclose(m->proc_swaps);
-
- m->swaps_by_devnode = hashmap_free(m->swaps_by_devnode);
-}
-
-static void swap_enumerate(Manager *m) {
- int r;
-
- assert(m);
-
- if (!m->proc_swaps) {
- m->proc_swaps = fopen("/proc/swaps", "re");
- if (!m->proc_swaps) {
- if (errno == ENOENT)
- log_debug("Not swap enabled, skipping enumeration");
- else
- log_error_errno(errno, "Failed to open /proc/swaps: %m");
-
- return;
- }
-
- r = sd_event_add_io(m->event, &m->swap_event_source, fileno(m->proc_swaps), EPOLLPRI, swap_dispatch_io, m);
- if (r < 0) {
- log_error_errno(r, "Failed to watch /proc/swaps: %m");
- 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) {
- log_error_errno(r, "Failed to change /proc/swaps priority: %m");
- goto fail;
- }
-
- (void) sd_event_source_set_description(m->swap_event_source, "swap-proc");
- }
-
- r = swap_load_proc_swaps(m, false);
- if (r < 0)
- goto fail;
-
- return;
-
-fail:
- swap_shutdown(m);
-}
-
-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;
-
- r = unit_name_from_path(dn, ".swap", &e);
- if (r < 0)
- return r;
-
- 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;
- int q;
-
- q = unit_name_from_path(udev_list_entry_get_name(item), ".swap", &n);
- if (q < 0)
- return q;
-
- s = hashmap_get(m->units, n);
- if (s) {
- 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, usec_t *timeout) {
- Swap *s = SWAP(u);
- usec_t t;
- int r;
-
- if (!s->timer_event_source)
- return 0;
-
- r = sd_event_source_get_time(s->timer_event_source, &t);
- if (r < 0)
- return r;
- if (t == USEC_INFINITY)
- return 0;
-
- *timeout = t;
- return 1;
-}
-
-static bool swap_supported(void) {
- 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() <= 0;
-
- return supported;
-}
-
-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_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_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 ac7a63d81b..0000000000
--- a/src/core/swap.h
+++ /dev/null
@@ -1,109 +0,0 @@
-#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 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_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 e2ded27333..0000000000
--- a/src/core/system.conf
+++ /dev/null
@@ -1,60 +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
-#ShowStatus=yes
-#CrashChangeVT=no
-#CrashShell=no
-#CrashReboot=no
-#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
-#DefaultTasksAccounting=yes
-#DefaultTasksMax=512
-#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 ac52b30dd3..0000000000
--- a/src/core/systemd.pc.in
+++ /dev/null
@@ -1,34 +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@
-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 61a91aad07..0000000000
--- a/src/core/target.c
+++ /dev/null
@@ -1,223 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "dbus-target.h"
-#include "log.h"
-#include "special.h"
-#include "string-util.h"
-#include "unit-name.h"
-#include "unit.h"
-#include "target.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_REQUISITE,
- 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) {
- 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);
-}
-
-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_vtable = bus_target_vtable,
-
- .status_message_formats = {
- .finished_start_job = {
- [JOB_DONE] = "Reached target %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 339aea154e..0000000000
--- a/src/core/target.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#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;
-
-struct Target {
- Unit meta;
-
- TargetState state, deserialized_state;
-};
-
-extern const UnitVTable target_vtable;
diff --git a/src/core/timer.c b/src/core/timer.c
deleted file mode 100644
index 3d0bae16e5..0000000000
--- a/src/core/timer.c
+++ /dev/null
@@ -1,851 +0,0 @@
-/***
- 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 "alloc-util.h"
-#include "bus-error.h"
-#include "bus-util.h"
-#include "dbus-timer.h"
-#include "fs-util.h"
-#include "parse-util.h"
-#include "random-util.h"
-#include "special.h"
-#include "string-table.h"
-#include "string-util.h"
-#include "timer.h"
-#include "unit-name.h"
-#include "unit.h"
-#include "user-util.h"
-#include "virt.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;
- t->remain_after_elapse = true;
-}
-
-void timer_free_values(Timer *t) {
- TimerValue *v;
-
- assert(t);
-
- while ((v = t->values)) {
- LIST_REMOVE(value, t->values, v);
- 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), "Timer unit lacks value setting. Refusing.");
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int timer_add_default_dependencies(Timer *t) {
- int r;
- TimerValue *v;
-
- assert(t);
-
- if (!UNIT(t)->default_dependencies)
- return 0;
-
- 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 == MANAGER_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 == MANAGER_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_unit_error_errno(UNIT(t), 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;
-
- 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"
- "%sRemainAfterElapse: %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),
- prefix, yes_no(t->remain_after_elapse));
-
- 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), "Changed %s -> %s", timer_state_to_string(old_state), timer_state_to_string(state));
-
- unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
-}
-
-static void timer_enter_waiting(Timer *t, bool initial);
-
-static int timer_coldplug(Unit *u) {
- Timer *t = TIMER(u);
-
- assert(t);
- assert(t->state == TIMER_DEAD);
-
- if (t->deserialized_state == t->state)
- return 0;
-
- if (t->deserialized_state == TIMER_WAITING)
- timer_enter_waiting(t, false);
- 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 void timer_enter_elapsed(Timer *t, bool leave_around) {
- assert(t);
-
- /* If a unit is marked with RemainAfterElapse=yes we leave it
- * around even after it elapsed once, so that starting it
- * later again does not necessarily mean immediate
- * retriggering. We unconditionally leave units with
- * TIMER_UNIT_ACTIVE or TIMER_UNIT_INACTIVE triggers around,
- * since they might be restarted automatically at any time
- * later on. */
-
- if (t->remain_after_elapse || leave_around)
- timer_set_state(t, TIMER_ELAPSED);
- else
- timer_enter_dead(t, TIMER_SUCCESS);
-}
-
-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 add_random(Timer *t, usec_t *v) {
- char s[FORMAT_TIMESPAN_MAX];
- usec_t add;
-
- assert(t);
- assert(v);
-
- if (t->random_usec == 0)
- return;
- if (*v == USEC_INFINITY)
- return;
-
- add = random_u64() % t->random_usec;
-
- if (*v + add < *v) /* overflow */
- *v = (usec_t) -2; /* Highest possible value, that is not USEC_INFINITY */
- else
- *v += add;
-
- log_unit_info(UNIT(t), "Adding %s random time.", format_timespan(s, sizeof(s), add, 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;
- bool leave_around = false;
- TimerValue *v;
- Unit *trigger;
- int r;
-
- assert(t);
-
- trigger = UNIT_TRIGGER(UNIT(t));
- if (!trigger) {
- log_unit_error(UNIT(t), "Unit to trigger vanished.");
- timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
- return;
- }
-
- /* 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:
- if (detect_container() <= 0) {
- /* CLOCK_MONOTONIC equals the uptime on Linux */
- base = 0;
- break;
- }
- /* In a container we don't want to include the time the host
- * was already up when the container started, so count from
- * our own startup. Fall through. */
- case TIMER_STARTUP:
- base = UNIT(t)->manager->userspace_timestamp.monotonic;
- break;
-
- case TIMER_UNIT_ACTIVE:
- leave_around = true;
- base = trigger->inactive_exit_timestamp.monotonic;
-
- if (base <= 0)
- base = t->last_trigger.monotonic;
-
- if (base <= 0)
- continue;
-
- break;
-
- case TIMER_UNIT_INACTIVE:
- leave_around = true;
- base = trigger->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), "Timer is elapsed.");
- timer_enter_elapsed(t, leave_around);
- return;
- }
-
- if (found_monotonic) {
- char buf[FORMAT_TIMESPAN_MAX];
- usec_t left;
-
- add_random(t, &t->next_elapse_monotonic_or_boottime);
-
- left = t->next_elapse_monotonic_or_boottime > ts_monotonic ? t->next_elapse_monotonic_or_boottime - ts_monotonic : 0;
- log_unit_debug(UNIT(t), "Monotonic timer elapses in %s.", format_timespan(buf, sizeof(buf), left, 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);
- if (r < 0)
- goto fail;
- } 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;
-
- (void) sd_event_source_set_description(t->monotonic_event_source, "timer-monotonic");
- }
-
- } 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];
-
- add_random(t, &t->next_elapse_realtime);
-
- log_unit_debug(UNIT(t), "Realtime timer elapses at %s.", 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);
- if (r < 0)
- goto fail;
- } 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;
-
- (void) sd_event_source_set_description(t->realtime_event_source, "timer-realtime");
- }
-
- } 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), r, "Failed to enter waiting state: %m");
- timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
-}
-
-static void timer_enter_running(Timer *t) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- Unit *trigger;
- int r;
-
- assert(t);
-
- /* Don't start job if we are supposed to go down */
- if (unit_stop_pending(UNIT(t)))
- return;
-
- trigger = UNIT_TRIGGER(UNIT(t));
- if (!trigger) {
- log_unit_error(UNIT(t), "Unit to trigger vanished.");
- timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
- return;
- }
-
- r = manager_add_job(UNIT(t)->manager, JOB_START, trigger, JOB_REPLACE, &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, MODE_INVALID);
-
- timer_set_state(t, TIMER_RUNNING);
- return;
-
-fail:
- log_unit_warning(UNIT(t), "Failed to queue unit startup job: %s", bus_error_message(&error, r));
- timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
-}
-
-static int timer_start(Unit *u) {
- Timer *t = TIMER(u);
- TimerValue *v;
- Unit *trigger;
-
- assert(t);
- assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
-
- trigger = UNIT_TRIGGER(u);
- if (!trigger || trigger->load_state != UNIT_LOADED) {
- log_unit_error(u, "Refusing to start, unit to trigger not 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, MODE_INVALID);
- }
-
- 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, "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, "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, "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, "Failed to parse last-trigger-monotonic value: %s", value);
-
- } else
- log_unit_debug(u, "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), "Timer elapsed.");
- 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), "Got notified about unit deactivation.");
- 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, "Time change, recalculating next elapse.");
- timer_enter_waiting(t, false);
-}
-
-static const char* const timer_base_table[_TIMER_BASE_MAX] = {
- [TIMER_ACTIVE] = "OnActiveSec",
- [TIMER_BOOT] = "OnBootSec",
- [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_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 698e6da2f5..0000000000
--- a/src/core/timer.h
+++ /dev/null
@@ -1,88 +0,0 @@
-#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 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;
- usec_t random_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;
- bool remain_after_elapse;
-
- char *stamp_path;
-};
-
-void timer_free_values(Timer *t);
-
-extern const UnitVTable timer_vtable;
-
-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 b28fc76785..0000000000
--- a/src/core/transaction.c
+++ /dev/null
@@ -1,1092 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <fcntl.h>
-#include <unistd.h>
-
-#include "alloc-util.h"
-#include "bus-common-errors.h"
-#include "bus-error.h"
-#include "terminal-util.h"
-#include "transaction.h"
-#include "dbus-unit.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->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,
- "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,
- "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,
- "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,
- "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,
- "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,
- "Breaking ordering cycle by deleting job %s/%s",
- delete->unit->id, job_type_to_string(delete->type));
- log_unit_error(delete->unit,
- "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 " SKIP " ANSI_NORMAL,
- "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) {
- r = transaction_verify_order_one(tr, j, NULL, g, e);
- if (r < 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,
- "%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,
- "%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,
- "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) {
- (void) pipe2(m->idle_pipe, O_NONBLOCK|O_CLOEXEC);
- (void) pipe2(m->idle_pipe + 2, O_NONBLOCK|O_CLOEXEC);
- }
- }
-
- return 0;
-}
-
-static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, 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->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,
- "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 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);
-
- /* Before adding jobs for this unit, let's ensure that its state has been loaded
- * This matters when jobs are spawned as part of coldplugging itself (see e. g. path_coldplug()).
- * This way, we "recursively" coldplug units, ensuring that we do not look at state of
- * not-yet-coldplugged units. */
- if (unit->manager->n_reloading > 0)
- unit_coldplug(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) {
- r = bus_unit_check_load_state(unit, e);
- if (r < 0)
- return r;
- }
-
- 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, &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, false, false, ignore_order, e);
- if (r < 0) {
- log_unit_warning(dep, "Cannot add dependency job for, ignoring: %s", bus_error_message(e, r));
- 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, false, false, ignore_order, e);
- if (r < 0) {
- if (r != -EBADR) /* job type not applicable */
- goto fail;
-
- 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, false, false, ignore_order, e);
- if (r < 0) {
- if (r != -EBADR) /* job type not applicable */
- goto fail;
-
- 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, ignore_order, e);
- if (r < 0) {
- /* unit masked, job type not applicable and unit not found are not considered as errors. */
- log_unit_full(dep,
- IN_SET(r, -ESHUTDOWN, -EBADR, -ENOENT) ? LOG_DEBUG : LOG_WARNING,
- r, "Cannot add dependency job, ignoring: %s",
- bus_error_message(e, r));
- 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, false, false, ignore_order, e);
- if (r < 0) {
- if (r != -EBADR) /* job type not applicable */
- goto fail;
-
- 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, true, false, ignore_order, e);
- if (r < 0) {
- if (r != -EBADR) /* job type not applicable */
- goto fail;
-
- 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, false, false, ignore_order, e);
- if (r < 0) {
- log_unit_warning(dep,
- "Cannot add dependency job, ignoring: %s",
- bus_error_message(e, r));
- sd_bus_error_free(e);
- }
- }
-
- }
-
- if (type == JOB_STOP || type == JOB_RESTART) {
- static const UnitDependency propagate_deps[] = {
- UNIT_REQUIRED_BY,
- UNIT_REQUISITE_OF,
- UNIT_BOUND_BY,
- UNIT_CONSISTS_OF,
- };
-
- JobType ptype;
- unsigned j;
-
- /* We propagate STOP as STOP, but RESTART only
- * as TRY_RESTART, in order not to start
- * dependencies that are not around. */
- ptype = type == JOB_RESTART ? JOB_TRY_RESTART : type;
-
- for (j = 0; j < ELEMENTSOF(propagate_deps); j++)
- SET_FOREACH(dep, ret->unit->dependencies[propagate_deps[j]], i) {
- JobType nt;
-
- nt = job_type_collapse(ptype, dep);
- if (nt == JOB_NOP)
- continue;
-
- r = transaction_add_job_and_dependencies(tr, nt, dep, ret, true, false, false, ignore_order, e);
- if (r < 0) {
- if (r != -EBADR) /* job type not applicable */
- goto fail;
-
- sd_bus_error_free(e);
- }
- }
- }
-
- if (type == JOB_RELOAD) {
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) {
- JobType nt;
-
- nt = job_type_collapse(JOB_TRY_RELOAD, dep);
- if (nt == JOB_NOP)
- continue;
-
- r = transaction_add_job_and_dependencies(tr, nt, dep, ret, false, false, false, ignore_order, e);
- if (r < 0) {
- log_unit_warning(dep,
- "Cannot add dependency reload job, ignoring: %s",
- bus_error_message(e, r));
- 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, NULL);
- if (r < 0)
- log_unit_warning_errno(u, r, "Cannot add isolate job, ignoring: %m");
- }
-
- 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 6a3f927b0f..0000000000
--- a/src/core/transaction.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct Transaction Transaction;
-
-#include "hashmap.h"
-#include "job.h"
-#include "manager.h"
-#include "unit.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 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/triggers.systemd.in b/src/core/triggers.systemd.in
deleted file mode 100644
index 9e18a39a67..0000000000
--- a/src/core/triggers.systemd.in
+++ /dev/null
@@ -1,64 +0,0 @@
-# -*- Mode: rpm-spec; indent-tabs-mode: nil -*- */
-#
-# This file is part of systemd.
-#
-# Copyright 2015 Zbigniew Jędrzejewski-Szmek
-#
-# systemd is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation; either version 2.1 of the License, or
-# (at your option) any later version.
-#
-# systemd is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with systemd; If not, see <http://www.gnu.org/licenses/>.
-
-# The contents of this are an example to be copied into systemd.spec.
-
-%transfiletriggerin -P 900900 -p <lua> -- @systemunitdir@ /etc/systemd/system
--- This script will run after any package is initially installed or
--- upgraded. We care about the case where a package is initially
--- installed, because other cases are covered by the *un scriptlets,
--- so sometimes we will reload needlessly.
-
-pid = posix.fork()
-if pid == 0 then
- assert(posix.exec("%{_bindir}/systemctl", "daemon-reload"))
-elseif pid > 0 then
- posix.wait(pid)
-end
-
-%transfiletriggerun -p <lua> -- @systemunitdir@ /etc/systemd/system
--- On removal, we need to run daemon-reload after any units have been
--- removed. %transfiletriggerpostun would be ideal, but it does not get
--- executed for some reason.
--- On upgrade, we need to run daemon-reload after any new unit files
--- have been installed, but before %postun scripts in packages get
--- executed. %transfiletriggerun gets the right list of files
--- but it is invoked too early (before changes happen).
--- %filetriggerpostun happens at the right time, but it fires for
--- every package.
--- To execute the reload at the right time, we create a state
--- file in %transfiletriggerun and execute the daemon-reload in
--- the first %filetriggerpostun.
-
-posix.mkdir("%{_localstatedir}/lib")
-posix.mkdir("%{_localstatedir}/lib/rpm-state")
-posix.mkdir("%{_localstatedir}/lib/rpm-state/systemd")
-io.open("%{_localstatedir}/lib/rpm-state/systemd/needs-reload", "w")
-
-%filetriggerpostun -P 1000100 -p <lua> -- @systemunitdir@ /etc/systemd/system
-if posix.access("%{_localstatedir}/lib/rpm-state/systemd/needs-reload") then
- posix.unlink("%{_localstatedir}/lib/rpm-state/systemd/needs-reload")
- posix.rmdir("%{_localstatedir}/lib/rpm-state/systemd")
- pid = posix.fork()
- if pid == 0 then
- assert(posix.exec("%{_bindir}/systemctl", "daemon-reload"))
- elseif pid > 0 then
- posix.wait(pid)
- end
-end
diff --git a/src/core/umount.c b/src/core/umount.c
deleted file mode 100644
index a458768e7d..0000000000
--- a/src/core/umount.c
+++ /dev/null
@@ -1,613 +0,0 @@
-/***
- 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 <linux/dm-ioctl.h>
-#include <linux/loop.h>
-#include <string.h>
-#include <sys/mount.h>
-#include <sys/swap.h>
-
-#include "libudev.h"
-
-#include "alloc-util.h"
-#include "escape.h"
-#include "fd-util.h"
-#include "fstab-util.h"
-#include "list.h"
-#include "mount-setup.h"
-#include "path-util.h"
-#include "string-util.h"
-#include "udev-util.h"
-#include "umount.h"
-#include "util.h"
-#include "virt.h"
-
-typedef struct MountPoint {
- char *path;
- char *options;
- 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;
- int r;
-
- 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, *options = 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 flags */
- "%*[^-]" /* (7) optional fields */
- "- " /* (8) separator */
- "%*s " /* (9) file system type */
- "%*s" /* (10) mount source */
- "%ms" /* (11) mount options */
- "%*[^\n]", /* some rubbish at the end */
- &path, &options);
- if (k != 2) {
- if (k == EOF)
- break;
-
- log_warning("Failed to parse /proc/self/mountinfo:%u.", i);
- continue;
- }
-
- r = cunescape(path, UNESCAPE_RELAX, &p);
- if (r < 0)
- return r;
-
- /* 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;
- m->options = options;
- options = NULL;
-
- LIST_PREPEND(mount_point, *head, m);
- }
-
- return 0;
-}
-
-static int swap_list_get(MountPoint **head) {
- _cleanup_fclose_ FILE *proc_swaps = NULL;
- unsigned int i;
- int r;
-
- assert(head);
-
- proc_swaps = fopen("/proc/swaps", "re");
- if (!proc_swaps)
- 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;
-
- k = fscanf(proc_swaps,
- "%ms " /* device/file */
- "%*s " /* type of swap */
- "%*s " /* swap size */
- "%*s " /* used */
- "%*s\n", /* priority */
- &dev);
-
- if (k != 1) {
- if (k == EOF)
- break;
-
- log_warning("Failed to parse /proc/swaps:%u.", i);
- free(dev);
- continue;
- }
-
- if (endswith(dev, " (deleted)")) {
- free(dev);
- continue;
- }
-
- r = cunescape(dev, UNESCAPE_RELAX, &d);
- free(dev);
- if (r < 0)
- return r;
-
- swap = new0(MountPoint, 1);
- if (!swap) {
- 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() <= 0) {
- _cleanup_free_ char *options = NULL;
- /* MS_REMOUNT requires that the data parameter
- * should be the same from the original mount
- * except for the desired changes. Since we want
- * to remount read-only, we should filter out
- * rw (and ro too, because it confuses the kernel) */
- (void) fstab_filter_options(m->options, "rw\0ro\0", NULL, NULL, &options);
-
- /* 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. */
- log_info("Remounting '%s' read-only with options '%s'.", m->path, options);
- (void) mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, options);
- }
-
- /* 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 4e2215a47d..0000000000
--- a/src/core/umount.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#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 fc057d965c..0000000000
--- a/src/core/unit-printf.c
+++ /dev/null
@@ -1,309 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "alloc-util.h"
-#include "cgroup-util.h"
-#include "formats-util.h"
-#include "macro.h"
-#include "specifier.h"
-#include "string-util.h"
-#include "strv.h"
-#include "unit-name.h"
-#include "unit-printf.h"
-#include "unit.h"
-#include "user-util.h"
-
-static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) {
- Unit *u = userdata;
-
- assert(u);
-
- return unit_name_to_prefix_and_instance(u->id, ret);
-}
-
-static int specifier_prefix(char specifier, void *data, void *userdata, char **ret) {
- Unit *u = userdata;
-
- assert(u);
-
- return unit_name_to_prefix(u->id, ret);
-}
-
-static int specifier_prefix_unescaped(char specifier, void *data, void *userdata, char **ret) {
- _cleanup_free_ char *p = NULL;
- Unit *u = userdata;
- int r;
-
- assert(u);
-
- r = unit_name_to_prefix(u->id, &p);
- if (r < 0)
- return r;
-
- return unit_name_unescape(p, ret);
-}
-
-static int specifier_instance_unescaped(char specifier, void *data, void *userdata, char **ret) {
- Unit *u = userdata;
-
- assert(u);
-
- return unit_name_unescape(strempty(u->instance), ret);
-}
-
-static int specifier_filename(char specifier, void *data, void *userdata, char **ret) {
- Unit *u = userdata;
-
- assert(u);
-
- if (u->instance)
- return unit_name_path_unescape(u->instance, ret);
- else
- return unit_name_to_path(u->id, ret);
-}
-
-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;
- char *n;
-
- assert(u);
-
- n = strdup(u->manager->cgroup_root);
- if (!n)
- return -ENOMEM;
-
- *ret = n;
- return 0;
-}
-
-static int specifier_cgroup_slice(char specifier, void *data, void *userdata, char **ret) {
- Unit *u = userdata;
- char *n;
-
- assert(u);
-
- if (UNIT_ISSET(u->slice)) {
- Unit *slice;
-
- slice = UNIT_DEREF(u->slice);
-
- if (slice->cgroup_path)
- n = strdup(slice->cgroup_path);
- else
- n = unit_default_cgroup_path(slice);
- } else
- n = strdup(u->manager->cgroup_root);
- 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 == MANAGER_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 *t;
-
- /* If we are UID 0 (root), this will not result in NSS,
- * otherwise it might. This is good, as we want to be able to
- * run this in PID 1, where our user ID is 0, but where NSS
- * lookups are not allowed. */
-
- t = getusername_malloc();
- if (!t)
- return -ENOMEM;
-
- *ret = t;
- return 0;
-}
-
-static int specifier_user_id(char specifier, void *data, void *userdata, char **ret) {
-
- if (asprintf(ret, UID_FMT, getuid()) < 0)
- return -ENOMEM;
-
- return 0;
-}
-
-static int specifier_user_home(char specifier, void *data, void *userdata, char **ret) {
-
- /* On PID 1 (which runs as root) this will not result in NSS,
- * which is good. See above */
-
- return get_home_dir(ret);
-}
-
-static int specifier_user_shell(char specifier, void *data, void *userdata, char **ret) {
-
- /* On PID 1 (which runs as root) this will not result in NSS,
- * which is good. See above */
-
- return get_shell(ret);
-}
-
-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 running user
- * %u the username of the running user
- * %h the homedir of the running user
- * %s the shell of the 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_slice, NULL },
- { 'R', specifier_cgroup_root, NULL },
- { 't', specifier_runtime, NULL },
-
- { 'U', specifier_user_id, NULL },
- { 'u', specifier_user_name, NULL },
- { 'h', specifier_user_home, NULL },
- { 's', specifier_user_shell, NULL },
-
- { 'm', specifier_machine_id, NULL },
- { 'H', specifier_host_name, NULL },
- { 'b', specifier_boot_id, NULL },
- { 'v', specifier_kernel_release, NULL },
- {}
- };
-
- 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 4fc8531228..0000000000
--- a/src/core/unit-printf.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#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 d39e3dcaeb..0000000000
--- a/src/core/unit.c
+++ /dev/null
@@ -1,3756 +0,0 @@
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "sd-id128.h"
-#include "sd-messages.h"
-
-#include "alloc-util.h"
-#include "bus-common-errors.h"
-#include "bus-util.h"
-#include "cgroup-util.h"
-#include "dbus-unit.h"
-#include "dbus.h"
-#include "dropin.h"
-#include "escape.h"
-#include "execute.h"
-#include "fileio-label.h"
-#include "formats-util.h"
-#include "load-dropin.h"
-#include "load-fragment.h"
-#include "log.h"
-#include "macro.h"
-#include "missing.h"
-#include "mkdir.h"
-#include "parse-util.h"
-#include "path-util.h"
-#include "process-util.h"
-#include "set.h"
-#include "special.h"
-#include "stat-util.h"
-#include "stdio-util.h"
-#include "string-util.h"
-#include "strv.h"
-#include "unit-name.h"
-#include "unit.h"
-#include "user-util.h"
-#include "virt.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_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 void maybe_warn_about_dependency(Unit *u, 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->default_dependencies = true;
- u->unit_file_state = _UNIT_FILE_STATE_INVALID;
- u->unit_file_preset = -1;
- u->on_failure_job_mode = JOB_REPLACE;
- u->cgroup_inotify_wd = -1;
- u->job_timeout = USEC_INFINITY;
-
- RATELIMIT_INIT(u->start_limit, m->default_start_limit_interval, m->default_start_limit_burst);
- RATELIMIT_INIT(u->auto_stop_ratelimit, 10 * USEC_PER_SEC, 16);
-
- 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;
- cc->tasks_accounting = u->manager->default_tasks_accounting;
-
- if (u->type != UNIT_SLICE)
- cc->tasks_max = u->manager->default_tasks_max;
- }
-
- 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_valid(text, UNIT_NAME_TEMPLATE)) {
-
- if (!u->instance)
- return -EINVAL;
-
- r = unit_name_replace_instance(text, u->instance, &s);
- if (r < 0)
- return r;
- } else {
- s = strdup(text);
- if (!s)
- return -ENOMEM;
- }
-
- if (set_contains(u->names, s))
- return 0;
- if (hashmap_contains(u->manager->units, s))
- return -EEXIST;
-
- if (!unit_name_is_valid(s, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE))
- return -EINVAL;
-
- t = unit_name_to_type(s);
- if (t < 0)
- return -EINVAL;
-
- 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. Note that we do allow names with different
- * instance names however! */
- if (u->type != _UNIT_TYPE_INVALID && !u->instance != !i)
- return -EINVAL;
-
- if (unit_vtable[t]->no_alias && !set_isempty(u->names))
- return -EEXIST;
-
- if (hashmap_size(u->manager->units) >= MANAGER_MAX_NAMES)
- return -E2BIG;
-
- r = set_put(u->names, s);
- if (r < 0)
- return r;
- assert(r > 0);
-
- r = hashmap_put(u->manager->units, s, u);
- if (r < 0) {
- (void) 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_valid(name, UNIT_NAME_TEMPLATE)) {
-
- if (!u->instance)
- return -EINVAL;
-
- r = unit_name_replace_instance(name, u->instance, &t);
- if (r < 0)
- return r;
-
- name = t;
- }
-
- /* Selects one of the names of this unit as the id */
- s = set_get(u->names, (char*) name);
- if (!s)
- return -ENOENT;
-
- /* Determine the new instance from the new id */
- 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 (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)
- (void) unlink(u->fragment_path);
-
- STRV_FOREACH(i, u->dropin_paths) {
- _cleanup_free_ char *p = NULL;
-
- (void) unlink(*i);
-
- p = dirname_malloc(*i);
- if (p)
- (void) 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);
- }
- }
- }
-
- u->requires_mounts_for = strv_free(u->requires_mounts_for);
-}
-
-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);
-
- sd_bus_slot_unref(u->match_bus_slot);
-
- 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);
-
- unit_release_cgroup(u);
-
- (void) 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);
-
- free(u->reboot_arg);
-
- 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, 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, 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);
-
- other->dependencies[d] = set_free(other->dependencies[d]);
-}
-
-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_valid(name, UNIT_NAME_TEMPLATE)) {
- if (!u->instance)
- return -EINVAL;
-
- r = unit_name_replace_instance(name, u->instance, &s);
- if (r < 0)
- return r;
-
- name = s;
- }
-
- other = manager_get_unit(u->manager, name);
- if (other)
- return unit_merge(u, other);
-
- return unit_add_name(u, name);
-}
-
-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 != MANAGER_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
- timestamp0[FORMAT_TIMESTAMP_MAX],
- 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\nState Change Timestamp: %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(timestamp0, sizeof(timestamp0), u->state_change_timestamp.realtime)),
- 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 != USEC_INFINITY)
- 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",
- 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));
-
- 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_REQUISITE_OF,
- 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_HAS_CGROUP_CONTEXT(u))
- return 0;
-
- if (UNIT_ISSET(u->slice))
- return unit_add_two_dependencies(u, UNIT_AFTER, UNIT_REQUIRES, UNIT_DEREF(u->slice), true);
-
- if (unit_has_name(u, SPECIAL_ROOT_SLICE))
- return 0;
-
- return unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, 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) {
- _cleanup_free_ char *p = NULL;
- Unit *m;
-
- r = unit_name_from_path(prefix, ".mount", &p);
- if (r < 0)
- return r;
-
- m = manager_get_unit(u->manager, p);
- if (!m) {
- /* Make sure to load the mount unit if
- * it exists. If so the dependencies
- * on this unit will be added later
- * during the loading of the mount
- * unit. */
- (void) manager_load_unit_prepare(u->manager, p, NULL, NULL, &m);
- 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;
-
- c = unit_get_cgroup_context(u);
- if (!c)
- return 0;
-
- if (c->startup_cpu_shares == CGROUP_CPU_SHARES_INVALID &&
- c->startup_blockio_weight == CGROUP_BLKIO_WEIGHT_INVALID)
- return 0;
-
- r = set_ensure_allocated(&u->manager->startup_units, NULL);
- if (r < 0)
- return r;
-
- return set_put(u->manager->startup_units, u);
-}
-
-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, "More than one OnFailure= dependencies specified but OnFailureJobMode=isolate set. Refusing.");
- 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_errno(u, r, "Failed to load configuration: %m");
-
- 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,
- "Couldn't determine result for %s=%s%s%s, assuming failed: %m",
- to_string(c->type),
- c->trigger ? "|" : "",
- c->negate ? "!" : "",
- c->parameter);
- else
- log_unit_debug(u,
- "%s=%s%s%s %s.",
- to_string(c->type),
- c->trigger ? "|" : "",
- c->negate ? "!" : "",
- c->parameter,
- condition_result_to_string(c->result));
-
- 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;
-}
-
-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;
-}
-
-_pure_ static const char* unit_get_status_message_format(Unit *u, JobType t) {
- const char *format;
- const UnitStatusMessageFormats *format_table;
-
- assert(u);
- assert(IN_SET(t, JOB_START, JOB_STOP, JOB_RELOAD));
-
- if (t != JOB_RELOAD) {
- format_table = &UNIT_VTABLE(u)->status_message_formats;
- if (format_table) {
- format = format_table->starting_stopping[t == JOB_STOP];
- if (format)
- return format;
- }
- }
-
- /* Return generic strings */
- if (t == JOB_START)
- return "Starting %s.";
- else if (t == JOB_STOP)
- return "Stopping %s.";
- else
- return "Reloading %s.";
-}
-
-static void unit_status_print_starting_stopping(Unit *u, JobType t) {
- const char *format;
-
- assert(u);
-
- /* Reload status messages have traditionally not been printed to console. */
- if (!IN_SET(t, JOB_START, JOB_STOP))
- return;
-
- format = unit_get_status_message_format(u, t);
-
- 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 (!IN_SET(t, JOB_START, JOB_STOP, JOB_RELOAD))
- return;
-
- if (log_on_console())
- return;
-
- /* We log status messages for all units and all operations. */
-
- format = unit_get_status_message_format(u, t);
-
- DISABLE_WARNING_FORMAT_NONLITERAL;
- xsprintf(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;
-
- /* Note that we deliberately use LOG_MESSAGE() instead of
- * LOG_UNIT_MESSAGE() here, since this is supposed to mimic
- * closely what is written to screen using the status output,
- * which is supposed the highest level, friendliest output
- * possible, which means we should avoid the low-level unit
- * name. */
- log_struct(LOG_INFO,
- LOG_MESSAGE_ID(mid),
- LOG_UNIT_ID(u),
- LOG_MESSAGE("%s", buf),
- NULL);
-}
-
-void unit_status_emit_starting_stopping_reloading(Unit *u, JobType t) {
- assert(u);
- assert(t >= 0);
- assert(t < _JOB_TYPE_MAX);
-
- unit_status_log_starting_stopping_reloading(u, t);
- unit_status_print_starting_stopping(u, t);
-}
-
-static int unit_start_limit_test(Unit *u) {
- assert(u);
-
- if (ratelimit_test(&u->start_limit)) {
- u->start_limit_hit = false;
- return 0;
- }
-
- log_unit_warning(u, "Start request repeated too quickly.");
- u->start_limit_hit = true;
-
- return failure_action(u->manager, u->start_limit_action, u->reboot_arg);
-}
-
-/* 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
- * -EINVAL: Unit not loaded
- * -EOPNOTSUPP: Unit type not supported
- */
-int unit_start(Unit *u) {
- UnitActiveState state;
- Unit *following;
- int r;
-
- assert(u);
-
- /* 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;
-
- /* Make sure we don't enter a busy loop of some kind. */
- r = unit_start_limit_test(u);
- if (r < 0)
- return r;
-
- /* Units that aren't loaded cannot be started */
- if (u->load_state != UNIT_LOADED)
- return -EINVAL;
-
- /* 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, "Starting requested but condition failed. Not starting unit.");
- return -EALREADY;
- }
-
- /* If the asserts failed, fail the entire job */
- if (state != UNIT_ACTIVATING &&
- !unit_assert_test(u)) {
- log_unit_notice(u, "Starting requested but asserts failed.");
- return -EPROTO;
- }
-
- /* Units of types that aren't supported cannot be
- * started. Note that we do this test only after the condition
- * checks, so that we rather return condition check errors
- * (which are usually not considered a true failure) than "not
- * supported" errors (which are considered a failure).
- */
- if (!unit_supported(u))
- return -EOPNOTSUPP;
-
- /* Forward to the main object, if we aren't it. */
- following = unit_following(u);
- if (following) {
- log_unit_debug(u, "Redirecting start request from %s to %s.", u->id, following->id);
- return unit_start(following);
- }
-
- /* 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);
-
- return UNIT_VTABLE(u)->start(u);
-}
-
-bool unit_can_start(Unit *u) {
- assert(u);
-
- if (u->load_state != UNIT_LOADED)
- return false;
-
- if (!unit_supported(u))
- return false;
-
- 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;
-
- 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, "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);
-
- return UNIT_VTABLE(u)->stop(u);
-}
-
-/* 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;
-
- 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, "Unit cannot be reloaded because it is inactive.");
- return -ENOEXEC;
- }
-
- following = unit_following(u);
- if (following) {
- log_unit_debug(u, "Redirecting reload request from %s to %s.", u->id, following->id);
- return unit_reload(following);
- }
-
- unit_add_to_dbus_queue(u);
-
- return UNIT_VTABLE(u)->reload(u);
-}
-
-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) {
-
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
-
- static const UnitDependency needed_dependencies[] = {
- UNIT_REQUIRED_BY,
- UNIT_REQUISITE_OF,
- UNIT_WANTED_BY,
- UNIT_BOUND_BY,
- };
-
- Unit *other;
- Iterator i;
- unsigned j;
- int r;
-
- 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;
-
- for (j = 0; j < ELEMENTSOF(needed_dependencies); j++)
- SET_FOREACH(other, u->dependencies[needed_dependencies[j]], i)
- if (unit_active_or_pending(other))
- return;
-
- /* If stopping a unit fails continously we might enter a stop
- * loop here, hence stop acting on the service being
- * unnecessary after a while. */
- if (!ratelimit_test(&u->auto_stop_ratelimit)) {
- log_unit_warning(u, "Unit not needed anymore, but not stopping since we tried this too often recently.");
- return;
- }
-
- log_unit_info(u, "Unit not needed anymore. Stopping.");
-
- /* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */
- r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, &error, NULL);
- if (r < 0)
- log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %s", bus_error_message(&error, r));
-}
-
-static void unit_check_binds_to(Unit *u) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- bool stop = false;
- Unit *other;
- Iterator i;
- int r;
-
- 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;
-
- /* If stopping a unit fails continously we might enter a stop
- * loop here, hence stop acting on the service being
- * unnecessary after a while. */
- if (!ratelimit_test(&u->auto_stop_ratelimit)) {
- log_unit_warning(u, "Unit is bound to inactive unit %s, but not stopping since we tried this too often recently.", other->id);
- return;
- }
-
- assert(other);
- log_unit_info(u, "Unit is bound to inactive unit %s. Stopping, too.", other->id);
-
- /* A unit we need to run is gone. Sniff. Let's stop this. */
- r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, &error, NULL);
- if (r < 0)
- log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %s", bus_error_message(&error, r));
-}
-
-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, 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, 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, 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, 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, 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, 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_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_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, "Triggering OnFailure= dependencies.");
-
- 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, NULL, NULL);
- if (r < 0)
- log_unit_error_errno(u, 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_get(&u->state_change_timestamp);
-
- if (UNIT_IS_INACTIVE_OR_FAILED(os) && !UNIT_IS_INACTIVE_OR_FAILED(ns))
- u->inactive_exit_timestamp = u->state_change_timestamp;
- else if (!UNIT_IS_INACTIVE_OR_FAILED(os) && UNIT_IS_INACTIVE_OR_FAILED(ns))
- u->inactive_enter_timestamp = u->state_change_timestamp;
-
- if (!UNIT_IS_ACTIVE_OR_RELOADING(os) && UNIT_IS_ACTIVE_OR_RELOADING(ns))
- u->active_enter_timestamp = u->state_change_timestamp;
- else if (UNIT_IS_ACTIVE_OR_RELOADING(os) && !UNIT_IS_ACTIVE_OR_RELOADING(ns))
- u->active_exit_timestamp = u->state_change_timestamp;
- }
-
- /* Keep track of failed units */
- (void) 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_prune_cgroup(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:
- case JOB_TRY_RELOAD:
-
- 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, "Unit entered failed state.");
- 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, PID_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, PID_TO_PTR(pid), u);
- }
-
- q = set_put(u->pids, PID_TO_PTR(pid));
- if (q < 0)
- return q;
-
- return r;
-}
-
-void unit_unwatch_pid(Unit *u, pid_t pid) {
- assert(u);
- assert(pid >= 1);
-
- (void) hashmap_remove_value(u->manager->watch_pids1, PID_TO_PTR(pid), u);
- (void) hashmap_remove_value(u->manager->watch_pids2, PID_TO_PTR(pid), u);
- (void) set_remove(u->pids, PID_TO_PTR(pid));
-}
-
-void unit_unwatch_all_pids(Unit *u) {
- assert(u);
-
- while (!set_isempty(u->pids))
- unit_unwatch_pid(u, PTR_TO_PID(set_first(u->pids)));
-
- u->pids = set_free(u->pids);
-}
-
-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_PID(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:
- case JOB_TRY_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 void maybe_warn_about_dependency(Unit *u, const char *other, UnitDependency dependency) {
- assert(u);
-
- /* Only warn about some unit types */
- if (!IN_SET(dependency, UNIT_CONFLICTS, UNIT_CONFLICTED_BY, UNIT_BEFORE, UNIT_AFTER, UNIT_ON_FAILURE, UNIT_TRIGGERS, UNIT_TRIGGERED_BY))
- return;
-
- if (streq_ptr(u->id, other))
- log_unit_warning(u, "Dependency %s=%s dropped", unit_dependency_to_string(dependency), u->id);
- else
- log_unit_warning(u, "Dependency %s=%s dropped, merged into %s", unit_dependency_to_string(dependency), strna(other), u->id);
-}
-
-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_WANTS] = UNIT_WANTED_BY,
- [UNIT_REQUISITE] = UNIT_REQUISITE_OF,
- [UNIT_BINDS_TO] = UNIT_BOUND_BY,
- [UNIT_PART_OF] = UNIT_CONSISTS_OF,
- [UNIT_REQUIRED_BY] = UNIT_REQUIRES,
- [UNIT_REQUISITE_OF] = UNIT_REQUISITE,
- [UNIT_WANTED_BY] = UNIT_WANTS,
- [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, 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;
-
- return unit_add_dependency(u, e, other, add_reference);
-}
-
-static int resolve_template(Unit *u, const char *name, const char*path, char **buf, const char **ret) {
- int r;
-
- assert(u);
- assert(name || path);
- assert(buf);
- assert(ret);
-
- if (!name)
- name = basename(path);
-
- if (!unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) {
- *buf = NULL;
- *ret = name;
- return 0;
- }
-
- if (u->instance)
- r = unit_name_replace_instance(name, u->instance, buf);
- else {
- _cleanup_free_ char *i = NULL;
-
- r = unit_name_to_prefix(u->id, &i);
- if (r < 0)
- return r;
-
- r = unit_name_replace_instance(name, i, buf);
- }
- if (r < 0)
- return r;
-
- *ret = *buf;
- return 0;
-}
-
-int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) {
- _cleanup_free_ char *buf = NULL;
- Unit *other;
- int r;
-
- assert(u);
- assert(name || path);
-
- r = resolve_template(u, name, path, &buf, &name);
- if (r < 0)
- return r;
-
- 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 *buf = NULL;
- Unit *other;
- int r;
-
- assert(u);
- assert(name || path);
-
- r = resolve_template(u, name, path, &buf, &name);
- if (r < 0)
- return r;
-
- 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 set_unit_path(const char *p) {
- /* This is mostly for debug purposes */
- if (setenv("SYSTEMD_UNIT_PATH", p, 1) < 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);
-}
-
-int unit_set_slice(Unit *u, Unit *slice) {
- assert(u);
- assert(slice);
-
- /* Sets the unit slice if it has not been set before. Is extra
- * careful, to only allow this for units that actually have a
- * cgroup context. Also, we don't allow to set this for slices
- * (since the parent slice is derived from the name). Make
- * sure the unit we set is actually a slice. */
-
- if (!UNIT_HAS_CGROUP_CONTEXT(u))
- return -EOPNOTSUPP;
-
- if (u->type == UNIT_SLICE)
- return -EINVAL;
-
- if (unit_active_state(u) != UNIT_INACTIVE)
- return -EBUSY;
-
- if (slice->type != UNIT_SLICE)
- return -EINVAL;
-
- if (unit_has_name(u, SPECIAL_INIT_SCOPE) &&
- !unit_has_name(slice, SPECIAL_ROOT_SLICE))
- return -EPERM;
-
- if (UNIT_DEREF(u->slice) == slice)
- return 0;
-
- if (UNIT_ISSET(u->slice))
- return -EBUSY;
-
- unit_ref_set(&u->slice, slice);
- return 1;
-}
-
-int unit_set_default_slice(Unit *u) {
- _cleanup_free_ char *b = NULL;
- const char *slice_name;
- Unit *slice;
- int r;
-
- assert(u);
-
- 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 */
-
- r = unit_name_to_prefix(u->id, &prefix);
- if (r < 0)
- return r;
-
- /* The prefix is already escaped, but it might include
- * "-" which has a special meaning for slice units,
- * hence escape it here extra. */
- escaped = unit_name_escape(prefix);
- if (!escaped)
- return -ENOMEM;
-
- if (u->manager->running_as == MANAGER_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 == MANAGER_SYSTEM && !unit_has_name(u, SPECIAL_INIT_SCOPE)
- ? SPECIAL_SYSTEM_SLICE
- : SPECIAL_ROOT_SLICE;
-
- r = manager_load_unit(u->manager, slice_name, NULL, NULL, &slice);
- if (r < 0)
- return r;
-
- return unit_set_slice(u, slice);
-}
-
-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);
-
- r = unit_name_change_suffix(u->id, type, &t);
- if (r < 0)
- return r;
- if (unit_has_name(u, t))
- return -EINVAL;
-
- r = manager_load_unit(u->manager, t, NULL, NULL, _found);
- assert(r < 0 || *_found != u);
- return r;
-}
-
-static int signal_name_owner_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- const char *name, *old_owner, *new_owner;
- Unit *u = userdata;
- int r;
-
- assert(message);
- assert(u);
-
- r = sd_bus_message_read(message, "sss", &name, &old_owner, &new_owner);
- if (r < 0) {
- bus_log_parse_error(r);
- return 0;
- }
-
- if (UNIT_VTABLE(u)->bus_name_owner_change)
- UNIT_VTABLE(u)->bus_name_owner_change(u, name, old_owner, new_owner);
-
- return 0;
-}
-
-int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name) {
- const char *match;
-
- assert(u);
- assert(bus);
- assert(name);
-
- if (u->match_bus_slot)
- return -EBUSY;
-
- match = strjoina("type='signal',"
- "sender='org.freedesktop.DBus',"
- "path='/org/freedesktop/DBus',"
- "interface='org.freedesktop.DBus',"
- "member='NameOwnerChanged',"
- "arg0='", name, "'",
- NULL);
-
- return sd_bus_add_match(bus, &u->match_bus_slot, match, signal_name_owner_changed, u);
-}
-
-int unit_watch_bus_name(Unit *u, const char *name) {
- int r;
-
- assert(u);
- assert(name);
-
- /* Watch a specific name on the bus. We only support one unit
- * watching each name for now. */
-
- if (u->manager->api_bus) {
- /* If the bus is already available, install the match directly.
- * Otherwise, just put the name in the list. bus_setup_api() will take care later. */
- r = unit_install_bus_match(u, u->manager->api_bus, name);
- if (r < 0)
- return log_warning_errno(r, "Failed to subscribe to NameOwnerChanged signal for '%s': %m", name);
- }
-
- r = hashmap_put(u->manager->watch_bus, name, u);
- if (r < 0) {
- u->match_bus_slot = sd_bus_slot_unref(u->match_bus_slot);
- return log_warning_errno(r, "Failed to put bus name to hashmap: %m");
- }
-
- return 0;
-}
-
-void unit_unwatch_bus_name(Unit *u, const char *name) {
- assert(u);
- assert(name);
-
- hashmap_remove_value(u->manager->watch_bus, name, u);
- u->match_bus_slot = sd_bus_slot_unref(u->match_bus_slot);
-}
-
-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(u, rt, f, fds);
- if (r < 0)
- return r;
- }
- }
-
- dual_timestamp_serialize(f, "state-change-timestamp", &u->state_change_timestamp);
-
- 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);
- unit_serialize_item(u, f, "cgroup-realized", yes_no(u->cgroup_realized));
-
- 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;
-}
-
-int unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) {
- assert(u);
- assert(f);
- assert(key);
-
- if (!value)
- return 0;
-
- fputs(key, f);
- fputc('=', f);
- fputs(value, f);
- fputc('\n', f);
-
- return 1;
-}
-
-int unit_serialize_item_escaped(Unit *u, FILE *f, const char *key, const char *value) {
- _cleanup_free_ char *c = NULL;
-
- assert(u);
- assert(f);
- assert(key);
-
- if (!value)
- return 0;
-
- c = cescape(value);
- if (!c)
- return -ENOMEM;
-
- fputs(key, f);
- fputc('=', f);
- fputs(c, f);
- fputc('\n', f);
-
- return 1;
-}
-
-int unit_serialize_item_fd(Unit *u, FILE *f, FDSet *fds, const char *key, int fd) {
- int copy;
-
- assert(u);
- assert(f);
- assert(key);
-
- if (fd < 0)
- return 0;
-
- copy = fdset_put_dup(fds, fd);
- if (copy < 0)
- return copy;
-
- fprintf(f, "%s=%i\n", key, copy);
- return 1;
-}
-
-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);
-}
-
-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 (isempty(l))
- break;
-
- 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 log_oom();
-
- 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 for pre-44 */
- log_unit_warning(u, "Update from too old systemd versions are unsupported, cannot deserialize job: %s", v);
- continue;
- } else if (streq(l, "state-change-timestamp")) {
- dual_timestamp_deserialize(v, &u->state_change_timestamp);
- 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")) {
-
- r = parse_boolean(v);
- if (r < 0)
- log_unit_debug(u, "Failed to parse condition result value %s, ignoring.", v);
- else
- u->condition_result = r;
-
- continue;
-
- } else if (streq(l, "assert-result")) {
-
- r = parse_boolean(v);
- if (r < 0)
- log_unit_debug(u, "Failed to parse assert result value %s, ignoring.", v);
- else
- u->assert_result = r;
-
- continue;
-
- } else if (streq(l, "transient")) {
-
- r = parse_boolean(v);
- if (r < 0)
- log_unit_debug(u, "Failed to parse transient bool %s, ignoring.", v);
- else
- u->transient = r;
-
- continue;
-
- } else if (streq(l, "cpuacct-usage-base")) {
-
- r = safe_atou64(v, &u->cpuacct_usage_base);
- if (r < 0)
- log_unit_debug(u, "Failed to parse CPU usage %s, ignoring.", v);
-
- continue;
-
- } else if (streq(l, "cgroup")) {
-
- r = unit_set_cgroup_path(u, v);
- if (r < 0)
- log_unit_debug_errno(u, r, "Failed to set cgroup path %s, ignoring: %m", v);
-
- (void) unit_watch_cgroup(u);
-
- continue;
- } else if (streq(l, "cgroup-realized")) {
- int b;
-
- b = parse_boolean(v);
- if (b < 0)
- log_unit_debug(u, "Failed to parse cgroup-realized bool %s, ignoring.", v);
- else
- u->cgroup_realized = b;
-
- continue;
- }
-
- if (unit_can_serialize(u)) {
- if (rt) {
- r = exec_runtime_deserialize_item(u, rt, l, v, fds);
- if (r < 0) {
- log_unit_warning(u, "Failed to deserialize runtime parameter '%s', ignoring.", l);
- continue;
- }
-
- /* Returns positive if key was handled by the call */
- if (r > 0)
- continue;
- }
-
- r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds);
- if (r < 0)
- log_unit_warning(u, "Failed to deserialize unit parameter '%s', ignoring.", l);
- }
- }
-
- /* Versions before 228 did not carry a state change timestamp. In this case, take the current time. This is
- * useful, so that timeouts based on this timestamp don't trigger too early, and is in-line with the logic from
- * before 228 where the base for timeouts was not persistent across reboots. */
-
- if (!dual_timestamp_is_set(&u->state_change_timestamp))
- dual_timestamp_get(&u->state_change_timestamp);
-
- return 0;
-}
-
-int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency dep) {
- Unit *device;
- _cleanup_free_ char *e = NULL;
- int r;
-
- assert(u);
-
- /* Adds in links to the device node that this unit is based on */
- if (isempty(what))
- return 0;
-
- if (!is_device_path(what))
- return 0;
-
- /* When device units aren't supported (such as in a
- * container), don't create dependencies on them. */
- if (!unit_type_supported(UNIT_DEVICE))
- return 0;
-
- r = unit_name_from_path(what, ".device", &e);
- if (r < 0)
- return r;
-
- 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 == MANAGER_SYSTEM ? dep : 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;
-}
-
-int unit_coldplug(Unit *u) {
- int r = 0, q = 0;
-
- assert(u);
-
- /* Make sure we don't enter a loop, when coldplugging
- * recursively. */
- if (u->coldplugged)
- return 0;
-
- u->coldplugged = true;
-
- if (UNIT_VTABLE(u)->coldplug)
- r = UNIT_VTABLE(u)->coldplug(u);
-
- if (u->job)
- q = job_coldplug(u->job);
-
- if (r < 0)
- return r;
- if (q < 0)
- return q;
-
- return 0;
-}
-
-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);
-
- RATELIMIT_RESET(u->start_limit);
- u->start_limit_hit = false;
-}
-
-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, PID_TO_PTR(main_pid));
- if (r < 0)
- goto fail;
- }
-
- if (control_pid > 0) {
- r = set_put(pid_set, PID_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;
- bool killed = false;
-
- if (IN_SET(who, KILL_MAIN, KILL_MAIN_FAIL)) {
- 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 if (main_pid == 0)
- return sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No main process to kill");
- }
-
- if (IN_SET(who, KILL_CONTROL, KILL_CONTROL_FAIL)) {
- 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 if (control_pid == 0)
- return sd_bus_error_set_const(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
- }
-
- if (IN_SET(who, KILL_CONTROL, KILL_CONTROL_FAIL, KILL_ALL, KILL_ALL_FAIL))
- if (control_pid > 0) {
- if (kill(control_pid, signo) < 0)
- r = -errno;
- else
- killed = true;
- }
-
- if (IN_SET(who, KILL_MAIN, KILL_MAIN_FAIL, KILL_ALL, KILL_ALL_FAIL))
- if (main_pid > 0) {
- if (kill(main_pid, signo) < 0)
- r = -errno;
- else
- killed = true;
- }
-
- if (IN_SET(who, KILL_ALL, KILL_ALL_FAIL) && 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, false, false, pid_set);
- if (q < 0 && q != -EAGAIN && q != -ESRCH && q != -ENOENT)
- r = q;
- else
- killed = true;
- }
-
- if (r == 0 && !killed && IN_SET(who, KILL_ALL_FAIL, KILL_CONTROL_FAIL))
- return -ESRCH;
-
- 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) {
- int r;
-
- assert(u);
-
- if (u->unit_file_state < 0 && u->fragment_path) {
- r = unit_file_get_state(
- u->manager->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER,
- NULL,
- basename(u->fragment_path),
- &u->unit_file_state);
- if (r < 0)
- u->unit_file_state = UNIT_FILE_BAD;
- }
-
- 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 == MANAGER_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 == MANAGER_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 == MANAGER_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 &= ~(UINT64_C(1) << 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) {
- assert(u);
-
- if (u->manager->running_as == MANAGER_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;
-}
-
-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_make_transient(Unit *u) {
- assert(u);
-
- if (!UNIT_VTABLE(u)->can_transient)
- return -EOPNOTSUPP;
-
- u->load_state = UNIT_STUB;
- u->load_error = 0;
- u->transient = true;
-
- u->fragment_path = mfree(u->fragment_path);
- u->source_path = mfree(u->source_path);
- u->dropin_paths = strv_free(u->dropin_paths);
- u->fragment_mtime = u->source_mtime = u->dropin_mtime = 0;
-
- unit_add_to_dbus_queue(u);
- unit_add_to_gc_queue(u);
- unit_add_to_load_queue(u);
-
- return 0;
-}
-
-int unit_kill_context(
- Unit *u,
- KillContext *c,
- KillOperation k,
- pid_t main_pid,
- pid_t control_pid,
- bool main_pid_alien) {
-
- bool wait_for_exit = false;
- int sig, 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, r, "Failed to kill main process " PID_FMT " (%s), ignoring: %m", main_pid, strna(comm));
- } else {
- if (!main_pid_alien)
- wait_for_exit = true;
-
- if (c->send_sighup && k == KILL_TERMINATE)
- (void) 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, r, "Failed to kill control process " PID_FMT " (%s), ignoring: %m", control_pid, strna(comm));
- } else {
- wait_for_exit = true;
-
- if (c->send_sighup && k == KILL_TERMINATE)
- (void) kill(control_pid, SIGHUP);
- }
- }
-
- if (u->cgroup_path &&
- (c->kill_mode == KILL_CONTROL_GROUP || (c->kill_mode == KILL_MIXED && k == KILL_KILL))) {
- _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, k != KILL_TERMINATE, false, pid_set);
- if (r < 0) {
- if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
- log_unit_warning_errno(u, r, "Failed to kill control group %s, ignoring: %m", u->cgroup_path);
-
- } else if (r > 0) {
-
- /* FIXME: For now, on the legacy hierarchy, we
- * will not wait for the cgroup members to die
- * if we are running in a container or if this
- * is a delegation unit, simply because cgroup
- * notification is unreliable in these
- * cases. It doesn't work at all in
- * containers, and outside of containers it
- * can be confused easily by left-over
- * directories in the cgroup -- which however
- * should not exist in non-delegated units. On
- * the unified hierarchy that's different,
- * there we get proper events. Hence rely on
- * them.*/
-
- if (cg_unified() > 0 ||
- (detect_container() == 0 && !unit_cgroup_delegate(u)))
- 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;
-
- r = hashmap_ensure_allocated(&u->manager->units_requiring_mounts_for, &string_hash_ops);
- if (r < 0)
- return r;
-
- 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);
-}
-
-bool unit_type_supported(UnitType t) {
- if (_unlikely_(t < 0))
- return false;
- if (_unlikely_(t >= _UNIT_TYPE_MAX))
- return false;
-
- if (!unit_vtable[t]->supported)
- return true;
-
- return unit_vtable[t]->supported();
-}
-
-void unit_warn_if_dir_nonempty(Unit *u, const char* where) {
- int r;
-
- assert(u);
- assert(where);
-
- r = dir_is_empty(where);
- if (r > 0)
- return;
- if (r < 0) {
- log_unit_warning_errno(u, r, "Failed to check directory %s: %m", where);
- return;
- }
-
- log_struct(LOG_NOTICE,
- LOG_MESSAGE_ID(SD_MESSAGE_OVERMOUNTING),
- LOG_UNIT_ID(u),
- LOG_UNIT_MESSAGE(u, "Directory %s to mount over is not empty, mounting anyway.", where),
- "WHERE=%s", where,
- NULL);
-}
-
-int unit_fail_if_symlink(Unit *u, const char* where) {
- int r;
-
- assert(u);
- assert(where);
-
- r = is_symlink(where);
- if (r < 0) {
- log_unit_debug_errno(u, r, "Failed to check symlink %s, ignoring: %m", where);
- return 0;
- }
- if (r == 0)
- return 0;
-
- log_struct(LOG_ERR,
- LOG_MESSAGE_ID(SD_MESSAGE_OVERMOUNTING),
- LOG_UNIT_ID(u),
- LOG_UNIT_MESSAGE(u, "Mount on symlink %s not allowed.", where),
- "WHERE=%s", where,
- NULL);
-
- return -ELOOP;
-}
-
-bool unit_is_pristine(Unit *u) {
- assert(u);
-
- /* Check if the unit already exists or is already around,
- * in a number of different ways. Note that to cater for unit
- * types such as slice, we are generally fine with units that
- * are marked UNIT_LOADED even even though nothing was
- * actually loaded, as those unit types don't require a file
- * on disk to validly load. */
-
- return !(!IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_LOADED) ||
- u->fragment_path ||
- u->source_path ||
- !strv_isempty(u->dropin_paths) ||
- u->job ||
- u->merged_into);
-}
diff --git a/src/core/unit.h b/src/core/unit.h
deleted file mode 100644
index 601e763ce2..0000000000
--- a/src/core/unit.h
+++ /dev/null
@@ -1,630 +0,0 @@
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-typedef struct Unit Unit;
-typedef struct UnitVTable UnitVTable;
-typedef struct UnitRef UnitRef;
-typedef struct UnitStatusMessageFormats UnitStatusMessageFormats;
-
-#include "condition.h"
-#include "failure-action.h"
-#include "install.h"
-#include "list.h"
-#include "unit-name.h"
-
-typedef enum KillOperation {
- KILL_TERMINATE,
- KILL_KILL,
- KILL_ABORT,
- _KILL_OPERATION_MAX,
- _KILL_OPERATION_INVALID = -1
-} 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;
-
- /* The slot used for watching NameOwnerChanged signals */
- sd_bus_slot *match_bus_slot;
-
- /* 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;
-
- /* Updated whenever the low-level state changes */
- dual_timestamp state_change_timestamp;
-
- /* Updated whenever the (high-level) active state enters or leaves the active or inactive states */
- 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);
-
- /* Units with the same CGroup netclass */
- LIST_FIELDS(Unit, cgroup_netclass);
-
- /* 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;
-
- /* Error code when we didn't manage to load the unit (negative) */
- int load_error;
-
- /* Put a ratelimit on unit starting */
- RateLimit start_limit;
- FailureAction start_limit_action;
- char *reboot_arg;
-
- /* Make sure we never enter endless loops with the check unneeded logic, or the BindsTo= logic */
- RateLimit auto_stop_ratelimit;
-
- /* 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;
- CGroupMask cgroup_realized_mask;
- CGroupMask cgroup_subtree_mask;
- CGroupMask cgroup_members_mask;
- int cgroup_inotify_wd;
-
- uint32_t cgroup_netclass_id;
-
- /* 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;
-
- /* 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;
-
- bool start_limit_hit:1;
-
- /* Did we already invoke unit_coldplug() for this unit? */
- bool coldplugged: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 "automount.h"
-#include "busname.h"
-#include "device.h"
-#include "path.h"
-#include "scope.h"
-#include "slice.h"
-#include "socket.h"
-#include "swap.h"
-#include "target.h"
-#include "timer.h"
-
-struct UnitVTable {
- /* 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(). */
- int (*coldplug)(Unit *u);
-
- 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 */
- void (*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);
-
- /* 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);
-
- /* Returns the next timeout of a unit */
- int (*get_timeout)(Unit *u, usec_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. */
- void (*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)(void);
-
- /* 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;
-
- /* 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_HAS_EXEC_CONTEXT(u) (UNIT_VTABLE(u)->exec_context_offset > 0)
-#define UNIT_HAS_CGROUP_CONTEXT(u) (UNIT_VTABLE(u)->cgroup_context_offset > 0)
-#define UNIT_HAS_KILL_CONTEXT(u) (UNIT_VTABLE(u)->kill_context_offset > 0)
-
-#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(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_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_set_slice(Unit *u, Unit *slice);
-int unit_set_default_slice(Unit *u);
-
-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);
-void unit_unwatch_all_pids(Unit *u);
-
-void unit_tidy_watch_pids(Unit *u, pid_t except1, pid_t except2);
-
-int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name);
-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);
-int unit_deserialize(Unit *u, FILE *f, FDSet *fds);
-
-int unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value);
-int unit_serialize_item_escaped(Unit *u, FILE *f, const char *key, const char *value);
-int unit_serialize_item_fd(Unit *u, FILE *f, FDSet *fds, const char *key, int fd);
-void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_(4,5);
-
-int unit_add_node_link(Unit *u, const char *what, bool wants, UnitDependency d);
-
-int unit_coldplug(Unit *u);
-
-void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) _printf_(3, 0);
-void unit_status_emit_starting_stopping_reloading(Unit *u, JobType t);
-
-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);
-
-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_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);
-
-bool unit_type_supported(UnitType t);
-
-bool unit_is_pristine(Unit *u);
-
-static inline bool unit_supported(Unit *u) {
- return unit_type_supported(u->type);
-}
-
-void unit_warn_if_dir_nonempty(Unit *u, const char* where);
-int unit_fail_if_symlink(Unit *u, const char* where);
-
-/* Macros which append UNIT= or USER_UNIT= to the message */
-
-#define log_unit_full(unit, level, error, ...) \
- ({ \
- Unit *_u = (unit); \
- _u ? log_object_internal(level, error, __FILE__, __LINE__, __func__, _u->manager->unit_log_field, _u->id, ##__VA_ARGS__) : \
- log_internal(level, error, __FILE__, __LINE__, __func__, ##__VA_ARGS__); \
- })
-
-#define log_unit_debug(unit, ...) log_unit_full(unit, LOG_DEBUG, 0, ##__VA_ARGS__)
-#define log_unit_info(unit, ...) log_unit_full(unit, LOG_INFO, 0, ##__VA_ARGS__)
-#define log_unit_notice(unit, ...) log_unit_full(unit, LOG_NOTICE, 0, ##__VA_ARGS__)
-#define log_unit_warning(unit, ...) log_unit_full(unit, LOG_WARNING, 0, ##__VA_ARGS__)
-#define log_unit_error(unit, ...) log_unit_full(unit, LOG_ERR, 0, ##__VA_ARGS__)
-
-#define log_unit_debug_errno(unit, error, ...) log_unit_full(unit, LOG_DEBUG, error, ##__VA_ARGS__)
-#define log_unit_info_errno(unit, error, ...) log_unit_full(unit, LOG_INFO, error, ##__VA_ARGS__)
-#define log_unit_notice_errno(unit, error, ...) log_unit_full(unit, LOG_NOTICE, error, ##__VA_ARGS__)
-#define log_unit_warning_errno(unit, error, ...) log_unit_full(unit, LOG_WARNING, error, ##__VA_ARGS__)
-#define log_unit_error_errno(unit, error, ...) log_unit_full(unit, LOG_ERR, error, ##__VA_ARGS__)
-
-#define LOG_UNIT_MESSAGE(unit, fmt, ...) "MESSAGE=%s: " fmt, (unit)->id, ##__VA_ARGS__
-#define LOG_UNIT_ID(unit) (unit)->manager->unit_log_format_string, (unit)->id
diff --git a/src/core/user.conf b/src/core/user.conf
deleted file mode 100644
index 87c8164378..0000000000
--- 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=