summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/.gitignore6
l---------src/core/Makefile1
-rw-r--r--src/core/audit-fd.c73
-rw-r--r--src/core/audit-fd.h25
-rw-r--r--src/core/automount.c902
-rw-r--r--src/core/automount.h73
-rw-r--r--src/core/build.h84
-rw-r--r--src/core/bus-errors.h55
-rw-r--r--src/core/cgroup-attr.c102
-rw-r--r--src/core/cgroup-attr.h46
-rw-r--r--src/core/cgroup.c598
-rw-r--r--src/core/cgroup.h91
-rw-r--r--src/core/condition.c370
-rw-r--r--src/core/condition.h69
-rw-r--r--src/core/dbus-automount.c75
-rw-r--r--src/core/dbus-automount.h31
-rw-r--r--src/core/dbus-device.c68
-rw-r--r--src/core/dbus-device.h31
-rw-r--r--src/core/dbus-execute.c439
-rw-r--r--src/core/dbus-execute.h124
-rw-r--r--src/core/dbus-job.c378
-rw-r--r--src/core/dbus-job.h33
-rw-r--r--src/core/dbus-kill.c35
-rw-r--r--src/core/dbus-kill.h39
-rw-r--r--src/core/dbus-manager.c1685
-rw-r--r--src/core/dbus-manager.h28
-rw-r--r--src/core/dbus-mount.c168
-rw-r--r--src/core/dbus-mount.h31
-rw-r--r--src/core/dbus-path.c122
-rw-r--r--src/core/dbus-path.h32
-rw-r--r--src/core/dbus-service.c161
-rw-r--r--src/core/dbus-service.h31
-rw-r--r--src/core/dbus-snapshot.c94
-rw-r--r--src/core/dbus-snapshot.h30
-rw-r--r--src/core/dbus-socket.c151
-rw-r--r--src/core/dbus-socket.h31
-rw-r--r--src/core/dbus-swap.c115
-rw-r--r--src/core/dbus-swap.h32
-rw-r--r--src/core/dbus-target.c58
-rw-r--r--src/core/dbus-target.h30
-rw-r--r--src/core/dbus-timer.c140
-rw-r--r--src/core/dbus-timer.h31
-rw-r--r--src/core/dbus-unit.c887
-rw-r--r--src/core/dbus-unit.h147
-rw-r--r--src/core/dbus.c1479
-rw-r--r--src/core/dbus.h50
-rw-r--r--src/core/device.c644
-rw-r--r--src/core/device.h56
-rw-r--r--src/core/execute.c2132
-rw-r--r--src/core/execute.h209
-rw-r--r--src/core/fdset.c167
-rw-r--r--src/core/fdset.h37
-rw-r--r--src/core/hostname-setup.c182
-rw-r--r--src/core/hostname-setup.h24
-rw-r--r--src/core/ima-setup.c115
-rw-r--r--src/core/ima-setup.h26
-rw-r--r--src/core/initreq.h77
-rw-r--r--src/core/job.c1086
-rw-r--r--src/core/job.h230
-rw-r--r--src/core/kill.c63
-rw-r--r--src/core/kill.h60
-rw-r--r--src/core/killall.c177
-rw-r--r--src/core/killall.h27
-rw-r--r--src/core/kmod-setup.c104
-rw-r--r--src/core/kmod-setup.h24
-rw-r--r--src/core/load-dropin.c150
-rw-r--r--src/core/load-dropin.h28
-rw-r--r--src/core/load-fragment-gperf.gperf.m4255
-rw-r--r--src/core/load-fragment.c2541
-rw-r--r--src/core/load-fragment.h88
-rw-r--r--src/core/locale-setup.c241
-rw-r--r--src/core/locale-setup.h24
-rw-r--r--src/core/loopback-setup.c317
-rw-r--r--src/core/loopback-setup.h24
-rw-r--r--src/core/machine-id-setup.c246
-rw-r--r--src/core/machine-id-setup.h24
-rw-r--r--src/core/macros.systemd.in56
-rw-r--r--src/core/main.c1950
-rw-r--r--src/core/manager.c2309
-rw-r--r--src/core/manager.h293
-rw-r--r--src/core/mount-setup.c441
-rw-r--r--src/core/mount-setup.h33
-rw-r--r--src/core/mount.c1885
-rw-r--r--src/core/mount.h121
-rw-r--r--src/core/namespace.c330
-rw-r--r--src/core/namespace.h31
-rw-r--r--src/core/org.freedesktop.systemd1.conf92
-rw-r--r--src/core/org.freedesktop.systemd1.policy.in.in41
-rw-r--r--src/core/org.freedesktop.systemd1.service11
-rw-r--r--src/core/path.c773
-rw-r--r--src/core/path.h110
-rw-r--r--src/core/securebits.h45
-rw-r--r--src/core/selinux-access.c441
-rw-r--r--src/core/selinux-access.h62
-rw-r--r--src/core/selinux-setup.c123
-rw-r--r--src/core/selinux-setup.h26
-rw-r--r--src/core/service.c3941
-rw-r--r--src/core/service.h225
-rw-r--r--src/core/shutdown.c316
-rw-r--r--src/core/snapshot.c308
-rw-r--r--src/core/snapshot.h50
-rw-r--r--src/core/socket.c2289
-rw-r--r--src/core/socket.h175
-rw-r--r--src/core/special.h113
-rw-r--r--src/core/swap.c1433
-rw-r--r--src/core/swap.h121
-rw-r--r--src/core/switch-root.c142
-rw-r--r--src/core/switch-root.h27
-rw-r--r--src/core/syscall-list.c55
-rw-r--r--src/core/syscall-list.h30
-rw-r--r--src/core/sysfs-show.h24
-rw-r--r--src/core/system.conf43
-rw-r--r--src/core/systemd.pc.in23
-rw-r--r--src/core/target.c239
-rw-r--r--src/core/target.h44
-rw-r--r--src/core/tcpwrap.c68
-rw-r--r--src/core/tcpwrap.h26
-rw-r--r--src/core/timer.c519
-rw-r--r--src/core/timer.h90
-rw-r--r--src/core/transaction.c1087
-rw-r--r--src/core/transaction.h56
-rw-r--r--src/core/umount.c639
-rw-r--r--src/core/umount.h30
-rw-r--r--src/core/unit-printf.c346
-rw-r--r--src/core/unit-printf.h28
-rw-r--r--src/core/unit.c2738
-rw-r--r--src/core/unit.h551
-rw-r--r--src/core/user.conf17
128 files changed, 0 insertions, 43625 deletions
diff --git a/src/core/.gitignore b/src/core/.gitignore
deleted file mode 100644
index a763f72507..0000000000
--- a/src/core/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-/syscall-from-name.gperf
-/syscall-from-name.h
-/syscall-list.txt
-/syscall-to-name.h
-/macros.systemd
-/systemd.pc
diff --git a/src/core/Makefile b/src/core/Makefile
deleted file mode 120000
index d0b0e8e008..0000000000
--- a/src/core/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../Makefile \ No newline at end of file
diff --git a/src/core/audit-fd.c b/src/core/audit-fd.c
deleted file mode 100644
index 5955bd846e..0000000000
--- a/src/core/audit-fd.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2012 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-
-#include <errno.h>
-#include "audit-fd.h"
-
-#ifdef HAVE_AUDIT
-
-#include <stdbool.h>
-#include <libaudit.h>
-
-#include "log.h"
-#include "util.h"
-
-static bool initialized = false;
-static int audit_fd;
-
-int get_audit_fd(void) {
-
- if (!initialized) {
- audit_fd = audit_open();
-
- if (audit_fd < 0) {
- if (errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT)
- log_error("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)
- close_nointr_nofail(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 8b58289dc5..0000000000
--- a/src/core/audit-fd.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2012 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-int get_audit_fd(void);
-void close_audit_fd(void);
diff --git a/src/core/automount.c b/src/core/automount.c
deleted file mode 100644
index b1619a64e6..0000000000
--- a/src/core/automount.c
+++ /dev/null
@@ -1,902 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <limits.h>
-#include <sys/mount.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/epoll.h>
-#include <sys/stat.h>
-#include <linux/auto_fs4.h>
-#include <linux/auto_dev-ioctl.h>
-
-#include "unit.h"
-#include "automount.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
-#include "unit-name.h"
-#include "dbus-automount.h"
-#include "bus-errors.h"
-#include "special.h"
-#include "label.h"
-#include "mkdir.h"
-#include "path-util.h"
-
-static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = {
- [AUTOMOUNT_DEAD] = UNIT_INACTIVE,
- [AUTOMOUNT_WAITING] = UNIT_ACTIVE,
- [AUTOMOUNT_RUNNING] = UNIT_ACTIVE,
- [AUTOMOUNT_FAILED] = UNIT_FAILED
-};
-
-static int open_dev_autofs(Manager *m);
-
-static void automount_init(Unit *u) {
- Automount *a = AUTOMOUNT(u);
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
-
- a->pipe_watch.fd = a->pipe_fd = -1;
- a->pipe_watch.type = WATCH_INVALID;
-
- a->directory_mode = 0755;
-
- UNIT(a)->ignore_on_isolate = true;
-}
-
-static void repeat_unmout(const char *path) {
- assert(path);
-
- for (;;) {
- /* If there are multiple mounts on a mount point, this
- * removes them all */
-
- if (umount2(path, MNT_DETACH) >= 0)
- continue;
-
- if (errno != EINVAL)
- log_error("Failed to unmount: %m");
-
- break;
- }
-}
-
-static void unmount_autofs(Automount *a) {
- assert(a);
-
- if (a->pipe_fd < 0)
- return;
-
- automount_send_ready(a, -EHOSTDOWN);
-
- unit_unwatch_fd(UNIT(a), &a->pipe_watch);
- close_nointr_nofail(a->pipe_fd);
- a->pipe_fd = -1;
-
- /* If we reload/reexecute things we keep the mount point
- * around */
- if (a->where &&
- (UNIT(a)->manager->exit_code != MANAGER_RELOAD &&
- UNIT(a)->manager->exit_code != MANAGER_REEXECUTE))
- repeat_unmout(a->where);
-}
-
-static void automount_done(Unit *u) {
- Automount *a = AUTOMOUNT(u);
-
- assert(a);
-
- unmount_autofs(a);
- unit_ref_unset(&a->mount);
-
- free(a->where);
- a->where = NULL;
-
- set_free(a->tokens);
- a->tokens = NULL;
-}
-
-int automount_add_one_mount_link(Automount *a, Mount *m) {
- int r;
-
- assert(a);
- assert(m);
-
- if (UNIT(a)->load_state != UNIT_LOADED ||
- UNIT(m)->load_state != UNIT_LOADED)
- return 0;
-
- if (!path_startswith(a->where, m->where))
- return 0;
-
- if (path_equal(a->where, m->where))
- return 0;
-
- if ((r = unit_add_two_dependencies(UNIT(a), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true)) < 0)
- return r;
-
- return 0;
-}
-
-static int automount_add_mount_links(Automount *a) {
- Unit *other;
- int r;
-
- assert(a);
-
- LIST_FOREACH(units_by_type, other, UNIT(a)->manager->units_by_type[UNIT_MOUNT])
- if ((r = automount_add_one_mount_link(a, MOUNT(other))) < 0)
- return r;
-
- return 0;
-}
-
-static int automount_add_default_dependencies(Automount *a) {
- int r;
-
- assert(a);
-
- if (UNIT(a)->manager->running_as != SYSTEMD_SYSTEM)
- return 0;
-
- r = unit_add_two_dependencies_by_name(UNIT(a), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-static int automount_verify(Automount *a) {
- bool b;
- char *e;
- assert(a);
-
- if (UNIT(a)->load_state != UNIT_LOADED)
- return 0;
-
- if (path_equal(a->where, "/")) {
- log_error("Cannot have an automount unit for the root directory. Refusing.");
- return -EINVAL;
- }
-
- if (!(e = unit_name_from_path(a->where, ".automount")))
- return -ENOMEM;
-
- b = unit_has_name(UNIT(a), e);
- free(e);
-
- if (!b) {
- log_error("%s's Where setting doesn't match unit name. Refusing.", UNIT(a)->id);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int automount_load(Unit *u) {
- int r;
- Automount *a = AUTOMOUNT(u);
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
-
- /* Load a .automount file */
- if ((r = unit_load_fragment_and_dropin_optional(u)) < 0)
- return r;
-
- if (u->load_state == UNIT_LOADED) {
- Unit *x;
-
- if (!a->where)
- if (!(a->where = unit_name_to_path(u->id)))
- return -ENOMEM;
-
- path_kill_slashes(a->where);
-
- if ((r = automount_add_mount_links(a)) < 0)
- return r;
-
- r = unit_load_related_unit(u, ".mount", &x);
- if (r < 0)
- return r;
-
- unit_ref_set(&a->mount, x);
-
- r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(a->mount), true);
- if (r < 0)
- return r;
-
- if (UNIT(a)->default_dependencies)
- if ((r = automount_add_default_dependencies(a)) < 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_debug("%s changed %s -> %s",
- UNIT(a)->id,
- automount_state_to_string(old_state),
- automount_state_to_string(state));
-
- unit_notify(UNIT(a), state_translation_table[old_state], state_translation_table[state], true);
-}
-
-static int automount_coldplug(Unit *u) {
- Automount *a = AUTOMOUNT(u);
- int r;
-
- assert(a);
- assert(a->state == AUTOMOUNT_DEAD);
-
- if (a->deserialized_state != a->state) {
-
- if ((r = open_dev_autofs(u->manager)) < 0)
- return r;
-
- if (a->deserialized_state == AUTOMOUNT_WAITING ||
- a->deserialized_state == AUTOMOUNT_RUNNING) {
-
- assert(a->pipe_fd >= 0);
-
- if ((r = unit_watch_fd(UNIT(a), a->pipe_fd, EPOLLIN, &a->pipe_watch)) < 0)
- return r;
- }
-
- automount_set_state(a, a->deserialized_state);
- }
-
- return 0;
-}
-
-static void automount_dump(Unit *u, FILE *f, const char *prefix) {
- Automount *a = AUTOMOUNT(u);
-
- assert(a);
-
- fprintf(f,
- "%sAutomount State: %s\n"
- "%sResult: %s\n"
- "%sWhere: %s\n"
- "%sDirectoryMode: %04o\n",
- prefix, automount_state_to_string(a->state),
- prefix, automount_result_to_string(a->result),
- prefix, a->where,
- prefix, a->directory_mode);
-}
-
-static void automount_enter_dead(Automount *a, AutomountResult f) {
- assert(a);
-
- if (f != AUTOMOUNT_SUCCESS)
- a->result = f;
-
- automount_set_state(a, a->result != AUTOMOUNT_SUCCESS ? AUTOMOUNT_FAILED : AUTOMOUNT_DEAD);
-}
-
-static int open_dev_autofs(Manager *m) {
- struct autofs_dev_ioctl param;
-
- assert(m);
-
- if (m->dev_autofs_fd >= 0)
- return m->dev_autofs_fd;
-
- label_fix("/dev/autofs", false, false);
-
- if ((m->dev_autofs_fd = open("/dev/autofs", O_CLOEXEC|O_RDONLY)) < 0) {
- log_error("Failed to open /dev/autofs: %s", strerror(errno));
- return -errno;
- }
-
- init_autofs_dev_ioctl(&param);
- if (ioctl(m->dev_autofs_fd, AUTOFS_DEV_IOCTL_VERSION, &param) < 0) {
- close_nointr_nofail(m->dev_autofs_fd);
- m->dev_autofs_fd = -1;
- 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;
- int r;
-
- assert(dev_autofs_fd >= 0);
- assert(where);
-
- l = sizeof(struct autofs_dev_ioctl) + strlen(where) + 1;
-
- if (!(param = malloc(l)))
- return -ENOMEM;
-
- 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) {
- r = -errno;
- goto finish;
- }
-
- if (param->ioctlfd < 0) {
- r = -EIO;
- goto finish;
- }
-
- fd_cloexec(param->ioctlfd, true);
- r = param->ioctlfd;
-
-finish:
- free(param);
- return r;
-}
-
-static int autofs_protocol(int dev_autofs_fd, int ioctl_fd) {
- uint32_t major, minor;
- struct autofs_dev_ioctl param;
-
- assert(dev_autofs_fd >= 0);
- assert(ioctl_fd >= 0);
-
- init_autofs_dev_ioctl(&param);
- param.ioctlfd = ioctl_fd;
-
- if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_PROTOVER, &param) < 0)
- return -errno;
-
- major = param.protover.version;
-
- init_autofs_dev_ioctl(&param);
- param.ioctlfd = ioctl_fd;
-
- if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_PROTOSUBVER, &param) < 0)
- return -errno;
-
- minor = param.protosubver.sub_version;
-
- log_debug("Autofs protocol version %i.%i", major, minor);
- return 0;
-}
-
-static int autofs_set_timeout(int dev_autofs_fd, int ioctl_fd, time_t sec) {
- struct autofs_dev_ioctl param;
-
- assert(dev_autofs_fd >= 0);
- assert(ioctl_fd >= 0);
-
- init_autofs_dev_ioctl(&param);
- param.ioctlfd = ioctl_fd;
- param.timeout.timeout = sec;
-
- if (ioctl(dev_autofs_fd, AUTOFS_DEV_IOCTL_TIMEOUT, &param) < 0)
- return -errno;
-
- return 0;
-}
-
-static int autofs_send_ready(int dev_autofs_fd, int ioctl_fd, uint32_t token, int status) {
- struct autofs_dev_ioctl param;
-
- assert(dev_autofs_fd >= 0);
- assert(ioctl_fd >= 0);
-
- init_autofs_dev_ioctl(&param);
- param.ioctlfd = ioctl_fd;
-
- if (status) {
- param.fail.token = token;
- param.fail.status = status;
- } else
- param.ready.token = token;
-
- if (ioctl(dev_autofs_fd, status ? AUTOFS_DEV_IOCTL_FAIL : AUTOFS_DEV_IOCTL_READY, &param) < 0)
- return -errno;
-
- return 0;
-}
-
-int automount_send_ready(Automount *a, int status) {
- int ioctl_fd, r;
- unsigned token;
-
- assert(a);
- assert(status <= 0);
-
- if (set_isempty(a->tokens))
- return 0;
-
- if ((ioctl_fd = open_ioctl_fd(UNIT(a)->manager->dev_autofs_fd, a->where, a->dev_id)) < 0) {
- r = ioctl_fd;
- goto fail;
- }
-
- if (status)
- log_debug("Sending failure: %s", strerror(-status));
- else
- log_debug("Sending success.");
-
- r = 0;
-
- /* Autofs thankfully does not hand out 0 as a token */
- while ((token = PTR_TO_UINT(set_steal_first(a->tokens)))) {
- int k;
-
- /* Autofs fun fact II:
- *
- * if you pass a positive status code here, the kernel will
- * freeze! Yay! */
-
- if ((k = autofs_send_ready(UNIT(a)->manager->dev_autofs_fd,
- ioctl_fd,
- token,
- status)) < 0)
- r = k;
- }
-
-fail:
- if (ioctl_fd >= 0)
- close_nointr_nofail(ioctl_fd);
-
- return r;
-}
-
-static void automount_enter_waiting(Automount *a) {
- int p[2] = { -1, -1 };
- char name[32], options[128];
- bool mounted = false;
- int r, ioctl_fd = -1, dev_autofs_fd;
- struct stat st;
-
- assert(a);
- assert(a->pipe_fd < 0);
- assert(a->where);
-
- if (a->tokens)
- set_clear(a->tokens);
-
- if ((dev_autofs_fd = open_dev_autofs(UNIT(a)->manager)) < 0) {
- r = dev_autofs_fd;
- goto fail;
- }
-
- /* We knowingly ignore the results of this call */
- mkdir_p_label(a->where, 0555);
-
- if (dir_is_empty(a->where) <= 0)
- log_notice("%s: Directory %s to mount over is not empty, mounting anyway. (To see the over-mounted files, please manually mount the underlying file system to a secondary location.)", a->meta.id, a->where);
-
- if (pipe2(p, O_NONBLOCK|O_CLOEXEC) < 0) {
- r = -errno;
- goto fail;
- }
-
- snprintf(options, sizeof(options), "fd=%i,pgrp=%u,minproto=5,maxproto=5,direct", p[1], (unsigned) getpgrp());
- char_array_0(options);
-
- snprintf(name, sizeof(name), "systemd-%u", (unsigned) getpid());
- char_array_0(name);
-
- if (mount(name, a->where, "autofs", 0, options) < 0) {
- r = -errno;
- goto fail;
- }
-
- mounted = true;
-
- close_nointr_nofail(p[1]);
- p[1] = -1;
-
- if (stat(a->where, &st) < 0) {
- r = -errno;
- goto fail;
- }
-
- if ((ioctl_fd = open_ioctl_fd(dev_autofs_fd, a->where, st.st_dev)) < 0) {
- r = ioctl_fd;
- goto fail;
- }
-
- if ((r = autofs_protocol(dev_autofs_fd, ioctl_fd)) < 0)
- goto fail;
-
- if ((r = autofs_set_timeout(dev_autofs_fd, ioctl_fd, 300)) < 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. */
-
- close_nointr_nofail(ioctl_fd);
- ioctl_fd = -1;
-
- if ((r = unit_watch_fd(UNIT(a), p[0], EPOLLIN, &a->pipe_watch)) < 0)
- goto fail;
-
- a->pipe_fd = p[0];
- a->dev_id = st.st_dev;
-
- automount_set_state(a, AUTOMOUNT_WAITING);
-
- return;
-
-fail:
- assert_se(close_pipe(p) == 0);
-
- if (ioctl_fd >= 0)
- close_nointr_nofail(ioctl_fd);
-
- if (mounted)
- repeat_unmout(a->where);
-
- log_error("Failed to initialize automounter: %s", strerror(-r));
- automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
-}
-
-static void automount_enter_runnning(Automount *a) {
- int r;
- struct stat st;
- DBusError error;
-
- assert(a);
- assert(UNIT_DEREF(a->mount));
-
- dbus_error_init(&error);
-
- /* We don't take mount requests anymore if we are supposed to
- * shut down anyway */
- if (unit_pending_inactive(UNIT(a))) {
- log_debug("Suppressing automount request on %s since unit stop is scheduled.", UNIT(a)->id);
- automount_send_ready(a, -EHOSTDOWN);
- return;
- }
-
- mkdir_p_label(a->where, a->directory_mode);
-
- /* Before we do anything, let's see if somebody is playing games with us? */
- if (lstat(a->where, &st) < 0) {
- log_warning("%s failed to stat automount point: %m", UNIT(a)->id);
- goto fail;
- }
-
- if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id)
- log_info("%s's automount point already active?", UNIT(a)->id);
- else if ((r = manager_add_job(UNIT(a)->manager, JOB_START, UNIT_DEREF(a->mount), JOB_REPLACE, true, &error, NULL)) < 0) {
- log_warning("%s failed to queue mount startup job: %s", UNIT(a)->id, bus_error(&error, r));
- goto fail;
- }
-
- automount_set_state(a, AUTOMOUNT_RUNNING);
- return;
-
-fail:
- automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
- dbus_error_free(&error);
-}
-
-static int automount_start(Unit *u) {
- Automount *a = AUTOMOUNT(u);
-
- assert(a);
-
- assert(a->state == AUTOMOUNT_DEAD || a->state == AUTOMOUNT_FAILED);
-
- if (path_is_mount_point(a->where, false)) {
- log_error("Path %s is already a mount point, refusing start for %s", a->where, u->id);
- return -EEXIST;
- }
-
- if (UNIT_DEREF(a->mount)->load_state != UNIT_LOADED)
- return -ENOENT;
-
- a->result = AUTOMOUNT_SUCCESS;
- automount_enter_waiting(a);
- return 0;
-}
-
-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 0;
-}
-
-static int automount_serialize(Unit *u, FILE *f, FDSet *fds) {
- Automount *a = AUTOMOUNT(u);
- void *p;
- Iterator i;
-
- assert(a);
- assert(f);
- assert(fds);
-
- unit_serialize_item(u, f, "state", automount_state_to_string(a->state));
- unit_serialize_item(u, f, "result", automount_result_to_string(a->result));
- unit_serialize_item_format(u, f, "dev-id", "%u", (unsigned) a->dev_id);
-
- SET_FOREACH(p, a->tokens, i)
- unit_serialize_item_format(u, f, "token", "%u", PTR_TO_UINT(p));
-
- if (a->pipe_fd >= 0) {
- int copy;
-
- if ((copy = fdset_put_dup(fds, a->pipe_fd)) < 0)
- return copy;
-
- unit_serialize_item_format(u, f, "pipe-fd", "%i", copy);
- }
-
- return 0;
-}
-
-static int automount_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Automount *a = AUTOMOUNT(u);
- int r;
-
- assert(a);
- assert(fds);
-
- if (streq(key, "state")) {
- AutomountState state;
-
- if ((state = automount_state_from_string(value)) < 0)
- log_debug("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_debug("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_debug("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_debug("Failed to parse token value %s", value);
- else {
- if (!a->tokens)
- if (!(a->tokens = set_new(trivial_hash_func, trivial_compare_func)))
- return -ENOMEM;
-
- if ((r = set_put(a->tokens, UINT_TO_PTR(token))) < 0)
- return r;
- }
- } else if (streq(key, "pipe-fd")) {
- int fd;
-
- if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_debug("Failed to parse pipe-fd value %s", value);
- else {
- if (a->pipe_fd >= 0)
- close_nointr_nofail(a->pipe_fd);
-
- a->pipe_fd = fdset_remove(fds, fd);
- }
- } else
- log_debug("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) {
- Automount *a = AUTOMOUNT(u);
-
- assert(a);
-
- if (!UNIT_DEREF(a->mount))
- return false;
-
- return UNIT_VTABLE(UNIT_DEREF(a->mount))->check_gc(UNIT_DEREF(a->mount));
-}
-
-static void automount_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
- Automount *a = AUTOMOUNT(u);
- union autofs_v5_packet_union packet;
- ssize_t l;
- int r;
-
- assert(a);
- assert(fd == a->pipe_fd);
-
- if (events != EPOLLIN) {
- log_error("Got invalid poll event on pipe.");
- goto fail;
- }
-
- if ((l = loop_read(a->pipe_fd, &packet, sizeof(packet), true)) != sizeof(packet)) {
- log_error("Invalid read from pipe: %s", l < 0 ? strerror(-l) : "short read");
- goto fail;
- }
-
- switch (packet.hdr.type) {
-
- case autofs_ptype_missing_direct:
-
- if (packet.v5_packet.pid > 0) {
- char *p = NULL;
-
- get_process_comm(packet.v5_packet.pid, &p);
- log_debug("Got direct mount request on %s, triggered by %lu (%s)",
- a->where, (unsigned long) packet.v5_packet.pid, strna(p));
- free(p);
-
- } else
- log_debug("Got direct mount request on %s", a->where);
-
- if (!a->tokens)
- if (!(a->tokens = set_new(trivial_hash_func, trivial_compare_func))) {
- log_error("Failed to allocate token set.");
- goto fail;
- }
-
- if ((r = set_put(a->tokens, UINT_TO_PTR(packet.v5_packet.wait_queue_token))) < 0) {
- log_error("Failed to remember token: %s", strerror(-r));
- goto fail;
- }
-
- automount_enter_runnning(a);
- break;
-
- default:
- log_error("Received unknown automount request %i", packet.hdr.type);
- break;
- }
-
- return;
-
-fail:
- automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
-}
-
-static void automount_shutdown(Manager *m) {
- assert(m);
-
- if (m->dev_autofs_fd >= 0)
- close_nointr_nofail(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 const char* const automount_state_table[_AUTOMOUNT_STATE_MAX] = {
- [AUTOMOUNT_DEAD] = "dead",
- [AUTOMOUNT_WAITING] = "waiting",
- [AUTOMOUNT_RUNNING] = "running",
- [AUTOMOUNT_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(automount_state, AutomountState);
-
-static const char* const automount_result_table[_AUTOMOUNT_RESULT_MAX] = {
- [AUTOMOUNT_SUCCESS] = "success",
- [AUTOMOUNT_FAILURE_RESOURCES] = "resources"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(automount_result, AutomountResult);
-
-const UnitVTable automount_vtable = {
- .object_size = sizeof(Automount),
- .sections =
- "Unit\0"
- "Automount\0"
- "Install\0",
-
- .no_alias = true,
- .no_instances = true,
-
- .init = automount_init,
- .load = automount_load,
- .done = automount_done,
-
- .coldplug = automount_coldplug,
-
- .dump = automount_dump,
-
- .start = automount_start,
- .stop = automount_stop,
-
- .serialize = automount_serialize,
- .deserialize_item = automount_deserialize_item,
-
- .active_state = automount_active_state,
- .sub_state_to_string = automount_sub_state_to_string,
-
- .check_gc = automount_check_gc,
-
- .fd_event = automount_fd_event,
-
- .reset_failed = automount_reset_failed,
-
- .bus_interface = "org.freedesktop.systemd1.Automount",
- .bus_message_handler = bus_automount_message_handler,
- .bus_invalidating_properties = bus_automount_invalidating_properties,
-
- .shutdown = automount_shutdown,
-
- .status_message_formats = {
- .finished_start_job = {
- [JOB_DONE] = "Set up automount %s.",
- [JOB_FAILED] = "Failed to set up automount %s.",
- [JOB_DEPENDENCY] = "Dependency failed for %s.",
- },
- .finished_stop_job = {
- [JOB_DONE] = "Unset automount %s.",
- [JOB_FAILED] = "Failed to unset automount %s.",
- },
- },
-};
diff --git a/src/core/automount.h b/src/core/automount.h
deleted file mode 100644
index 3d5736d1cb..0000000000
--- a/src/core/automount.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct Automount Automount;
-
-#include "unit.h"
-
-typedef enum AutomountState {
- AUTOMOUNT_DEAD,
- AUTOMOUNT_WAITING,
- AUTOMOUNT_RUNNING,
- AUTOMOUNT_FAILED,
- _AUTOMOUNT_STATE_MAX,
- _AUTOMOUNT_STATE_INVALID = -1
-} AutomountState;
-
-typedef enum AutomountResult {
- AUTOMOUNT_SUCCESS,
- AUTOMOUNT_FAILURE_RESOURCES,
- _AUTOMOUNT_RESULT_MAX,
- _AUTOMOUNT_RESULT_INVALID = -1
-} AutomountResult;
-
-struct Automount {
- Unit meta;
-
- AutomountState state, deserialized_state;
-
- char *where;
-
- UnitRef mount;
-
- int pipe_fd;
- mode_t directory_mode;
- Watch pipe_watch;
- dev_t dev_id;
-
- Set *tokens;
-
- AutomountResult result;
-};
-
-extern const UnitVTable automount_vtable;
-
-int automount_send_ready(Automount *a, int status);
-
-int automount_add_one_mount_link(Automount *a, Mount *m);
-
-const char* automount_state_to_string(AutomountState i);
-AutomountState automount_state_from_string(const char *s);
-
-const char* automount_result_to_string(AutomountResult i);
-AutomountResult automount_result_from_string(const char *s);
diff --git a/src/core/build.h b/src/core/build.h
deleted file mode 100644
index 4513a0bad7..0000000000
--- a/src/core/build.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 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/>.
-***/
-
-#ifdef HAVE_PAM
-#define _PAM_FEATURE_ "+PAM"
-#else
-#define _PAM_FEATURE_ "-PAM"
-#endif
-
-#ifdef HAVE_LIBWRAP
-#define _LIBWRAP_FEATURE_ "+LIBWRAP"
-#else
-#define _LIBWRAP_FEATURE_ "-LIBWRAP"
-#endif
-
-#ifdef HAVE_AUDIT
-#define _AUDIT_FEATURE_ "+AUDIT"
-#else
-#define _AUDIT_FEATURE_ "-AUDIT"
-#endif
-
-#ifdef HAVE_SELINUX
-#define _SELINUX_FEATURE_ "+SELINUX"
-#else
-#define _SELINUX_FEATURE_ "-SELINUX"
-#endif
-
-#ifdef HAVE_IMA
-#define _IMA_FEATURE_ "+IMA"
-#else
-#define _IMA_FEATURE_ "-IMA"
-#endif
-
-#ifdef HAVE_SYSV_COMPAT
-#define _SYSVINIT_FEATURE_ "+SYSVINIT"
-#else
-#define _SYSVINIT_FEATURE_ "-SYSVINIT"
-#endif
-
-#ifdef HAVE_LIBCRYPTSETUP
-#define _LIBCRYPTSETUP_FEATURE_ "+LIBCRYPTSETUP"
-#else
-#define _LIBCRYPTSETUP_FEATURE_ "-LIBCRYPTSETUP"
-#endif
-
-#ifdef HAVE_GCRYPT
-#define _GCRYPT_FEATURE_ "+GCRYPT"
-#else
-#define _GCRYPT_FEATURE_ "-GCRYPT"
-#endif
-
-#ifdef HAVE_ACL
-#define _ACL_FEATURE_ "+ACL"
-#else
-#define _ACL_FEATURE_ "-ACL"
-#endif
-
-#ifdef HAVE_XZ
-#define _XZ_FEATURE_ "+XZ"
-#else
-#define _XZ_FEATURE_ "-XZ"
-#endif
-
-#define SYSTEMD_FEATURES _PAM_FEATURE_ " " _LIBWRAP_FEATURE_ " " _AUDIT_FEATURE_ " " _SELINUX_FEATURE_ " " _IMA_FEATURE_ " " _SYSVINIT_FEATURE_ " " _LIBCRYPTSETUP_FEATURE_ " " _GCRYPT_FEATURE_ " " _ACL_FEATURE_ " " _XZ_FEATURE_
diff --git a/src/core/bus-errors.h b/src/core/bus-errors.h
deleted file mode 100644
index 04c1b2849d..0000000000
--- a/src/core/bus-errors.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <string.h>
-#include <dbus/dbus.h>
-
-#define BUS_ERROR_NO_SUCH_UNIT "org.freedesktop.systemd1.NoSuchUnit"
-#define BUS_ERROR_NO_SUCH_JOB "org.freedesktop.systemd1.NoSuchJob"
-#define BUS_ERROR_NOT_SUBSCRIBED "org.freedesktop.systemd1.NotSubscribed"
-#define BUS_ERROR_INVALID_PATH "org.freedesktop.systemd1.InvalidPath"
-#define BUS_ERROR_INVALID_NAME "org.freedesktop.systemd1.InvalidName"
-#define BUS_ERROR_UNIT_TYPE_MISMATCH "org.freedesktop.systemd1.UnitTypeMismatch"
-#define BUS_ERROR_UNIT_EXISTS "org.freedesktop.systemd1.UnitExists"
-#define BUS_ERROR_NOT_SUPPORTED "org.freedesktop.systemd1.NotSupported"
-#define BUS_ERROR_INVALID_JOB_MODE "org.freedesktop.systemd1.InvalidJobMode"
-#define BUS_ERROR_ONLY_BY_DEPENDENCY "org.freedesktop.systemd1.OnlyByDependency"
-#define BUS_ERROR_NO_ISOLATION "org.freedesktop.systemd1.NoIsolation"
-#define BUS_ERROR_LOAD_FAILED "org.freedesktop.systemd1.LoadFailed"
-#define BUS_ERROR_MASKED "org.freedesktop.systemd1.Masked"
-#define BUS_ERROR_JOB_TYPE_NOT_APPLICABLE "org.freedesktop.systemd1.JobTypeNotApplicable"
-#define BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE "org.freedesktop.systemd1.TransactionIsDestructive"
-#define BUS_ERROR_TRANSACTION_JOBS_CONFLICTING "org.freedesktop.systemd1.TransactionJobsConflicting"
-#define BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC "org.freedesktop.systemd1.TransactionOrderIsCyclic"
-#define BUS_ERROR_SHUTTING_DOWN "org.freedesktop.systemd1.ShuttingDown"
-#define BUS_ERROR_NO_SUCH_PROCESS "org.freedesktop.systemd1.NoSuchProcess"
-
-static inline const char *bus_error(const DBusError *e, int r) {
- if (e && e->message)
- return e->message;
-
- if (r >= 0)
- return strerror(r);
-
- return strerror(-r);
-}
diff --git a/src/core/cgroup-attr.c b/src/core/cgroup-attr.c
deleted file mode 100644
index 71af09cf87..0000000000
--- a/src/core/cgroup-attr.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2011 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "cgroup-attr.h"
-#include "cgroup-util.h"
-#include "list.h"
-
-int cgroup_attribute_apply(CGroupAttribute *a, CGroupBonding *b) {
- int r;
- char *path = NULL;
- char *v = NULL;
-
- assert(a);
-
- b = cgroup_bonding_find_list(b, a->controller);
- if (!b)
- return 0;
-
- if (a->map_callback) {
- r = a->map_callback(a->controller, a->name, a->value, &v);
- if (r < 0)
- return r;
- }
-
- r = cg_get_path(a->controller, b->path, a->name, &path);
- if (r < 0) {
- free(v);
- return r;
- }
-
- r = write_one_line_file(path, v ? v : a->value);
- if (r < 0)
- log_warning("Failed to write '%s' to %s: %s", v ? v : a->value, path, strerror(-r));
-
- free(path);
- free(v);
-
- return r;
-}
-
-int cgroup_attribute_apply_list(CGroupAttribute *first, CGroupBonding *b) {
- CGroupAttribute *a;
- int r = 0;
-
- LIST_FOREACH(by_unit, a, first) {
- int k;
-
- k = cgroup_attribute_apply(a, b);
- if (r == 0)
- r = k;
- }
-
- return r;
-}
-
-CGroupAttribute *cgroup_attribute_find_list(CGroupAttribute *first, const char *controller, const char *name) {
- CGroupAttribute *a;
-
- assert(controller);
- assert(name);
-
- LIST_FOREACH(by_unit, a, first)
- if (streq(a->controller, controller) &&
- streq(a->name, name))
- return a;
-
- return NULL;
-}
-
-static void cgroup_attribute_free(CGroupAttribute *a) {
- assert(a);
-
- free(a->controller);
- free(a->name);
- free(a->value);
- free(a);
-}
-
-void cgroup_attribute_free_list(CGroupAttribute *first) {
- CGroupAttribute *a, *n;
-
- LIST_FOREACH_SAFE(by_unit, a, n, first)
- cgroup_attribute_free(a);
-}
diff --git a/src/core/cgroup-attr.h b/src/core/cgroup-attr.h
deleted file mode 100644
index 2b754eac40..0000000000
--- a/src/core/cgroup-attr.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2011 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- 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 CGroupAttribute CGroupAttribute;
-
-typedef int (*CGroupAttributeMapCallback)(const char *controller, const char*name, const char *value, char **ret);
-
-#include "unit.h"
-#include "cgroup.h"
-
-struct CGroupAttribute {
- char *controller;
- char *name;
- char *value;
-
- CGroupAttributeMapCallback map_callback;
-
- LIST_FIELDS(CGroupAttribute, by_unit);
-};
-
-int cgroup_attribute_apply(CGroupAttribute *a, CGroupBonding *b);
-int cgroup_attribute_apply_list(CGroupAttribute *first, CGroupBonding *b);
-
-CGroupAttribute *cgroup_attribute_find_list(CGroupAttribute *first, const char *controller, const char *name);
-
-void cgroup_attribute_free_list(CGroupAttribute *first);
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
deleted file mode 100644
index 8fc1731485..0000000000
--- a/src/core/cgroup.c
+++ /dev/null
@@ -1,598 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <assert.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <signal.h>
-#include <sys/mount.h>
-#include <fcntl.h>
-
-#include "cgroup.h"
-#include "cgroup-util.h"
-#include "log.h"
-#include "strv.h"
-#include "path-util.h"
-
-int cgroup_bonding_realize(CGroupBonding *b) {
- int r;
-
- assert(b);
- assert(b->path);
- assert(b->controller);
-
- r = cg_create(b->controller, b->path);
- if (r < 0) {
- log_warning("Failed to create cgroup %s:%s: %s", b->controller, b->path, strerror(-r));
- return r;
- }
-
- b->realized = true;
-
- return 0;
-}
-
-int cgroup_bonding_realize_list(CGroupBonding *first) {
- CGroupBonding *b;
- int r;
-
- LIST_FOREACH(by_unit, b, first)
- if ((r = cgroup_bonding_realize(b)) < 0 && b->essential)
- return r;
-
- return 0;
-}
-
-void cgroup_bonding_free(CGroupBonding *b, bool trim) {
- assert(b);
-
- if (b->unit) {
- CGroupBonding *f;
-
- LIST_REMOVE(CGroupBonding, by_unit, b->unit->cgroup_bondings, b);
-
- if (streq(b->controller, SYSTEMD_CGROUP_CONTROLLER)) {
- assert_se(f = hashmap_get(b->unit->manager->cgroup_bondings, b->path));
- LIST_REMOVE(CGroupBonding, by_path, f, b);
-
- if (f)
- hashmap_replace(b->unit->manager->cgroup_bondings, b->path, f);
- else
- hashmap_remove(b->unit->manager->cgroup_bondings, b->path);
- }
- }
-
- if (b->realized && b->ours && trim)
- cg_trim(b->controller, b->path, false);
-
- free(b->controller);
- free(b->path);
- free(b);
-}
-
-void cgroup_bonding_free_list(CGroupBonding *first, bool remove_or_trim) {
- CGroupBonding *b, *n;
-
- LIST_FOREACH_SAFE(by_unit, b, n, first)
- cgroup_bonding_free(b, remove_or_trim);
-}
-
-void cgroup_bonding_trim(CGroupBonding *b, bool delete_root) {
- assert(b);
-
- if (b->realized && b->ours)
- cg_trim(b->controller, b->path, delete_root);
-}
-
-void cgroup_bonding_trim_list(CGroupBonding *first, bool delete_root) {
- CGroupBonding *b;
-
- LIST_FOREACH(by_unit, b, first)
- cgroup_bonding_trim(b, delete_root);
-}
-
-
-int cgroup_bonding_install(CGroupBonding *b, pid_t pid, const char *cgroup_suffix) {
- char *p = NULL;
- const char *path;
- int r;
-
- assert(b);
- assert(pid >= 0);
-
- if (cgroup_suffix) {
- p = strjoin(b->path, "/", cgroup_suffix, NULL);
- if (!p)
- return -ENOMEM;
-
- path = p;
- } else
- path = b->path;
-
- r = cg_create_and_attach(b->controller, path, pid);
- free(p);
-
- if (r < 0)
- return r;
-
- b->realized = true;
- return 0;
-}
-
-int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid, const char *cgroup_suffix) {
- CGroupBonding *b;
- int r;
-
- LIST_FOREACH(by_unit, b, first) {
- r = cgroup_bonding_install(b, pid, cgroup_suffix);
- if (r < 0 && b->essential)
- return r;
- }
-
- return 0;
-}
-
-int cgroup_bonding_set_group_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid) {
- assert(b);
-
- if (!b->realized)
- return -EINVAL;
-
- return cg_set_group_access(b->controller, b->path, mode, uid, gid);
-}
-
-int cgroup_bonding_set_group_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid) {
- CGroupBonding *b;
- int r;
-
- LIST_FOREACH(by_unit, b, first) {
- r = cgroup_bonding_set_group_access(b, mode, uid, gid);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-int cgroup_bonding_set_task_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid, int sticky) {
- assert(b);
-
- if (!b->realized)
- return -EINVAL;
-
- return cg_set_task_access(b->controller, b->path, mode, uid, gid, sticky);
-}
-
-int cgroup_bonding_set_task_access_list(CGroupBonding *first, mode_t mode, uid_t uid, gid_t gid, int sticky) {
- CGroupBonding *b;
- int r;
-
- LIST_FOREACH(by_unit, b, first) {
- r = cgroup_bonding_set_task_access(b, mode, uid, gid, sticky);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-int cgroup_bonding_kill(CGroupBonding *b, int sig, bool sigcont, bool rem, Set *s, const char *cgroup_suffix) {
- char *p = NULL;
- const char *path;
- int r;
-
- assert(b);
- assert(sig >= 0);
-
- /* Don't kill cgroups that aren't ours */
- if (!b->ours)
- return 0;
-
- if (cgroup_suffix) {
- p = strjoin(b->path, "/", cgroup_suffix, NULL);
- if (!p)
- return -ENOMEM;
-
- path = p;
- } else
- path = b->path;
-
- r = cg_kill_recursive(b->controller, path, sig, sigcont, true, rem, s);
- free(p);
-
- return r;
-}
-
-int cgroup_bonding_kill_list(CGroupBonding *first, int sig, bool sigcont, bool rem, Set *s, const char *cgroup_suffix) {
- CGroupBonding *b;
- Set *allocated_set = NULL;
- int ret = -EAGAIN, r;
-
- if (!first)
- return 0;
-
- if (!s)
- if (!(s = allocated_set = set_new(trivial_hash_func, trivial_compare_func)))
- return -ENOMEM;
-
- LIST_FOREACH(by_unit, b, first) {
- r = cgroup_bonding_kill(b, sig, sigcont, rem, s, cgroup_suffix);
- if (r < 0) {
- if (r == -EAGAIN || r == -ESRCH)
- continue;
-
- ret = r;
- goto finish;
- }
-
- if (ret < 0 || r > 0)
- ret = r;
- }
-
-finish:
- if (allocated_set)
- set_free(allocated_set);
-
- return ret;
-}
-
-/* Returns 1 if the group is empty, 0 if it is not, -EAGAIN if we
- * cannot know */
-int cgroup_bonding_is_empty(CGroupBonding *b) {
- int r;
-
- assert(b);
-
- if ((r = cg_is_empty_recursive(b->controller, b->path, true)) < 0)
- return r;
-
- /* If it is empty it is empty */
- if (r > 0)
- return 1;
-
- /* It's not only us using this cgroup, so we just don't know */
- return b->ours ? 0 : -EAGAIN;
-}
-
-int cgroup_bonding_is_empty_list(CGroupBonding *first) {
- CGroupBonding *b;
-
- LIST_FOREACH(by_unit, b, first) {
- int r;
-
- if ((r = cgroup_bonding_is_empty(b)) < 0) {
- /* If this returned -EAGAIN, then we don't know if the
- * group is empty, so let's see if another group can
- * tell us */
-
- if (r != -EAGAIN)
- return r;
- } else
- return r;
- }
-
- return -EAGAIN;
-}
-
-int manager_setup_cgroup(Manager *m) {
- char *current = NULL, *path = NULL;
- int r;
- char suffix[32];
-
- assert(m);
-
- /* 0. Be nice to Ingo Molnar #628004 */
- if (path_is_mount_point("/sys/fs/cgroup/systemd", false) <= 0) {
- log_warning("No control group support available, not creating root group.");
- return 0;
- }
-
- /* 1. Determine hierarchy */
- r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, &current);
- if (r < 0) {
- log_error("Cannot determine cgroup we are running in: %s", strerror(-r));
- goto finish;
- }
-
- if (m->running_as == SYSTEMD_SYSTEM)
- strcpy(suffix, "/system");
- else {
- snprintf(suffix, sizeof(suffix), "/systemd-%lu", (unsigned long) getpid());
- char_array_0(suffix);
- }
-
- free(m->cgroup_hierarchy);
- if (endswith(current, suffix)) {
- /* We probably got reexecuted and can continue to use our root cgroup */
- m->cgroup_hierarchy = current;
- current = NULL;
-
- } else {
- /* We need a new root cgroup */
- m->cgroup_hierarchy = NULL;
- if (asprintf(&m->cgroup_hierarchy, "%s%s", streq(current, "/") ? "" : current, suffix) < 0) {
- r = log_oom();
- goto finish;
- }
- }
-
- /* 2. Show data */
- r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, NULL, &path);
- if (r < 0) {
- log_error("Cannot find cgroup mount point: %s", strerror(-r));
- goto finish;
- }
-
- log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
-
- /* 3. Install agent */
- r = cg_install_release_agent(SYSTEMD_CGROUP_CONTROLLER, SYSTEMD_CGROUP_AGENT_PATH);
- if (r < 0)
- log_warning("Failed to install release agent, ignoring: %s", strerror(-r));
- else if (r > 0)
- log_debug("Installed release agent.");
- else
- log_debug("Release agent already installed.");
-
- /* 4. Realize the group */
- r = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, 0);
- if (r < 0) {
- log_error("Failed to create root cgroup hierarchy: %s", strerror(-r));
- goto finish;
- }
-
- /* 5. And pin it, so that it cannot be unmounted */
- if (m->pin_cgroupfs_fd >= 0)
- close_nointr_nofail(m->pin_cgroupfs_fd);
-
- m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK);
- if (r < 0) {
- log_error("Failed to open pin file: %m");
- r = -errno;
- goto finish;
- }
-
- log_debug("Created root group.");
-
- cg_shorten_controllers(m->default_controllers);
-
-finish:
- free(current);
- free(path);
-
- return r;
-}
-
-void manager_shutdown_cgroup(Manager *m, bool delete) {
- assert(m);
-
- if (delete && m->cgroup_hierarchy)
- cg_delete(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy);
-
- if (m->pin_cgroupfs_fd >= 0) {
- close_nointr_nofail(m->pin_cgroupfs_fd);
- m->pin_cgroupfs_fd = -1;
- }
-
- free(m->cgroup_hierarchy);
- m->cgroup_hierarchy = NULL;
-}
-
-int cgroup_bonding_get(Manager *m, const char *cgroup, CGroupBonding **bonding) {
- CGroupBonding *b;
- char *p;
-
- assert(m);
- assert(cgroup);
- assert(bonding);
-
- b = hashmap_get(m->cgroup_bondings, cgroup);
- if (b) {
- *bonding = b;
- return 1;
- }
-
- p = strdup(cgroup);
- if (!p)
- return -ENOMEM;
-
- for (;;) {
- char *e;
-
- e = strrchr(p, '/');
- if (!e || e == p) {
- free(p);
- *bonding = NULL;
- return 0;
- }
-
- *e = 0;
-
- b = hashmap_get(m->cgroup_bondings, p);
- if (b) {
- free(p);
- *bonding = b;
- return 1;
- }
- }
-}
-
-int cgroup_notify_empty(Manager *m, const char *group) {
- CGroupBonding *l, *b;
- int r;
-
- assert(m);
- assert(group);
-
- r = cgroup_bonding_get(m, group, &l);
- if (r <= 0)
- return r;
-
- LIST_FOREACH(by_path, b, l) {
- int t;
-
- if (!b->unit)
- continue;
-
- t = cgroup_bonding_is_empty_list(b);
- if (t < 0) {
-
- /* If we don't know, we don't know */
- if (t != -EAGAIN)
- log_warning("Failed to check whether cgroup is empty: %s", strerror(errno));
-
- continue;
- }
-
- if (t > 0) {
- /* If it is empty, let's delete it */
- cgroup_bonding_trim_list(b->unit->cgroup_bondings, true);
-
- if (UNIT_VTABLE(b->unit)->cgroup_notify_empty)
- UNIT_VTABLE(b->unit)->cgroup_notify_empty(b->unit);
- }
- }
-
- return 0;
-}
-
-Unit* cgroup_unit_by_pid(Manager *m, pid_t pid) {
- CGroupBonding *l, *b;
- char *group = NULL;
-
- assert(m);
-
- if (pid <= 1)
- return NULL;
-
- if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, pid, &group) < 0)
- return NULL;
-
- l = hashmap_get(m->cgroup_bondings, group);
-
- if (!l) {
- char *slash;
-
- while ((slash = strrchr(group, '/'))) {
- if (slash == group)
- break;
-
- *slash = 0;
-
- if ((l = hashmap_get(m->cgroup_bondings, group)))
- break;
- }
- }
-
- free(group);
-
- LIST_FOREACH(by_path, b, l) {
-
- if (!b->unit)
- continue;
-
- if (b->ours)
- return b->unit;
- }
-
- return NULL;
-}
-
-CGroupBonding *cgroup_bonding_find_list(CGroupBonding *first, const char *controller) {
- CGroupBonding *b;
-
- assert(controller);
-
- LIST_FOREACH(by_unit, b, first)
- if (streq(b->controller, controller))
- return b;
-
- return NULL;
-}
-
-char *cgroup_bonding_to_string(CGroupBonding *b) {
- char *r;
-
- assert(b);
-
- if (asprintf(&r, "%s:%s", b->controller, b->path) < 0)
- return NULL;
-
- return r;
-}
-
-pid_t cgroup_bonding_search_main_pid(CGroupBonding *b) {
- FILE *f;
- pid_t pid = 0, npid, mypid;
-
- assert(b);
-
- if (!b->ours)
- return 0;
-
- if (cg_enumerate_processes(b->controller, b->path, &f) < 0)
- return 0;
-
- mypid = getpid();
-
- while (cg_read_pid(f, &npid) > 0) {
- pid_t ppid;
-
- if (npid == pid)
- continue;
-
- /* Ignore processes that aren't our kids */
- if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid)
- continue;
-
- if (pid != 0) {
- /* Dang, there's more than one daemonized PID
- in this group, so we don't know what process
- is the main process. */
- pid = 0;
- break;
- }
-
- pid = npid;
- }
-
- fclose(f);
-
- return pid;
-}
-
-pid_t cgroup_bonding_search_main_pid_list(CGroupBonding *first) {
- CGroupBonding *b;
- pid_t pid;
-
- /* Try to find a main pid from this cgroup, but checking if
- * there's only one PID in the cgroup and returning it. Later
- * on we might want to add additional, smarter heuristics
- * here. */
-
- LIST_FOREACH(by_unit, b, first)
- if ((pid = cgroup_bonding_search_main_pid(b)) != 0)
- return pid;
-
- return 0;
-
-}
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
deleted file mode 100644
index 229da52ba4..0000000000
--- a/src/core/cgroup.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct CGroupBonding CGroupBonding;
-
-#include "unit.h"
-
-/* Binds a cgroup to a name */
-struct CGroupBonding {
- char *controller;
- char *path;
-
- Unit *unit;
-
- /* For the Unit::cgroup_bondings list */
- LIST_FIELDS(CGroupBonding, by_unit);
-
- /* For the Manager::cgroup_bondings hashmap */
- LIST_FIELDS(CGroupBonding, by_path);
-
- /* When shutting down, remove cgroup? Are our own tasks the
- * only ones in this group?*/
- bool ours:1;
-
- /* If we cannot create this group, or add a process to it, is this fatal? */
- bool essential:1;
-
- /* This cgroup is realized */
- bool realized:1;
-};
-
-int cgroup_bonding_realize(CGroupBonding *b);
-int cgroup_bonding_realize_list(CGroupBonding *first);
-
-void cgroup_bonding_free(CGroupBonding *b, bool trim);
-void cgroup_bonding_free_list(CGroupBonding *first, bool trim);
-
-int cgroup_bonding_install(CGroupBonding *b, pid_t pid, const char *suffix);
-int cgroup_bonding_install_list(CGroupBonding *first, pid_t pid, const char *suffix);
-
-int cgroup_bonding_set_group_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid);
-int cgroup_bonding_set_group_access_list(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid);
-
-int cgroup_bonding_set_task_access(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid, int sticky);
-int cgroup_bonding_set_task_access_list(CGroupBonding *b, mode_t mode, uid_t uid, gid_t gid, int sticky);
-
-int cgroup_bonding_kill(CGroupBonding *b, int sig, bool sigcont, bool rem, Set *s, const char *suffix);
-int cgroup_bonding_kill_list(CGroupBonding *first, int sig, bool sigcont, bool rem, Set *s, const char *suffix);
-
-void cgroup_bonding_trim(CGroupBonding *first, bool delete_root);
-void cgroup_bonding_trim_list(CGroupBonding *first, bool delete_root);
-
-int cgroup_bonding_is_empty(CGroupBonding *b);
-int cgroup_bonding_is_empty_list(CGroupBonding *first);
-
-CGroupBonding *cgroup_bonding_find_list(CGroupBonding *first, const char *controller);
-
-char *cgroup_bonding_to_string(CGroupBonding *b);
-
-pid_t cgroup_bonding_search_main_pid(CGroupBonding *b);
-pid_t cgroup_bonding_search_main_pid_list(CGroupBonding *b);
-
-#include "manager.h"
-
-int manager_setup_cgroup(Manager *m);
-void manager_shutdown_cgroup(Manager *m, bool delete);
-
-int cgroup_bonding_get(Manager *m, const char *cgroup, CGroupBonding **bonding);
-int cgroup_notify_empty(Manager *m, const char *group);
-
-Unit* cgroup_unit_by_pid(Manager *m, pid_t pid);
diff --git a/src/core/condition.c b/src/core/condition.c
deleted file mode 100644
index 32a37ccad6..0000000000
--- a/src/core/condition.c
+++ /dev/null
@@ -1,370 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdlib.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/capability.h>
-#include <sys/statvfs.h>
-#include <fnmatch.h>
-
-#ifdef HAVE_SELINUX
-#include <selinux/selinux.h>
-#endif
-
-#include <systemd/sd-id128.h>
-#include "util.h"
-#include "condition.h"
-#include "virt.h"
-#include "path-util.h"
-
-Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) {
- Condition *c;
-
- assert(type < _CONDITION_TYPE_MAX);
-
- c = new0(Condition, 1);
- if (!c)
- return NULL;
-
- c->type = type;
- c->trigger = trigger;
- c->negate = negate;
-
- if (parameter) {
- c->parameter = strdup(parameter);
- if (!c->parameter) {
- free(c);
- return NULL;
- }
- }
-
- return c;
-}
-
-void condition_free(Condition *c) {
- assert(c);
-
- free(c->parameter);
- free(c);
-}
-
-void condition_free_list(Condition *first) {
- Condition *c, *n;
-
- LIST_FOREACH_SAFE(conditions, c, n, first)
- condition_free(c);
-}
-
-static bool test_kernel_command_line(const char *parameter) {
- char *line, *w, *state, *word = NULL;
- bool equal;
- int r;
- size_t l, pl;
- bool found = false;
-
- assert(parameter);
-
- if (detect_container(NULL) > 0)
- return false;
-
- r = read_one_line_file("/proc/cmdline", &line);
- if (r < 0) {
- log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
- return false;
- }
-
- equal = !!strchr(parameter, '=');
- pl = strlen(parameter);
-
- FOREACH_WORD_QUOTED(w, l, line, state) {
-
- free(word);
- word = strndup(w, l);
- if (!word)
- break;
-
- if (equal) {
- if (streq(word, parameter)) {
- found = true;
- break;
- }
- } else {
- if (startswith(word, parameter) && (word[pl] == '=' || word[pl] == 0)) {
- found = true;
- break;
- }
- }
-
- }
-
- free(word);
- free(line);
-
- return found;
-}
-
-static bool test_virtualization(const char *parameter) {
- int b;
- Virtualization v;
- const char *id;
-
- assert(parameter);
-
- v = detect_virtualization(&id);
- if (v < 0) {
- log_warning("Failed to detect virtualization, ignoring: %s", strerror(-v));
- return false;
- }
-
- /* First, compare with yes/no */
- b = parse_boolean(parameter);
-
- if (v > 0 && b > 0)
- return true;
-
- if (v == 0 && b == 0)
- return true;
-
- /* Then, compare categorization */
- if (v == VIRTUALIZATION_VM && streq(parameter, "vm"))
- return true;
-
- if (v == VIRTUALIZATION_CONTAINER && streq(parameter, "container"))
- return true;
-
- /* Finally compare id */
- return v > 0 && streq(parameter, id);
-}
-
-static bool test_security(const char *parameter) {
-#ifdef HAVE_SELINUX
- if (streq(parameter, "selinux"))
- return is_selinux_enabled() > 0;
-#endif
- return false;
-}
-
-static bool test_capability(const char *parameter) {
- cap_value_t value;
- FILE *f;
- char line[LINE_MAX];
- unsigned long long capabilities = (unsigned long long) -1;
-
- /* If it's an invalid capability, we don't have it */
-
- if (cap_from_name(parameter, &value) < 0)
- return false;
-
- /* If it's a valid capability we default to assume
- * that we have it */
-
- f = fopen("/proc/self/status", "re");
- if (!f)
- return true;
-
- while (fgets(line, sizeof(line), f)) {
- truncate_nl(line);
-
- if (startswith(line, "CapBnd:")) {
- (void) sscanf(line+7, "%llx", &capabilities);
- break;
- }
- }
-
- fclose(f);
-
- return !!(capabilities & (1ULL << value));
-}
-
-static bool test_host(const char *parameter) {
- sd_id128_t x, y;
- char *h;
- int r;
- bool b;
-
- if (sd_id128_from_string(parameter, &x) >= 0) {
-
- r = sd_id128_get_machine(&y);
- if (r < 0)
- return false;
-
- return sd_id128_equal(x, y);
- }
-
- h = gethostname_malloc();
- if (!h)
- return false;
-
- b = fnmatch(parameter, h, FNM_CASEFOLD) == 0;
- free(h);
-
- return b;
-}
-
-bool condition_test(Condition *c) {
- assert(c);
-
- switch(c->type) {
-
- case CONDITION_PATH_EXISTS:
- return (access(c->parameter, F_OK) >= 0) == !c->negate;
-
- case CONDITION_PATH_EXISTS_GLOB:
- return (glob_exists(c->parameter) > 0) == !c->negate;
-
- case CONDITION_PATH_IS_DIRECTORY: {
- struct stat st;
-
- if (stat(c->parameter, &st) < 0)
- return c->negate;
- return S_ISDIR(st.st_mode) == !c->negate;
- }
-
- case CONDITION_PATH_IS_SYMBOLIC_LINK: {
- struct stat st;
-
- if (lstat(c->parameter, &st) < 0)
- return c->negate;
- return S_ISLNK(st.st_mode) == !c->negate;
- }
-
- case CONDITION_PATH_IS_MOUNT_POINT:
- return (path_is_mount_point(c->parameter, true) > 0) == !c->negate;
-
- case CONDITION_PATH_IS_READ_WRITE:
- return (path_is_read_only_fs(c->parameter) > 0) == c->negate;
-
- case CONDITION_DIRECTORY_NOT_EMPTY: {
- int k;
-
- k = dir_is_empty(c->parameter);
- return !(k == -ENOENT || k > 0) == !c->negate;
- }
-
- case CONDITION_FILE_NOT_EMPTY: {
- struct stat st;
-
- if (stat(c->parameter, &st) < 0)
- return c->negate;
-
- return (S_ISREG(st.st_mode) && st.st_size > 0) == !c->negate;
- }
-
- case CONDITION_FILE_IS_EXECUTABLE: {
- struct stat st;
-
- if (stat(c->parameter, &st) < 0)
- return c->negate;
-
- return (S_ISREG(st.st_mode) && (st.st_mode & 0111)) == !c->negate;
- }
-
- case CONDITION_KERNEL_COMMAND_LINE:
- return test_kernel_command_line(c->parameter) == !c->negate;
-
- case CONDITION_VIRTUALIZATION:
- return test_virtualization(c->parameter) == !c->negate;
-
- case CONDITION_SECURITY:
- return test_security(c->parameter) == !c->negate;
-
- case CONDITION_CAPABILITY:
- return test_capability(c->parameter) == !c->negate;
-
- case CONDITION_HOST:
- return test_host(c->parameter) == !c->negate;
-
- case CONDITION_NULL:
- return !c->negate;
-
- default:
- assert_not_reached("Invalid condition type.");
- }
-}
-
-bool condition_test_list(Condition *first) {
- Condition *c;
- int triggered = -1;
-
- /* 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) {
- bool b;
-
- b = condition_test(c);
-
- if (!c->trigger && !b)
- return false;
-
- if (c->trigger && triggered <= 0)
- triggered = b;
- }
-
- return triggered != 0;
-}
-
-void condition_dump(Condition *c, FILE *f, const char *prefix) {
- assert(c);
- assert(f);
-
- if (!prefix)
- prefix = "";
-
- fprintf(f,
- "%s\t%s: %s%s%s\n",
- prefix,
- condition_type_to_string(c->type),
- c->trigger ? "|" : "",
- c->negate ? "!" : "",
- c->parameter);
-}
-
-void condition_dump_list(Condition *first, FILE *f, const char *prefix) {
- Condition *c;
-
- LIST_FOREACH(conditions, c, first)
- condition_dump(c, f, prefix);
-}
-
-static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
- [CONDITION_PATH_EXISTS] = "ConditionPathExists",
- [CONDITION_PATH_EXISTS_GLOB] = "ConditionPathExistsGlob",
- [CONDITION_PATH_IS_DIRECTORY] = "ConditionPathIsDirectory",
- [CONDITION_PATH_IS_SYMBOLIC_LINK] = "ConditionPathIsSymbolicLink",
- [CONDITION_PATH_IS_MOUNT_POINT] = "ConditionPathIsMountPoint",
- [CONDITION_PATH_IS_READ_WRITE] = "ConditionPathIsReadWrite",
- [CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty",
- [CONDITION_FILE_NOT_EMPTY] = "ConditionFileNotEmpty",
- [CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine",
- [CONDITION_VIRTUALIZATION] = "ConditionVirtualization",
- [CONDITION_SECURITY] = "ConditionSecurity",
- [CONDITION_HOST] = "ConditionHost",
- [CONDITION_NULL] = "ConditionNull"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(condition_type, ConditionType);
diff --git a/src/core/condition.h b/src/core/condition.h
deleted file mode 100644
index 03954e40b3..0000000000
--- a/src/core/condition.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-
-#include "list.h"
-
-typedef enum ConditionType {
- CONDITION_PATH_EXISTS,
- CONDITION_PATH_EXISTS_GLOB,
- CONDITION_PATH_IS_DIRECTORY,
- CONDITION_PATH_IS_SYMBOLIC_LINK,
- CONDITION_PATH_IS_MOUNT_POINT,
- CONDITION_PATH_IS_READ_WRITE,
- CONDITION_DIRECTORY_NOT_EMPTY,
- CONDITION_FILE_NOT_EMPTY,
- CONDITION_FILE_IS_EXECUTABLE,
- CONDITION_KERNEL_COMMAND_LINE,
- CONDITION_VIRTUALIZATION,
- CONDITION_SECURITY,
- CONDITION_CAPABILITY,
- CONDITION_HOST,
- CONDITION_NULL,
- _CONDITION_TYPE_MAX,
- _CONDITION_TYPE_INVALID = -1
-} ConditionType;
-
-typedef struct Condition {
- ConditionType type;
- char *parameter;
-
- bool trigger:1;
- bool negate:1;
-
- LIST_FIELDS(struct Condition, conditions);
-} Condition;
-
-Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate);
-void condition_free(Condition *c);
-void condition_free_list(Condition *c);
-
-bool condition_test(Condition *c);
-bool condition_test_list(Condition *c);
-
-void condition_dump(Condition *c, FILE *f, const char *prefix);
-void condition_dump_list(Condition *c, FILE *f, const char *prefix);
-
-const char* condition_type_to_string(ConditionType t);
-int condition_type_from_string(const char *s);
diff --git a/src/core/dbus-automount.c b/src/core/dbus-automount.c
deleted file mode 100644
index 060cbf7707..0000000000
--- a/src/core/dbus-automount.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-
-#include "dbus-unit.h"
-#include "dbus-automount.h"
-#include "dbus-common.h"
-#include "selinux-access.h"
-
-#define BUS_AUTOMOUNT_INTERFACE \
- " <interface name=\"org.freedesktop.systemd1.Automount\">\n" \
- " <property name=\"Where\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"DirectoryMode\" type=\"u\" access=\"read\"/>\n" \
- " <property name=\"Result\" type=\"s\" access=\"read\"/>\n" \
- " </interface>\n"
-
-#define INTROSPECTION \
- DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
- "<node>\n" \
- BUS_UNIT_INTERFACE \
- BUS_AUTOMOUNT_INTERFACE \
- BUS_PROPERTIES_INTERFACE \
- BUS_PEER_INTERFACE \
- BUS_INTROSPECTABLE_INTERFACE \
- "</node>\n"
-
-#define INTERFACES_LIST \
- BUS_UNIT_INTERFACES_LIST \
- "org.freedesktop.systemd1.Automount\0"
-
-const char bus_automount_interface[] _introspect_("Automount") = BUS_AUTOMOUNT_INTERFACE;
-
-const char bus_automount_invalidating_properties[] =
- "Result\0";
-
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_automount_append_automount_result, automount_result, AutomountResult);
-
-static const BusProperty bus_automount_properties[] = {
- { "Where", bus_property_append_string, "s", offsetof(Automount, where), true },
- { "DirectoryMode", bus_property_append_mode, "u", offsetof(Automount, directory_mode) },
- { "Result", bus_automount_append_automount_result, "s", offsetof(Automount, result) },
- { NULL, }
-};
-
-DBusHandlerResult bus_automount_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
- Automount *am = AUTOMOUNT(u);
- const BusBoundProperties bps[] = {
- { "org.freedesktop.systemd1.Unit", bus_unit_properties, u },
- { "org.freedesktop.systemd1.Automount", bus_automount_properties, am },
- { NULL, }
- };
-
- SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status");
-
- return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
-}
diff --git a/src/core/dbus-automount.h b/src/core/dbus-automount.h
deleted file mode 100644
index b338e25fc1..0000000000
--- a/src/core/dbus-automount.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You 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/dbus.h>
-
-#include "unit.h"
-
-DBusHandlerResult bus_automount_message_handler(Unit *u, DBusConnection *c, DBusMessage *message);
-
-extern const char bus_automount_interface[];
-extern const char bus_automount_invalidating_properties[];
diff --git a/src/core/dbus-device.c b/src/core/dbus-device.c
deleted file mode 100644
index dbd91fe3db..0000000000
--- a/src/core/dbus-device.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "dbus-unit.h"
-#include "dbus-device.h"
-#include "dbus-common.h"
-#include "selinux-access.h"
-
-#define BUS_DEVICE_INTERFACE \
- " <interface name=\"org.freedesktop.systemd1.Device\">\n" \
- " <property name=\"SysFSPath\" type=\"s\" access=\"read\"/>\n" \
- " </interface>\n"
-
-#define INTROSPECTION \
- DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
- "<node>\n" \
- BUS_UNIT_INTERFACE \
- BUS_DEVICE_INTERFACE \
- BUS_PROPERTIES_INTERFACE \
- BUS_PEER_INTERFACE \
- BUS_INTROSPECTABLE_INTERFACE \
- "</node>\n"
-
-#define INTERFACES_LIST \
- BUS_UNIT_INTERFACES_LIST \
- "org.freedesktop.systemd1.Device\0"
-
-const char bus_device_interface[] _introspect_("Device") = BUS_DEVICE_INTERFACE;
-
-const char bus_device_invalidating_properties[] =
- "SysFSPath\0";
-
-static const BusProperty bus_device_properties[] = {
- { "SysFSPath", bus_property_append_string, "s", offsetof(Device, sysfs), true },
- { NULL, }
-};
-
-
-DBusHandlerResult bus_device_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
- Device *d = DEVICE(u);
- const BusBoundProperties bps[] = {
- { "org.freedesktop.systemd1.Unit", bus_unit_properties, u },
- { "org.freedesktop.systemd1.Device", bus_device_properties, d },
- { NULL, }
- };
-
- SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status");
-
- return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
-}
diff --git a/src/core/dbus-device.h b/src/core/dbus-device.h
deleted file mode 100644
index 311e0685d1..0000000000
--- a/src/core/dbus-device.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You 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/dbus.h>
-
-#include "unit.h"
-
-DBusHandlerResult bus_device_message_handler(Unit *u, DBusConnection *c, DBusMessage *message);
-
-extern const char bus_device_interface[];
-extern const char bus_device_invalidating_properties[];
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
deleted file mode 100644
index e815cb58e4..0000000000
--- a/src/core/dbus-execute.c
+++ /dev/null
@@ -1,439 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <dbus/dbus.h>
-#include <sys/prctl.h>
-
-#include "dbus-execute.h"
-#include "missing.h"
-#include "ioprio.h"
-#include "strv.h"
-#include "dbus-common.h"
-#include "syscall-list.h"
-
-DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_input, exec_input, ExecInput);
-DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_execute_append_output, exec_output, ExecOutput);
-
-int bus_execute_append_env_files(DBusMessageIter *i, const char *property, void *data) {
- char **env_files = data, **j;
- DBusMessageIter sub, sub2;
-
- assert(i);
- assert(property);
-
- if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sb)", &sub))
- return -ENOMEM;
-
- STRV_FOREACH(j, env_files) {
- dbus_bool_t b = false;
- char *fn = *j;
-
- if (fn[0] == '-') {
- b = true;
- fn++;
- }
-
- if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &fn) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_BOOLEAN, &b) ||
- !dbus_message_iter_close_container(&sub, &sub2))
- return -ENOMEM;
- }
-
- if (!dbus_message_iter_close_container(i, &sub))
- return -ENOMEM;
-
- return 0;
-}
-
-int bus_execute_append_oom_score_adjust(DBusMessageIter *i, const char *property, void *data) {
- ExecContext *c = data;
- int32_t n;
-
- assert(i);
- assert(property);
- assert(c);
-
- if (c->oom_score_adjust_set)
- n = c->oom_score_adjust;
- else {
- char *t;
-
- n = 0;
- if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0) {
- safe_atoi(t, &n);
- free(t);
- }
- }
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
- return -ENOMEM;
-
- return 0;
-}
-
-int bus_execute_append_nice(DBusMessageIter *i, const char *property, void *data) {
- ExecContext *c = data;
- int32_t n;
-
- assert(i);
- assert(property);
- assert(c);
-
- if (c->nice_set)
- n = c->nice;
- else
- n = getpriority(PRIO_PROCESS, 0);
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
- return -ENOMEM;
-
- return 0;
-}
-
-int bus_execute_append_ioprio(DBusMessageIter *i, const char *property, void *data) {
- ExecContext *c = data;
- int32_t n;
-
- assert(i);
- assert(property);
- assert(c);
-
- if (c->ioprio_set)
- n = c->ioprio;
- else
- n = ioprio_get(IOPRIO_WHO_PROCESS, 0);
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
- return -ENOMEM;
-
- return 0;
-}
-
-int bus_execute_append_cpu_sched_policy(DBusMessageIter *i, const char *property, void *data) {
- ExecContext *c = data;
- int32_t n;
-
- assert(i);
- assert(property);
- assert(c);
-
- if (c->cpu_sched_set)
- n = c->cpu_sched_policy;
- else
- n = sched_getscheduler(0);
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
- return -ENOMEM;
-
- return 0;
-}
-
-int bus_execute_append_cpu_sched_priority(DBusMessageIter *i, const char *property, void *data) {
- ExecContext *c = data;
- int32_t n;
-
- assert(i);
- assert(property);
- assert(c);
-
- if (c->cpu_sched_set)
- n = c->cpu_sched_priority;
- else {
- struct sched_param p;
- n = 0;
-
- zero(p);
- if (sched_getparam(0, &p) >= 0)
- n = p.sched_priority;
- }
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &n))
- return -ENOMEM;
-
- return 0;
-}
-
-int bus_execute_append_affinity(DBusMessageIter *i, const char *property, void *data) {
- ExecContext *c = data;
- dbus_bool_t b;
- DBusMessageIter sub;
-
- assert(i);
- assert(property);
- assert(c);
-
- if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "y", &sub))
- return -ENOMEM;
-
- if (c->cpuset)
- b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &c->cpuset, CPU_ALLOC_SIZE(c->cpuset_ncpus));
- else
- b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_BYTE, &c->cpuset, 0);
-
- if (!b)
- return -ENOMEM;
-
- if (!dbus_message_iter_close_container(i, &sub))
- return -ENOMEM;
-
- return 0;
-}
-
-int bus_execute_append_timer_slack_nsec(DBusMessageIter *i, const char *property, void *data) {
- ExecContext *c = data;
- uint64_t u;
-
- assert(i);
- assert(property);
- assert(c);
-
- if (c->timer_slack_nsec != (nsec_t) -1)
- u = (uint64_t) c->timer_slack_nsec;
- else
- u = (uint64_t) prctl(PR_GET_TIMERSLACK);
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
- return -ENOMEM;
-
- return 0;
-}
-
-int bus_execute_append_capability_bs(DBusMessageIter *i, const char *property, void *data) {
- ExecContext *c = data;
- uint64_t normal, inverted;
-
- assert(i);
- assert(property);
- assert(c);
-
- /* We store this negated internally, to match the kernel, but
- * we expose it normalized. */
-
- normal = *(uint64_t*) data;
- inverted = ~normal;
-
- return bus_property_append_uint64(i, property, &inverted);
-}
-
-int bus_execute_append_capabilities(DBusMessageIter *i, const char *property, void *data) {
- ExecContext *c = data;
- char *t = NULL;
- const char *s;
- dbus_bool_t b;
-
- assert(i);
- assert(property);
- assert(c);
-
- if (c->capabilities)
- s = t = cap_to_text(c->capabilities, NULL);
- else
- s = "";
-
- if (!s)
- return -ENOMEM;
-
- b = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &s);
-
- if (t)
- cap_free(t);
-
- if (!b)
- return -ENOMEM;
-
- return 0;
-}
-
-int bus_execute_append_rlimits(DBusMessageIter *i, const char *property, void *data) {
- ExecContext *c = data;
- int r;
- uint64_t u;
-
- assert(i);
- assert(property);
- assert(c);
-
- assert_se((r = rlimit_from_string(property)) >= 0);
-
- if (c->rlimit[r])
- u = (uint64_t) c->rlimit[r]->rlim_max;
- else {
- struct rlimit rl;
-
- zero(rl);
- getrlimit(r, &rl);
-
- u = (uint64_t) rl.rlim_max;
- }
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT64, &u))
- return -ENOMEM;
-
- return 0;
-}
-
-int bus_execute_append_command(DBusMessageIter *i, const char *property, void *data) {
- ExecCommand *c = data;
- DBusMessageIter sub, sub2, sub3;
-
- assert(i);
- assert(property);
-
- if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sasbttttuii)", &sub))
- return -ENOMEM;
-
- LIST_FOREACH(command, c, c) {
- char **l;
- uint32_t pid;
- int32_t code, status;
- dbus_bool_t b;
-
- if (!c->path)
- continue;
-
- if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &c->path) ||
- !dbus_message_iter_open_container(&sub2, DBUS_TYPE_ARRAY, "s", &sub3))
- return -ENOMEM;
-
- STRV_FOREACH(l, c->argv)
- if (!dbus_message_iter_append_basic(&sub3, DBUS_TYPE_STRING, l))
- return -ENOMEM;
-
- pid = (uint32_t) c->exec_status.pid;
- code = (int32_t) c->exec_status.code;
- status = (int32_t) c->exec_status.status;
-
- b = !!c->ignore;
-
- if (!dbus_message_iter_close_container(&sub2, &sub3) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_BOOLEAN, &b) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.start_timestamp.realtime) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.start_timestamp.monotonic) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.exit_timestamp.realtime) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &c->exec_status.exit_timestamp.monotonic) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &pid) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_INT32, &code) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_INT32, &status))
- return -ENOMEM;
-
- if (!dbus_message_iter_close_container(&sub, &sub2))
- return -ENOMEM;
- }
-
- if (!dbus_message_iter_close_container(i, &sub))
- return -ENOMEM;
-
- return 0;
-}
-
-int bus_execute_append_syscall_filter(DBusMessageIter *i, const char *property, void *data) {
- ExecContext *c = data;
- dbus_bool_t b;
- DBusMessageIter sub;
-
- assert(i);
- assert(property);
- assert(c);
-
- if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "u", &sub))
- return -ENOMEM;
-
- if (c->syscall_filter)
- b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_UINT32, &c->syscall_filter, (syscall_max() + 31) >> 4);
- else
- b = dbus_message_iter_append_fixed_array(&sub, DBUS_TYPE_UINT32, &c->syscall_filter, 0);
-
- if (!b)
- return -ENOMEM;
-
- if (!dbus_message_iter_close_container(i, &sub))
- return -ENOMEM;
-
- return 0;
-}
-
-const BusProperty bus_exec_context_properties[] = {
- { "Environment", bus_property_append_strv, "as", offsetof(ExecContext, environment), true },
- { "EnvironmentFiles", bus_execute_append_env_files, "a(sb)", offsetof(ExecContext, environment_files), true },
- { "UMask", bus_property_append_mode, "u", offsetof(ExecContext, umask) },
- { "LimitCPU", bus_execute_append_rlimits, "t", 0 },
- { "LimitFSIZE", bus_execute_append_rlimits, "t", 0 },
- { "LimitDATA", bus_execute_append_rlimits, "t", 0 },
- { "LimitSTACK", bus_execute_append_rlimits, "t", 0 },
- { "LimitCORE", bus_execute_append_rlimits, "t", 0 },
- { "LimitRSS", bus_execute_append_rlimits, "t", 0 },
- { "LimitNOFILE", bus_execute_append_rlimits, "t", 0 },
- { "LimitAS", bus_execute_append_rlimits, "t", 0 },
- { "LimitNPROC", bus_execute_append_rlimits, "t", 0 },
- { "LimitMEMLOCK", bus_execute_append_rlimits, "t", 0 },
- { "LimitLOCKS", bus_execute_append_rlimits, "t", 0 },
- { "LimitSIGPENDING", bus_execute_append_rlimits, "t", 0 },
- { "LimitMSGQUEUE", bus_execute_append_rlimits, "t", 0 },
- { "LimitNICE", bus_execute_append_rlimits, "t", 0 },
- { "LimitRTPRIO", bus_execute_append_rlimits, "t", 0 },
- { "LimitRTTIME", bus_execute_append_rlimits, "t", 0 },
- { "WorkingDirectory", bus_property_append_string, "s", offsetof(ExecContext, working_directory), true },
- { "RootDirectory", bus_property_append_string, "s", offsetof(ExecContext, root_directory), true },
- { "OOMScoreAdjust", bus_execute_append_oom_score_adjust, "i", 0 },
- { "Nice", bus_execute_append_nice, "i", 0 },
- { "IOScheduling", bus_execute_append_ioprio, "i", 0 },
- { "CPUSchedulingPolicy", bus_execute_append_cpu_sched_policy, "i", 0 },
- { "CPUSchedulingPriority", bus_execute_append_cpu_sched_priority, "i", 0 },
- { "CPUAffinity", bus_execute_append_affinity, "ay", 0 },
- { "TimerSlackNSec", bus_execute_append_timer_slack_nsec, "t", 0 },
- { "CPUSchedulingResetOnFork", bus_property_append_bool, "b", offsetof(ExecContext, cpu_sched_reset_on_fork) },
- { "NonBlocking", bus_property_append_bool, "b", offsetof(ExecContext, non_blocking) },
- { "StandardInput", bus_execute_append_input, "s", offsetof(ExecContext, std_input) },
- { "StandardOutput", bus_execute_append_output, "s", offsetof(ExecContext, std_output) },
- { "StandardError", bus_execute_append_output, "s", offsetof(ExecContext, std_error) },
- { "TTYPath", bus_property_append_string, "s", offsetof(ExecContext, tty_path), true },
- { "TTYReset", bus_property_append_bool, "b", offsetof(ExecContext, tty_reset) },
- { "TTYVHangup", bus_property_append_bool, "b", offsetof(ExecContext, tty_vhangup) },
- { "TTYVTDisallocate", bus_property_append_bool, "b", offsetof(ExecContext, tty_vt_disallocate) },
- { "SyslogPriority", bus_property_append_int, "i", offsetof(ExecContext, syslog_priority) },
- { "SyslogIdentifier", bus_property_append_string, "s", offsetof(ExecContext, syslog_identifier), true },
- { "SyslogLevelPrefix", bus_property_append_bool, "b", offsetof(ExecContext, syslog_level_prefix) },
- { "Capabilities", bus_execute_append_capabilities, "s", 0 },
- { "SecureBits", bus_property_append_int, "i", offsetof(ExecContext, secure_bits) },
- { "CapabilityBoundingSet", bus_execute_append_capability_bs, "t", offsetof(ExecContext, capability_bounding_set_drop) },
- { "User", bus_property_append_string, "s", offsetof(ExecContext, user), true },
- { "Group", bus_property_append_string, "s", offsetof(ExecContext, group), true },
- { "SupplementaryGroups", bus_property_append_strv, "as", offsetof(ExecContext, supplementary_groups), true },
- { "TCPWrapName", bus_property_append_string, "s", offsetof(ExecContext, tcpwrap_name), true },
- { "PAMName", bus_property_append_string, "s", offsetof(ExecContext, pam_name), true },
- { "ReadWriteDirectories", bus_property_append_strv, "as", offsetof(ExecContext, read_write_dirs), true },
- { "ReadOnlyDirectories", bus_property_append_strv, "as", offsetof(ExecContext, read_only_dirs), true },
- { "InaccessibleDirectories", bus_property_append_strv, "as", offsetof(ExecContext, inaccessible_dirs), true },
- { "MountFlags", bus_property_append_ul, "t", offsetof(ExecContext, mount_flags) },
- { "PrivateTmp", bus_property_append_bool, "b", offsetof(ExecContext, private_tmp) },
- { "PrivateNetwork", bus_property_append_bool, "b", offsetof(ExecContext, private_network) },
- { "SameProcessGroup", bus_property_append_bool, "b", offsetof(ExecContext, same_pgrp) },
- { "UtmpIdentifier", bus_property_append_string, "s", offsetof(ExecContext, utmp_id), true },
- { "ControlGroupModify", bus_property_append_bool, "b", offsetof(ExecContext, control_group_modify) },
- { "ControlGroupPersistent", bus_property_append_tristate_false, "b", offsetof(ExecContext, control_group_persistent) },
- { "IgnoreSIGPIPE", bus_property_append_bool, "b", offsetof(ExecContext, ignore_sigpipe) },
- { "NoNewPrivileges", bus_property_append_bool, "b", offsetof(ExecContext, no_new_privileges) },
- { "SystemCallFilter", bus_execute_append_syscall_filter, "au", 0 },
- { NULL, }
-};
diff --git a/src/core/dbus-execute.h b/src/core/dbus-execute.h
deleted file mode 100644
index eaa1b73e69..0000000000
--- a/src/core/dbus-execute.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus/dbus.h>
-
-#include "manager.h"
-#include "dbus-common.h"
-
-#define BUS_EXEC_STATUS_INTERFACE(prefix) \
- " <property name=\"" prefix "StartTimestamp\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"" prefix "StartTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"" prefix "ExitTimestamp\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"" prefix "ExitTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"" prefix "PID\" type=\"u\" access=\"read\"/>\n" \
- " <property name=\"" prefix "Code\" type=\"i\" access=\"read\"/>\n" \
- " <property name=\"" prefix "Status\" type=\"i\" access=\"read\"/>\n"
-
-#define BUS_EXEC_CONTEXT_INTERFACE \
- " <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"UMask\" type=\"u\" access=\"read\"/>\n" \
- " <property name=\"LimitCPU\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"LimitFSIZE\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"LimitDATA\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"LimitSTACK\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"LimitCORE\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"LimitRSS\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"LimitNOFILE\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"LimitAS\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"LimitNPROC\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"LimitMEMLOCK\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"LimitLOCKS\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"LimitSIGPENDING\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"LimitMSGQUEUE\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"LimitNICE\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"LimitRTPRIO\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"LimitRTTIME\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"WorkingDirectory\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"RootDirectory\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"OOMScoreAdjust\" type=\"i\" access=\"read\"/>\n" \
- " <property name=\"Nice\" type=\"i\" access=\"read\"/>\n" \
- " <property name=\"IOScheduling\" type=\"i\" access=\"read\"/>\n" \
- " <property name=\"CPUSchedulingPolicy\" type=\"i\" access=\"read\"/>\n" \
- " <property name=\"CPUSchedulingPriority\" type=\"i\" access=\"read\"/>\n" \
- " <property name=\"CPUAffinity\" type=\"ay\" access=\"read\"/>\n" \
- " <property name=\"TimerSlackNS\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"CPUSchedulingResetOnFork\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"NonBlocking\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"StandardInput\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"StandardOutput\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"StandardError\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"TTYPath\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"TTYReset\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"TTYVHangup\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"TTYVTDisallocate\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"SyslogPriority\" type=\"i\" access=\"read\"/>\n" \
- " <property name=\"SyslogIdentifier\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"SyslogLevelPrefix\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"Capabilities\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"SecureBits\" type=\"i\" access=\"read\"/>\n" \
- " <property name=\"CapabilityBoundingSet\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"User\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"Group\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"SupplementaryGroups\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"TCPWrapName\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"PAMName\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"ReadWriteDirectories\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"ReadOnlyDirectories\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"InaccessibleDirectories\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"MountFlags\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"PrivateTmp\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"SameProcessGroup\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"KillMode\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"KillSignal\" type=\"i\" access=\"read\"/>\n" \
- " <property name=\"UtmpIdentifier\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"ControlGroupModify\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"ControlGroupPersistent\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"PrivateNetwork\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"IgnoreSIGPIPE\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"NoNewPrivileges\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"SystemCallFilter\" type=\"au\" access=\"read\"/>\n"
-
-#define BUS_EXEC_COMMAND_INTERFACE(name) \
- " <property name=\"" name "\" type=\"a(sasbttuii)\" access=\"read\"/>\n"
-
-extern const BusProperty bus_exec_context_properties[];
-
-#define BUS_EXEC_COMMAND_PROPERTY(name, command, indirect) \
- { name, bus_execute_append_command, "a(sasbttttuii)", (command), (indirect), NULL }
-
-int bus_execute_append_output(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_input(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_oom_score_adjust(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_nice(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_ioprio(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_cpu_sched_policy(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_cpu_sched_priority(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_affinity(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_timer_slack_nsec(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_capabilities(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_capability_bs(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_rlimits(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_command(DBusMessageIter *u, const char *property, void *data);
-int bus_execute_append_env_files(DBusMessageIter *i, const char *property, void *data);
-int bus_execute_append_syscall_filter(DBusMessageIter *i, const char *property, void *data);
diff --git a/src/core/dbus-job.c b/src/core/dbus-job.c
deleted file mode 100644
index fdc1dce177..0000000000
--- a/src/core/dbus-job.c
+++ /dev/null
@@ -1,378 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-
-#include "dbus.h"
-#include "log.h"
-#include "dbus-job.h"
-#include "dbus-common.h"
-#include "selinux-access.h"
-
-#define BUS_JOB_INTERFACE \
- " <interface name=\"org.freedesktop.systemd1.Job\">\n" \
- " <method name=\"Cancel\"/>\n" \
- " <property name=\"Id\" type=\"u\" access=\"read\"/>\n" \
- " <property name=\"Unit\" type=\"(so)\" access=\"read\"/>\n" \
- " <property name=\"JobType\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"State\" type=\"s\" access=\"read\"/>\n" \
- " </interface>\n"
-
-#define INTROSPECTION \
- DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
- "<node>\n" \
- BUS_JOB_INTERFACE \
- BUS_PROPERTIES_INTERFACE \
- BUS_PEER_INTERFACE \
- BUS_INTROSPECTABLE_INTERFACE \
- "</node>\n"
-
-const char bus_job_interface[] _introspect_("Job") = BUS_JOB_INTERFACE;
-
-#define INTERFACES_LIST \
- BUS_GENERIC_INTERFACES_LIST \
- "org.freedesktop.systemd1.Job\0"
-
-#define INVALIDATING_PROPERTIES \
- "State\0"
-
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_job_append_state, job_state, JobState);
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_job_append_type, job_type, JobType);
-
-static int bus_job_append_unit(DBusMessageIter *i, const char *property, void *data) {
- Job *j = data;
- DBusMessageIter sub;
- char *p;
-
- assert(i);
- assert(property);
- assert(j);
-
- if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
- return -ENOMEM;
-
- p = unit_dbus_path(j->unit);
- if (!p)
- return -ENOMEM;
-
- if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &j->unit->id) ||
- !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
- free(p);
- return -ENOMEM;
- }
-
- free(p);
-
- if (!dbus_message_iter_close_container(i, &sub))
- return -ENOMEM;
-
- return 0;
-}
-
-static const BusProperty bus_job_properties[] = {
- { "Id", bus_property_append_uint32, "u", offsetof(Job, id) },
- { "State", bus_job_append_state, "s", offsetof(Job, state) },
- { "JobType", bus_job_append_type, "s", offsetof(Job, type) },
- { "Unit", bus_job_append_unit, "(so)", 0 },
- { NULL, }
-};
-
-static DBusHandlerResult bus_job_message_dispatch(Job *j, DBusConnection *connection, DBusMessage *message) {
- _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
-
- if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Job", "Cancel")) {
-
- SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "stop");
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
-
- job_finish_and_invalidate(j, JOB_CANCELED, true);
- } else {
- const BusBoundProperties bps[] = {
- { "org.freedesktop.systemd1.Job", bus_job_properties, j },
- { NULL, }
- };
-
- SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "status");
-
- return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
- }
-
- if (!dbus_connection_send(connection, reply, NULL))
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
-
- return DBUS_HANDLER_RESULT_HANDLED;
-}
-
-static DBusHandlerResult bus_job_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
- Manager *m = data;
- Job *j;
- int r;
- _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
-
- assert(connection);
- assert(message);
- assert(m);
-
- if (streq(dbus_message_get_path(message), "/org/freedesktop/systemd1/job")) {
- /* Be nice to gdbus and return introspection data for our mid-level paths */
-
- if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
- char *introspection = NULL;
- FILE *f;
- Iterator i;
- size_t size;
-
- SELINUX_ACCESS_CHECK(connection, message, "status");
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- /* We roll our own introspection code here, instead of
- * relying on bus_default_message_handler() because we
- * need to generate our introspection string
- * dynamically. */
-
- f = open_memstream(&introspection, &size);
- if (!f)
- goto oom;
-
- fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
- "<node>\n", f);
-
- fputs(BUS_INTROSPECTABLE_INTERFACE, f);
- fputs(BUS_PEER_INTERFACE, f);
-
- HASHMAP_FOREACH(j, m->jobs, i)
- fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
-
- fputs("</node>\n", f);
-
- if (ferror(f)) {
- fclose(f);
- free(introspection);
- goto oom;
- }
-
- fclose(f);
-
- if (!introspection)
- goto oom;
-
- if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
- free(introspection);
- goto oom;
- }
-
- free(introspection);
-
- if (!dbus_connection_send(connection, reply, NULL))
- goto oom;
-
- return DBUS_HANDLER_RESULT_HANDLED;
- }
-
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- }
-
- r = manager_get_job_from_dbus_path(m, dbus_message_get_path(message), &j);
- if (r == -ENOMEM)
- goto oom;
- if (r == -ENOENT) {
- DBusError e;
-
- dbus_error_init(&e);
- dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown job");
- return bus_send_error_reply(connection, message, &e, r);
- }
- if (r < 0)
- return bus_send_error_reply(connection, message, NULL, r);
-
- return bus_job_message_dispatch(j, connection, message);
-
-oom:
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
-}
-
-const DBusObjectPathVTable bus_job_vtable = {
- .message_function = bus_job_message_handler
-};
-
-static int job_send_message(Job *j, DBusMessage* (*new_message)(Job *j)) {
- DBusMessage *m = NULL;
- int r;
-
- assert(j);
- assert(new_message);
-
- if (bus_has_subscriber(j->manager) || j->forgot_bus_clients) {
- m = new_message(j);
- if (!m)
- goto oom;
- r = bus_broadcast(j->manager, m);
- dbus_message_unref(m);
- if (r < 0)
- return r;
-
- } else {
- /* If nobody is subscribed, we just send the message
- * to the client(s) which created the job */
- JobBusClient *cl;
- assert(j->bus_client_list);
- LIST_FOREACH(client, cl, j->bus_client_list) {
- assert(cl->bus);
-
- m = new_message(j);
- if (!m)
- goto oom;
-
- if (!dbus_message_set_destination(m, cl->name))
- goto oom;
-
- if (!dbus_connection_send(cl->bus, m, NULL))
- goto oom;
-
- dbus_message_unref(m);
- m = NULL;
- }
- }
-
- return 0;
-oom:
- if (m)
- dbus_message_unref(m);
- return -ENOMEM;
-}
-
-static DBusMessage* new_change_signal_message(Job *j) {
- DBusMessage *m = NULL;
- char *p = NULL;
-
- p = job_dbus_path(j);
- if (!p)
- goto oom;
-
- if (j->sent_dbus_new_signal) {
- /* Send a properties changed signal */
- m = bus_properties_changed_new(p, "org.freedesktop.systemd1.Job", INVALIDATING_PROPERTIES);
- if (!m)
- goto oom;
-
- } else {
- /* Send a new signal */
-
- m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "JobNew");
- if (!m)
- goto oom;
-
- if (!dbus_message_append_args(m,
- DBUS_TYPE_UINT32, &j->id,
- DBUS_TYPE_OBJECT_PATH, &p,
- DBUS_TYPE_STRING, &j->unit->id,
- DBUS_TYPE_INVALID))
- goto oom;
- }
-
- return m;
-
-oom:
- if (m)
- dbus_message_unref(m);
- free(p);
- return NULL;
-}
-
-static DBusMessage* new_removed_signal_message(Job *j) {
- DBusMessage *m = NULL;
- char *p = NULL;
- const char *r;
-
- p = job_dbus_path(j);
- if (!p)
- goto oom;
-
- m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "JobRemoved");
- if (!m)
- goto oom;
-
- r = job_result_to_string(j->result);
-
- if (!dbus_message_append_args(m,
- DBUS_TYPE_UINT32, &j->id,
- DBUS_TYPE_OBJECT_PATH, &p,
- DBUS_TYPE_STRING, &j->unit->id,
- DBUS_TYPE_STRING, &r,
- DBUS_TYPE_INVALID))
- goto oom;
-
- return m;
-
-oom:
- if (m)
- dbus_message_unref(m);
- free(p);
- return NULL;
-}
-
-void bus_job_send_change_signal(Job *j) {
- assert(j);
-
- if (j->in_dbus_queue) {
- LIST_REMOVE(Job, dbus_queue, j->manager->dbus_job_queue, j);
- j->in_dbus_queue = false;
- }
-
- if (!bus_has_subscriber(j->manager) && !j->bus_client_list && !j->forgot_bus_clients) {
- j->sent_dbus_new_signal = true;
- return;
- }
-
- if (job_send_message(j, new_change_signal_message) < 0)
- goto oom;
-
- j->sent_dbus_new_signal = true;
-
- return;
-
-oom:
- log_error("Failed to allocate job change signal.");
-}
-
-void bus_job_send_removed_signal(Job *j) {
- assert(j);
-
- if (!bus_has_subscriber(j->manager) && !j->bus_client_list && !j->forgot_bus_clients)
- return;
-
- if (!j->sent_dbus_new_signal)
- bus_job_send_change_signal(j);
-
- if (job_send_message(j, new_removed_signal_message) < 0)
- goto oom;
-
- return;
-
-oom:
- log_error("Failed to allocate job remove signal.");
-}
diff --git a/src/core/dbus-job.h b/src/core/dbus-job.h
deleted file mode 100644
index a1b928fb16..0000000000
--- a/src/core/dbus-job.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus/dbus.h>
-
-#include "job.h"
-
-void bus_job_send_change_signal(Job *j);
-void bus_job_send_removed_signal(Job *j);
-
-extern const DBusObjectPathVTable bus_job_vtable;
-
-extern const char bus_job_interface[];
diff --git a/src/core/dbus-kill.c b/src/core/dbus-kill.c
deleted file mode 100644
index 165f63074b..0000000000
--- a/src/core/dbus-kill.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2012 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <dbus/dbus.h>
-
-#include "dbus-kill.h"
-#include "dbus-common.h"
-
-DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_kill_append_mode, kill_mode, KillMode);
-
-const BusProperty bus_kill_context_properties[] = {
- { "KillMode", bus_kill_append_mode, "s", offsetof(KillContext, kill_mode) },
- { "KillSignal", bus_property_append_int, "i", offsetof(KillContext, kill_signal) },
- { "SendSIGKILL", bus_property_append_bool, "b", offsetof(KillContext, send_sigkill) },
- { NULL, }
-};
diff --git a/src/core/dbus-kill.h b/src/core/dbus-kill.h
deleted file mode 100644
index 238fbd36d6..0000000000
--- a/src/core/dbus-kill.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 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 <dbus/dbus.h>
-
-#include "manager.h"
-#include "dbus-common.h"
-
-#define BUS_KILL_CONTEXT_INTERFACE \
- " <property name=\"KillMode\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"KillSignal\" type=\"i\" access=\"read\"/>\n" \
- " <property name=\"SendSIGKILL\" type=\"b\" access=\"read\"/>\n"
-
-#define BUS_KILL_COMMAND_INTERFACE(name) \
- " <property name=\"" name "\" type=\"a(sasbttuii)\" access=\"read\"/>\n"
-
-extern const BusProperty bus_kill_context_properties[];
-
-int bus_kill_append_mode(DBusMessageIter *i, const char *property, void *data);
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
deleted file mode 100644
index 2010241e6a..0000000000
--- a/src/core/dbus-manager.c
+++ /dev/null
@@ -1,1685 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <unistd.h>
-
-#include "dbus.h"
-#include "log.h"
-#include "dbus-manager.h"
-#include "strv.h"
-#include "bus-errors.h"
-#include "build.h"
-#include "dbus-common.h"
-#include "install.h"
-#include "selinux-access.h"
-#include "watchdog.h"
-#include "hwclock.h"
-#include "path-util.h"
-#include "dbus-unit.h"
-#include "virt.h"
-
-#define BUS_MANAGER_INTERFACE_BEGIN \
- " <interface name=\"org.freedesktop.systemd1.Manager\">\n"
-
-#define BUS_MANAGER_INTERFACE_METHODS \
- " <method name=\"GetUnit\">\n" \
- " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"GetUnitByPID\">\n" \
- " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
- " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"LoadUnit\">\n" \
- " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"StartUnit\">\n" \
- " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"StartUnitReplace\">\n" \
- " <arg name=\"old_unit\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"new_unit\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"StopUnit\">\n" \
- " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"ReloadUnit\">\n" \
- " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"RestartUnit\">\n" \
- " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"TryRestartUnit\">\n" \
- " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"ReloadOrRestartUnit\">\n" \
- " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"ReloadOrTryRestartUnit\">\n" \
- " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"KillUnit\">\n" \
- " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"signal\" type=\"i\" direction=\"in\"/>\n" \
- " </method>\n" \
- " <method name=\"ResetFailedUnit\">\n" \
- " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
- " </method>\n" \
- " <method name=\"GetJob\">\n" \
- " <arg name=\"id\" type=\"u\" direction=\"in\"/>\n" \
- " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"ClearJobs\"/>\n" \
- " <method name=\"ResetFailed\"/>\n" \
- " <method name=\"ListUnits\">\n" \
- " <arg name=\"units\" type=\"a(ssssssouso)\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"ListJobs\">\n" \
- " <arg name=\"jobs\" type=\"a(usssoo)\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"Subscribe\"/>\n" \
- " <method name=\"Unsubscribe\"/>\n" \
- " <method name=\"Dump\">\n" \
- " <arg name=\"dump\" type=\"s\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"CreateSnapshot\">\n" \
- " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"cleanup\" type=\"b\" direction=\"in\"/>\n" \
- " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"Reload\"/>\n" \
- " <method name=\"Reexecute\"/>\n" \
- " <method name=\"Exit\"/>\n" \
- " <method name=\"Reboot\"/>\n" \
- " <method name=\"PowerOff\"/>\n" \
- " <method name=\"Halt\"/>\n" \
- " <method name=\"KExec\"/>\n" \
- " <method name=\"SwitchRoot\">\n" \
- " <arg name=\"new_root\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"init\" type=\"s\" direction=\"in\"/>\n" \
- " </method>\n" \
- " <method name=\"SetEnvironment\">\n" \
- " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \
- " </method>\n" \
- " <method name=\"UnsetEnvironment\">\n" \
- " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \
- " </method>\n" \
- " <method name=\"UnsetAndSetEnvironment\">\n" \
- " <arg name=\"unset\" type=\"as\" direction=\"in\"/>\n" \
- " <arg name=\"set\" type=\"as\" direction=\"in\"/>\n" \
- " </method>\n" \
- " <method name=\"ListUnitFiles\">\n" \
- " <arg name=\"files\" type=\"a(ss)\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"GetUnitFileState\">\n" \
- " <arg name=\"file\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"state\" type=\"s\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"EnableUnitFiles\">\n" \
- " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
- " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
- " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
- " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
- " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"DisableUnitFiles\">\n" \
- " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
- " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
- " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"ReenableUnitFiles\">\n" \
- " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
- " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
- " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
- " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
- " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"LinkUnitFiles\">\n" \
- " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
- " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
- " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
- " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"PresetUnitFiles\">\n" \
- " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
- " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
- " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
- " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
- " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"MaskUnitFiles\">\n" \
- " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
- " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
- " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
- " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"UnmaskUnitFiles\">\n" \
- " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
- " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
- " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
- " </method>\n"
-
-#define BUS_MANAGER_INTERFACE_SIGNALS \
- " <signal name=\"UnitNew\">\n" \
- " <arg name=\"id\" type=\"s\"/>\n" \
- " <arg name=\"unit\" type=\"o\"/>\n" \
- " </signal>\n" \
- " <signal name=\"UnitRemoved\">\n" \
- " <arg name=\"id\" type=\"s\"/>\n" \
- " <arg name=\"unit\" type=\"o\"/>\n" \
- " </signal>\n" \
- " <signal name=\"JobNew\">\n" \
- " <arg name=\"id\" type=\"u\"/>\n" \
- " <arg name=\"job\" type=\"o\"/>\n" \
- " <arg name=\"unit\" type=\"s\"/>\n" \
- " </signal>\n" \
- " <signal name=\"JobRemoved\">\n" \
- " <arg name=\"id\" type=\"u\"/>\n" \
- " <arg name=\"job\" type=\"o\"/>\n" \
- " <arg name=\"unit\" type=\"s\"/>\n" \
- " <arg name=\"result\" type=\"s\"/>\n" \
- " </signal>" \
- " <signal name=\"StartupFinished\">\n" \
- " <arg name=\"firmware\" type=\"t\"/>\n" \
- " <arg name=\"loader\" type=\"t\"/>\n" \
- " <arg name=\"kernel\" type=\"t\"/>\n" \
- " <arg name=\"initrd\" type=\"t\"/>\n" \
- " <arg name=\"userspace\" type=\"t\"/>\n" \
- " <arg name=\"total\" type=\"t\"/>\n" \
- " </signal>" \
- " <signal name=\"UnitFilesChanged\"/>\n"
-
-#define BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
- " <property name=\"Version\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"Distribution\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"Features\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"Tainted\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"FirmwareTimestamp\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"FirmwareTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"LoaderTimestamp\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"LoaderTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"KernelTimestamp\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"KernelTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"InitRDTimestamp\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"InitRDTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"UserspaceTimestamp\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"UserspaceTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"FinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"FinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"LogLevel\" type=\"s\" access=\"readwrite\"/>\n" \
- " <property name=\"LogTarget\" type=\"s\" access=\"readwrite\"/>\n" \
- " <property name=\"NNames\" type=\"u\" access=\"read\"/>\n" \
- " <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n" \
- " <property name=\"NInstalledJobs\" type=\"u\" access=\"read\"/>\n" \
- " <property name=\"NFailedJobs\" type=\"u\" access=\"read\"/>\n" \
- " <property name=\"Progress\" type=\"d\" access=\"read\"/>\n" \
- " <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"ShowStatus\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"DefaultControllers\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"DefaultStandardOutput\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"DefaultStandardError\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"RuntimeWatchdogUSec\" type=\"s\" access=\"readwrite\"/>\n" \
- " <property name=\"ShutdownWatchdogUSec\" type=\"s\" access=\"readwrite\"/>\n" \
- " <property name=\"Virtualization\" type=\"s\" access=\"read\"/>\n"
-
-#define BUS_MANAGER_INTERFACE_END \
- " </interface>\n"
-
-#define BUS_MANAGER_INTERFACE \
- BUS_MANAGER_INTERFACE_BEGIN \
- BUS_MANAGER_INTERFACE_METHODS \
- BUS_MANAGER_INTERFACE_SIGNALS \
- BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
- BUS_MANAGER_INTERFACE_END
-
-#define INTROSPECTION_BEGIN \
- DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
- "<node>\n" \
- BUS_MANAGER_INTERFACE \
- BUS_PROPERTIES_INTERFACE \
- BUS_PEER_INTERFACE \
- BUS_INTROSPECTABLE_INTERFACE
-
-#define INTROSPECTION_END \
- "</node>\n"
-
-#define INTERFACES_LIST \
- BUS_GENERIC_INTERFACES_LIST \
- "org.freedesktop.systemd1.Manager\0"
-
-const char bus_manager_interface[] _introspect_("Manager") = BUS_MANAGER_INTERFACE;
-
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput);
-
-static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) {
- const char *t;
- Manager *m = data;
- char buf[LINE_MAX] = "", *e = buf, *p = NULL;
-
- assert(i);
- assert(property);
- assert(m);
-
- if (m->taint_usr)
- e = stpcpy(e, "split-usr:");
-
- if (readlink_malloc("/etc/mtab", &p) < 0)
- e = stpcpy(e, "mtab-not-symlink:");
- else
- free(p);
-
- if (access("/proc/cgroups", F_OK) < 0)
- e = stpcpy(e, "cgroups-missing:");
-
- if (hwclock_is_localtime() > 0)
- e = stpcpy(e, "local-hwclock:");
-
- /* remove the last ':' */
- if (e != buf)
- e[-1] = 0;
-
- t = buf;
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
- return -ENOMEM;
-
- return 0;
-}
-
-static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) {
- const char *t;
-
- assert(i);
- assert(property);
-
- t = log_target_to_string(log_get_target());
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
- return -ENOMEM;
-
- return 0;
-}
-
-static int bus_manager_set_log_target(DBusMessageIter *i, const char *property, void *data) {
- const char *t;
-
- assert(i);
- assert(property);
-
- dbus_message_iter_get_basic(i, &t);
-
- return log_set_target_from_string(t);
-}
-
-static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) {
- char *t;
- int r;
-
- assert(i);
- assert(property);
-
- r = log_level_to_string_alloc(log_get_max_level(), &t);
- if (r < 0)
- return r;
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
- r = -ENOMEM;
-
- free(t);
- return r;
-}
-
-static int bus_manager_set_log_level(DBusMessageIter *i, const char *property, void *data) {
- const char *t;
-
- assert(i);
- assert(property);
-
- dbus_message_iter_get_basic(i, &t);
-
- return log_set_max_level_from_string(t);
-}
-
-static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) {
- Manager *m = data;
- uint32_t u;
-
- assert(i);
- assert(property);
- assert(m);
-
- u = hashmap_size(m->units);
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
- return -ENOMEM;
-
- return 0;
-}
-
-static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) {
- Manager *m = data;
- uint32_t u;
-
- assert(i);
- assert(property);
- assert(m);
-
- u = hashmap_size(m->jobs);
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
- return -ENOMEM;
-
- return 0;
-}
-
-static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) {
- double d;
- Manager *m = data;
-
- assert(i);
- assert(property);
- 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);
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d))
- return -ENOMEM;
-
- return 0;
-}
-
-static int bus_manager_append_virt(DBusMessageIter *i, const char *property, void *data) {
- Manager *m = data;
- const char *id = "";
-
- assert(i);
- assert(property);
- assert(m);
-
- detect_virtualization(&id);
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &id))
- return -ENOMEM;
-
- return 0;
-}
-
-static DBusMessage *message_from_file_changes(
- DBusMessage *m,
- UnitFileChange *changes,
- unsigned n_changes,
- int carries_install_info) {
-
- DBusMessageIter iter, sub, sub2;
- DBusMessage *reply;
- unsigned i;
-
- reply = dbus_message_new_method_return(m);
- if (!reply)
- return NULL;
-
- dbus_message_iter_init_append(reply, &iter);
-
- if (carries_install_info >= 0) {
- dbus_bool_t b;
-
- b = !!carries_install_info;
- if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
- goto oom;
- }
-
- if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub))
- goto oom;
-
- for (i = 0; i < n_changes; i++) {
- const char *type, *path, *source;
-
- type = unit_file_change_type_to_string(changes[i].type);
- path = strempty(changes[i].path);
- source = strempty(changes[i].source);
-
- if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) ||
- !dbus_message_iter_close_container(&sub, &sub2))
- goto oom;
- }
-
- if (!dbus_message_iter_close_container(&iter, &sub))
- goto oom;
-
- return reply;
-
-oom:
- dbus_message_unref(reply);
- return NULL;
-}
-
-static int bus_manager_send_unit_files_changed(Manager *m) {
- DBusMessage *s;
- int r;
-
- s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
- if (!s)
- return -ENOMEM;
-
- r = bus_broadcast(m, s);
- dbus_message_unref(s);
-
- return r;
-}
-
-static int bus_manager_set_runtime_watchdog_usec(DBusMessageIter *i, const char *property, void *data) {
- uint64_t *t = data;
-
- assert(i);
- assert(property);
-
- dbus_message_iter_get_basic(i, t);
-
- return watchdog_set_timeout(t);
-}
-
-static const char systemd_property_string[] =
- PACKAGE_STRING "\0"
- DISTRIBUTION "\0"
- SYSTEMD_FEATURES;
-
-static const BusProperty bus_systemd_properties[] = {
- { "Version", bus_property_append_string, "s", 0 },
- { "Distribution", bus_property_append_string, "s", sizeof(PACKAGE_STRING) },
- { "Features", bus_property_append_string, "s", sizeof(PACKAGE_STRING) + sizeof(DISTRIBUTION) },
- { NULL, }
-};
-
-static const BusProperty bus_manager_properties[] = {
- { "Tainted", bus_manager_append_tainted, "s", 0 },
- { "FirmwareTimestamp", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.realtime) },
- { "FirmwareTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.monotonic) },
- { "LoaderTimestamp", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.realtime) },
- { "LoaderTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.monotonic) },
- { "KernelTimestamp", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.realtime) },
- { "KernelTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.monotonic) },
- { "InitRDTimestamp", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.realtime) },
- { "InitRDTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.monotonic) },
- { "UserspaceTimestamp", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.realtime) },
- { "UserspaceTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.monotonic) },
- { "FinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.realtime) },
- { "FinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.monotonic) },
- { "LogLevel", bus_manager_append_log_level, "s", 0, false, bus_manager_set_log_level },
- { "LogTarget", bus_manager_append_log_target, "s", 0, false, bus_manager_set_log_target },
- { "NNames", bus_manager_append_n_names, "u", 0 },
- { "NJobs", bus_manager_append_n_jobs, "u", 0 },
- { "NInstalledJobs", bus_property_append_uint32, "u", offsetof(Manager, n_installed_jobs) },
- { "NFailedJobs", bus_property_append_uint32, "u", offsetof(Manager, n_failed_jobs) },
- { "Progress", bus_manager_append_progress, "d", 0 },
- { "Environment", bus_property_append_strv, "as", offsetof(Manager, environment), true },
- { "ConfirmSpawn", bus_property_append_bool, "b", offsetof(Manager, confirm_spawn) },
- { "ShowStatus", bus_property_append_bool, "b", offsetof(Manager, show_status) },
- { "UnitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.unit_path), true },
- { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_hierarchy), true },
- { "DefaultControllers", bus_property_append_strv, "as", offsetof(Manager, default_controllers), true },
- { "DefaultStandardOutput", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_output) },
- { "DefaultStandardError", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_error) },
- { "RuntimeWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, runtime_watchdog), false, bus_manager_set_runtime_watchdog_usec },
- { "ShutdownWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, shutdown_watchdog), false, bus_property_set_usec },
- { "Virtualization", bus_manager_append_virt, "s", 0, },
- { NULL, }
-};
-
-static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
- _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
- _cleanup_free_ char * path = NULL;
- Manager *m = data;
- int r;
- DBusError error;
- JobType job_type = _JOB_TYPE_INVALID;
- bool reload_if_possible = false;
- const char *member;
-
- assert(connection);
- assert(message);
- assert(m);
-
- dbus_error_init(&error);
-
- member = dbus_message_get_member(message);
-
- if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
- const char *name;
- Unit *u;
-
- if (!dbus_message_get_args(
- message,
- &error,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_INVALID))
- return bus_send_error_reply(connection, message, &error, -EINVAL);
-
- u = manager_get_unit(m, name);
- if (!u) {
- dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
- return bus_send_error_reply(connection, message, &error, -ENOENT);
- }
-
- SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- path = unit_dbus_path(u);
- if (!path)
- goto oom;
-
- if (!dbus_message_append_args(
- reply,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID))
- goto oom;
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
- Unit *u;
- uint32_t pid;
-
- if (!dbus_message_get_args(
- message,
- &error,
- DBUS_TYPE_UINT32, &pid,
- DBUS_TYPE_INVALID))
- return bus_send_error_reply(connection, message, &error, -EINVAL);
-
- u = cgroup_unit_by_pid(m, (pid_t) pid);
- if (!u) {
- dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
- return bus_send_error_reply(connection, message, &error, -ENOENT);
- }
-
- SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- path = unit_dbus_path(u);
- if (!path)
- goto oom;
-
- if (!dbus_message_append_args(
- reply,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID))
- goto oom;
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
- const char *name;
- Unit *u;
-
- if (!dbus_message_get_args(
- message,
- &error,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_INVALID))
- return bus_send_error_reply(connection, message, &error, -EINVAL);
-
- r = manager_load_unit(m, name, NULL, &error, &u);
- if (r < 0)
- return bus_send_error_reply(connection, message, &error, r);
-
- SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- path = unit_dbus_path(u);
- if (!path)
- goto oom;
-
- if (!dbus_message_append_args(
- reply,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID))
- goto oom;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
- job_type = JOB_START;
- else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
- job_type = JOB_START;
- else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
- job_type = JOB_STOP;
- else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
- job_type = JOB_RELOAD;
- else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
- job_type = JOB_RESTART;
- else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
- job_type = JOB_TRY_RESTART;
- else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
- reload_if_possible = true;
- job_type = JOB_RESTART;
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
- reload_if_possible = true;
- job_type = JOB_TRY_RESTART;
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
- const char *name, *swho;
- int32_t signo;
- Unit *u;
- KillWho who;
-
- if (!dbus_message_get_args(
- message,
- &error,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_STRING, &swho,
- DBUS_TYPE_INT32, &signo,
- DBUS_TYPE_INVALID))
- return bus_send_error_reply(connection, message, &error, -EINVAL);
-
- if (isempty(swho))
- who = KILL_ALL;
- else {
- who = kill_who_from_string(swho);
- if (who < 0)
- return bus_send_error_reply(connection, message, &error, -EINVAL);
- }
-
- if (signo <= 0 || signo >= _NSIG)
- return bus_send_error_reply(connection, message, &error, -EINVAL);
-
- u = manager_get_unit(m, name);
- if (!u) {
- dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
- return bus_send_error_reply(connection, message, &error, -ENOENT);
- }
-
- SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
-
- r = unit_kill(u, who, signo, &error);
- if (r < 0)
- return bus_send_error_reply(connection, message, &error, r);
-
- if (!(reply = dbus_message_new_method_return(message)))
- goto oom;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
- uint32_t id;
- Job *j;
-
- if (!dbus_message_get_args(
- message,
- &error,
- DBUS_TYPE_UINT32, &id,
- DBUS_TYPE_INVALID))
- return bus_send_error_reply(connection, message, &error, -EINVAL);
-
- j = manager_get_job(m, id);
- if (!j) {
- dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
- return bus_send_error_reply(connection, message, &error, -ENOENT);
- }
-
- SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "status");
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- path = job_dbus_path(j);
- if (!path)
- goto oom;
-
- if (!dbus_message_append_args(
- reply,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID))
- goto oom;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
-
- SELINUX_ACCESS_CHECK(connection, message, "reboot");
-
- manager_clear_jobs(m);
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
-
- SELINUX_ACCESS_CHECK(connection, message, "reload");
-
- manager_reset_failed(m);
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
- const char *name;
- Unit *u;
-
- if (!dbus_message_get_args(
- message,
- &error,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_INVALID))
- return bus_send_error_reply(connection, message, &error, -EINVAL);
-
- u = manager_get_unit(m, name);
- if (!u) {
- dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
- return bus_send_error_reply(connection, message, &error, -ENOENT);
- }
-
- SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "reload");
-
- unit_reset_failed(u);
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
- DBusMessageIter iter, sub;
- Iterator i;
- Unit *u;
- const char *k;
-
- SELINUX_ACCESS_CHECK(connection, message, "status");
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- dbus_message_iter_init_append(reply, &iter);
-
- if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub))
- goto oom;
-
- HASHMAP_FOREACH_KEY(u, k, m->units, i) {
- char *u_path, *j_path;
- const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
- DBusMessageIter sub2;
- uint32_t job_id;
- Unit *f;
-
- if (k != u->id)
- continue;
-
- if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
- goto oom;
-
- description = unit_description(u);
- load_state = unit_load_state_to_string(u->load_state);
- active_state = unit_active_state_to_string(unit_active_state(u));
- sub_state = unit_sub_state_to_string(u);
-
- f = unit_following(u);
- following = f ? f->id : "";
-
- u_path = unit_dbus_path(u);
- if (!u_path)
- goto oom;
-
- if (u->job) {
- job_id = (uint32_t) u->job->id;
-
- if (!(j_path = job_dbus_path(u->job))) {
- free(u_path);
- goto oom;
- }
-
- sjob_type = job_type_to_string(u->job->type);
- } else {
- job_id = 0;
- j_path = u_path;
- sjob_type = "";
- }
-
- if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->id) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
- free(u_path);
- if (u->job)
- free(j_path);
- goto oom;
- }
-
- free(u_path);
- if (u->job)
- free(j_path);
-
- if (!dbus_message_iter_close_container(&sub, &sub2))
- goto oom;
- }
-
- if (!dbus_message_iter_close_container(&iter, &sub))
- goto oom;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
- DBusMessageIter iter, sub;
- Iterator i;
- Job *j;
-
- SELINUX_ACCESS_CHECK(connection, message, "status");
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- dbus_message_iter_init_append(reply, &iter);
-
- if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub))
- goto oom;
-
- HASHMAP_FOREACH(j, m->jobs, i) {
- char *u_path, *j_path;
- const char *state, *type;
- uint32_t id;
- DBusMessageIter sub2;
-
- if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
- goto oom;
-
- id = (uint32_t) j->id;
- state = job_state_to_string(j->state);
- type = job_type_to_string(j->type);
-
- j_path = job_dbus_path(j);
- if (!j_path)
- goto oom;
-
- u_path = unit_dbus_path(j->unit);
- if (!u_path) {
- free(j_path);
- goto oom;
- }
-
- if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->id) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) {
- free(j_path);
- free(u_path);
- goto oom;
- }
-
- free(j_path);
- free(u_path);
-
- if (!dbus_message_iter_close_container(&sub, &sub2))
- goto oom;
- }
-
- if (!dbus_message_iter_close_container(&iter, &sub))
- goto oom;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
- char *client;
- Set *s;
-
- SELINUX_ACCESS_CHECK(connection, message, "status");
-
- s = BUS_CONNECTION_SUBSCRIBED(m, connection);
- if (!s) {
- s = set_new(string_hash_func, string_compare_func);
- if (!s)
- goto oom;
-
- if (!dbus_connection_set_data(connection, m->subscribed_data_slot, s, NULL)) {
- set_free(s);
- goto oom;
- }
- }
-
- client = strdup(bus_message_get_sender_with_fallback(message));
- if (!client)
- goto oom;
-
- r = set_put(s, client);
- if (r < 0) {
- free(client);
- return bus_send_error_reply(connection, message, NULL, r);
- }
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
- char *client;
-
- SELINUX_ACCESS_CHECK(connection, message, "status");
-
- client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) bus_message_get_sender_with_fallback(message));
- if (!client) {
- dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
- return bus_send_error_reply(connection, message, &error, -ENOENT);
- }
-
- free(client);
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
- FILE *f;
- char *dump = NULL;
- size_t size;
-
- SELINUX_ACCESS_CHECK(connection, message, "status");
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- f = open_memstream(&dump, &size);
- if (!f)
- goto oom;
-
- manager_dump_units(m, f, NULL);
- manager_dump_jobs(m, f, NULL);
-
- if (ferror(f)) {
- fclose(f);
- free(dump);
- goto oom;
- }
-
- fclose(f);
-
- if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
- free(dump);
- goto oom;
- }
-
- free(dump);
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
- const char *name;
- dbus_bool_t cleanup;
- Snapshot *s;
-
- SELINUX_ACCESS_CHECK(connection, message, "start");
-
- if (!dbus_message_get_args(
- message,
- &error,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_BOOLEAN, &cleanup,
- DBUS_TYPE_INVALID))
- return bus_send_error_reply(connection, message, &error, -EINVAL);
-
- if (isempty(name))
- name = NULL;
-
- r = snapshot_create(m, name, cleanup, &error, &s);
- if (r < 0)
- return bus_send_error_reply(connection, message, &error, r);
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- path = unit_dbus_path(UNIT(s));
- if (!path)
- goto oom;
-
- if (!dbus_message_append_args(
- reply,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID))
- goto oom;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
- char *introspection = NULL;
- FILE *f;
- Iterator i;
- Unit *u;
- Job *j;
- const char *k;
- size_t size;
-
- SELINUX_ACCESS_CHECK(connection, message, "status");
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- /* We roll our own introspection code here, instead of
- * relying on bus_default_message_handler() because we
- * need to generate our introspection string
- * dynamically. */
-
- f = open_memstream(&introspection, &size);
- if (!f)
- goto oom;
-
- fputs(INTROSPECTION_BEGIN, f);
-
- HASHMAP_FOREACH_KEY(u, k, m->units, i) {
- char *p;
-
- if (k != u->id)
- continue;
-
- p = bus_path_escape(k);
- if (!p) {
- fclose(f);
- free(introspection);
- goto oom;
- }
-
- fprintf(f, "<node name=\"unit/%s\"/>", p);
- free(p);
- }
-
- HASHMAP_FOREACH(j, m->jobs, i)
- fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
-
- fputs(INTROSPECTION_END, f);
-
- if (ferror(f)) {
- fclose(f);
- free(introspection);
- goto oom;
- }
-
- fclose(f);
-
- if (!introspection)
- goto oom;
-
- if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
- free(introspection);
- goto oom;
- }
-
- free(introspection);
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
-
- SELINUX_ACCESS_CHECK(connection, message, "reload");
-
- assert(!m->queued_message);
-
- /* 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. */
-
- m->queued_message = dbus_message_new_method_return(message);
- if (!m->queued_message)
- goto oom;
-
- m->queued_message_connection = connection;
- m->exit_code = MANAGER_RELOAD;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
-
- SELINUX_ACCESS_CHECK(connection, message, "reload");
-
- /* We don't send a reply back here, the client should
- * just wait for us disconnecting. */
-
- m->exit_code = MANAGER_REEXECUTE;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
-
- SELINUX_ACCESS_CHECK(connection, message, "halt");
-
- if (m->running_as == SYSTEMD_SYSTEM) {
- dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
- return bus_send_error_reply(connection, message, &error, -ENOTSUP);
- }
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- m->exit_code = MANAGER_EXIT;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
-
- SELINUX_ACCESS_CHECK(connection, message, "reboot");
-
- if (m->running_as != SYSTEMD_SYSTEM) {
- dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
- return bus_send_error_reply(connection, message, &error, -ENOTSUP);
- }
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- m->exit_code = MANAGER_REBOOT;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
-
- SELINUX_ACCESS_CHECK(connection, message, "halt");
-
- if (m->running_as != SYSTEMD_SYSTEM) {
- dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
- return bus_send_error_reply(connection, message, &error, -ENOTSUP);
- }
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- m->exit_code = MANAGER_POWEROFF;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
-
- SELINUX_ACCESS_CHECK(connection, message, "halt");
-
- if (m->running_as != SYSTEMD_SYSTEM) {
- dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
- return bus_send_error_reply(connection, message, &error, -ENOTSUP);
- }
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- m->exit_code = MANAGER_HALT;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
-
- SELINUX_ACCESS_CHECK(connection, message, "reboot");
-
- if (m->running_as != SYSTEMD_SYSTEM) {
- dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
- return bus_send_error_reply(connection, message, &error, -ENOTSUP);
- }
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- m->exit_code = MANAGER_KEXEC;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) {
- const char *switch_root, *switch_root_init;
- char *u, *v;
- int k;
-
- SELINUX_ACCESS_CHECK(connection, message, "reboot");
-
- if (!dbus_message_get_args(
- message,
- &error,
- DBUS_TYPE_STRING, &switch_root,
- DBUS_TYPE_STRING, &switch_root_init,
- DBUS_TYPE_INVALID))
- return bus_send_error_reply(connection, message, &error, -EINVAL);
-
- if (path_equal(switch_root, "/") || !path_is_absolute(switch_root))
- return bus_send_error_reply(connection, message, NULL, -EINVAL);
-
- if (!isempty(switch_root_init) && !path_is_absolute(switch_root_init))
- return bus_send_error_reply(connection, message, NULL, -EINVAL);
-
- if (m->running_as != SYSTEMD_SYSTEM) {
- dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers.");
- return bus_send_error_reply(connection, message, &error, -ENOTSUP);
- }
-
- /* Safety check */
- if (isempty(switch_root_init))
- k = access(switch_root, F_OK);
- else {
- char *p;
-
- p = strjoin(switch_root, "/", switch_root_init, NULL);
- if (!p)
- goto oom;
-
- k = access(p, X_OK);
- free(p);
- }
- if (k < 0)
- return bus_send_error_reply(connection, message, NULL, -errno);
-
- u = strdup(switch_root);
- if (!u)
- goto oom;
-
- if (!isempty(switch_root_init)) {
- v = strdup(switch_root_init);
- if (!v) {
- free(u);
- goto oom;
- }
- } else
- v = NULL;
-
- free(m->switch_root);
- free(m->switch_root_init);
- m->switch_root = u;
- m->switch_root_init = v;
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- m->exit_code = MANAGER_SWITCH_ROOT;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
- char **l = NULL, **e = NULL;
-
- SELINUX_ACCESS_CHECK(connection, message, "reboot");
-
- r = bus_parse_strv(message, &l);
- if (r == -ENOMEM)
- goto oom;
- if (r < 0)
- return bus_send_error_reply(connection, message, NULL, r);
-
- e = strv_env_merge(2, m->environment, l);
- strv_free(l);
- if (!e)
- goto oom;
-
- reply = dbus_message_new_method_return(message);
- if (!reply) {
- strv_free(e);
- goto oom;
- }
-
- strv_free(m->environment);
- m->environment = e;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
- char **l = NULL, **e = NULL;
-
- SELINUX_ACCESS_CHECK(connection, message, "reboot");
-
- r = bus_parse_strv(message, &l);
- if (r == -ENOMEM)
- goto oom;
- if (r < 0)
- return bus_send_error_reply(connection, message, NULL, r);
-
- e = strv_env_delete(m->environment, 1, l);
- strv_free(l);
-
- if (!e)
- goto oom;
-
- if (!(reply = dbus_message_new_method_return(message))) {
- strv_free(e);
- goto oom;
- }
-
- strv_free(m->environment);
- m->environment = e;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
- char **l_set = NULL, **l_unset = NULL, **e = NULL, **f = NULL;
- DBusMessageIter iter;
-
- SELINUX_ACCESS_CHECK(connection, message, "reboot");
-
- if (!dbus_message_iter_init(message, &iter))
- goto oom;
-
- r = bus_parse_strv_iter(&iter, &l_unset);
- if (r == -ENOMEM)
- goto oom;
- if (r < 0)
- return bus_send_error_reply(connection, message, NULL, r);
-
- if (!dbus_message_iter_next(&iter)) {
- strv_free(l_unset);
- return bus_send_error_reply(connection, message, NULL, -EINVAL);
- }
-
- r = bus_parse_strv_iter(&iter, &l_set);
- if (r < 0) {
- strv_free(l_unset);
- if (r == -ENOMEM)
- goto oom;
-
- return bus_send_error_reply(connection, message, NULL, r);
- }
-
- e = strv_env_delete(m->environment, 1, l_unset);
- strv_free(l_unset);
-
- if (!e) {
- strv_free(l_set);
- goto oom;
- }
-
- f = strv_env_merge(2, e, l_set);
- strv_free(l_set);
- strv_free(e);
-
- if (!f)
- goto oom;
-
- if (!(reply = dbus_message_new_method_return(message))) {
- strv_free(f);
- goto oom;
- }
-
- strv_free(m->environment);
- m->environment = f;
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
- DBusMessageIter iter, sub, sub2;
- Hashmap *h;
- Iterator i;
- UnitFileList *item;
-
- SELINUX_ACCESS_CHECK(connection, message, "status");
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- h = hashmap_new(string_hash_func, string_compare_func);
- if (!h)
- goto oom;
-
- r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
- if (r < 0) {
- unit_file_list_free(h);
- dbus_message_unref(reply);
- return bus_send_error_reply(connection, message, NULL, r);
- }
-
- dbus_message_iter_init_append(reply, &iter);
-
- if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
- unit_file_list_free(h);
- goto oom;
- }
-
- HASHMAP_FOREACH(item, h, i) {
- const char *state;
-
- state = unit_file_state_to_string(item->state);
- assert(state);
-
- if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
- !dbus_message_iter_close_container(&sub, &sub2)) {
- unit_file_list_free(h);
- goto oom;
- }
- }
-
- unit_file_list_free(h);
-
- if (!dbus_message_iter_close_container(&iter, &sub))
- goto oom;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
- const char *name;
- UnitFileState state;
- const char *s;
-
- SELINUX_ACCESS_CHECK(connection, message, "status");
-
- if (!dbus_message_get_args(
- message,
- &error,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_INVALID))
- return bus_send_error_reply(connection, message, &error, -EINVAL);
-
- state = unit_file_get_state(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
- if (state < 0)
- return bus_send_error_reply(connection, message, NULL, state);
-
- s = unit_file_state_to_string(state);
- assert(s);
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- if (!dbus_message_append_args(
- reply,
- DBUS_TYPE_STRING, &s,
- DBUS_TYPE_INVALID))
- goto oom;
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
- dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
- dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
- dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
- dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles")) {
-
- char **l = NULL;
- DBusMessageIter iter;
- UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
- UnitFileChange *changes = NULL;
- unsigned n_changes = 0;
- dbus_bool_t runtime, force;
- int carries_install_info = -1;
-
- SELINUX_ACCESS_CHECK(connection, message, streq(member, "MaskUnitFiles") ? "disable" : "enable");
-
- if (!dbus_message_iter_init(message, &iter))
- goto oom;
-
- r = bus_parse_strv_iter(&iter, &l);
- if (r < 0) {
- if (r == -ENOMEM)
- goto oom;
-
- return bus_send_error_reply(connection, message, NULL, r);
- }
-
- if (!dbus_message_iter_next(&iter) ||
- bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
- bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
- strv_free(l);
- return bus_send_error_reply(connection, message, NULL, -EIO);
- }
-
- if (streq(member, "EnableUnitFiles")) {
- r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
- carries_install_info = r;
- } else if (streq(member, "ReenableUnitFiles")) {
- r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
- carries_install_info = r;
- } else if (streq(member, "LinkUnitFiles"))
- r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
- else if (streq(member, "PresetUnitFiles")) {
- r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
- carries_install_info = r;
- } else if (streq(member, "MaskUnitFiles"))
- r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
- else
- assert_not_reached("Uh? Wrong method");
-
- strv_free(l);
- bus_manager_send_unit_files_changed(m);
-
- if (r < 0) {
- unit_file_changes_free(changes, n_changes);
- return bus_send_error_reply(connection, message, NULL, r);
- }
-
- reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
- unit_file_changes_free(changes, n_changes);
-
- if (!reply)
- goto oom;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
- dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
-
- char **l = NULL;
- DBusMessageIter iter;
- UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
- UnitFileChange *changes = NULL;
- unsigned n_changes = 0;
- dbus_bool_t runtime;
-
- SELINUX_ACCESS_CHECK(connection, message, streq(member, "UnmaskUnitFiles") ? "enable" : "disable");
-
- if (!dbus_message_iter_init(message, &iter))
- goto oom;
-
- r = bus_parse_strv_iter(&iter, &l);
- if (r < 0) {
- if (r == -ENOMEM)
- goto oom;
-
- return bus_send_error_reply(connection, message, NULL, r);
- }
-
- if (!dbus_message_iter_next(&iter) ||
- bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
- strv_free(l);
- return bus_send_error_reply(connection, message, NULL, -EIO);
- }
-
- if (streq(member, "DisableUnitFiles"))
- r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
- else if (streq(member, "UnmaskUnitFiles"))
- r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
- else
- assert_not_reached("Uh? Wrong method");
-
- strv_free(l);
- bus_manager_send_unit_files_changed(m);
-
- if (r < 0) {
- unit_file_changes_free(changes, n_changes);
- return bus_send_error_reply(connection, message, NULL, r);
- }
-
- reply = message_from_file_changes(message, changes, n_changes, -1);
- unit_file_changes_free(changes, n_changes);
-
- if (!reply)
- goto oom;
-
- } else {
- const BusBoundProperties bps[] = {
- { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
- { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
- { NULL, }
- };
-
- SELINUX_ACCESS_CHECK(connection, message, "status");
-
- return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
- }
-
- if (job_type != _JOB_TYPE_INVALID) {
- const char *name, *smode, *old_name = NULL;
- JobMode mode;
- Unit *u;
- dbus_bool_t b;
-
- if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
- b = dbus_message_get_args(
- message,
- &error,
- DBUS_TYPE_STRING, &old_name,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_STRING, &smode,
- DBUS_TYPE_INVALID);
- else
- b = dbus_message_get_args(
- message,
- &error,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_STRING, &smode,
- DBUS_TYPE_INVALID);
- if (!b)
- return bus_send_error_reply(connection, message, &error, -EINVAL);
-
- if (old_name) {
- u = manager_get_unit(m, old_name);
- if (!u || !u->job || u->job->type != JOB_START) {
- dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
- return bus_send_error_reply(connection, message, &error, -ENOENT);
- }
- }
-
- mode = job_mode_from_string(smode);
- if (mode < 0) {
- dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
- return bus_send_error_reply(connection, message, &error, -EINVAL);
- }
-
- r = manager_load_unit(m, name, NULL, &error, &u);
- if (r < 0)
- return bus_send_error_reply(connection, message, &error, r);
-
- return bus_unit_queue_job(connection, message, u, job_type, mode, reload_if_possible);
- }
-
- if (reply)
- if (!dbus_connection_send(connection, reply, NULL))
- goto oom;
-
- return DBUS_HANDLER_RESULT_HANDLED;
-
-oom:
- dbus_error_free(&error);
-
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
-}
-
-const DBusObjectPathVTable bus_manager_vtable = {
- .message_function = bus_manager_message_handler
-};
diff --git a/src/core/dbus-manager.h b/src/core/dbus-manager.h
deleted file mode 100644
index f0dce5a2e9..0000000000
--- a/src/core/dbus-manager.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus/dbus.h>
-
-extern const DBusObjectPathVTable bus_manager_vtable;
-
-extern const char bus_manager_interface[];
diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c
deleted file mode 100644
index d81edeb807..0000000000
--- a/src/core/dbus-mount.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-
-#include "dbus-unit.h"
-#include "dbus-mount.h"
-#include "dbus-kill.h"
-#include "dbus-execute.h"
-#include "dbus-common.h"
-#include "selinux-access.h"
-
-#define BUS_MOUNT_INTERFACE \
- " <interface name=\"org.freedesktop.systemd1.Mount\">\n" \
- " <property name=\"Where\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"What\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"Options\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"Type\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>\n" \
- BUS_EXEC_COMMAND_INTERFACE("ExecMount") \
- BUS_EXEC_COMMAND_INTERFACE("ExecUnmount") \
- BUS_EXEC_COMMAND_INTERFACE("ExecRemount") \
- BUS_EXEC_CONTEXT_INTERFACE \
- BUS_KILL_CONTEXT_INTERFACE \
- " <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \
- " <property name=\"DirectoryMode\" type=\"u\" access=\"read\"/>\n" \
- " <property name=\"Result\" type=\"s\" access=\"read\"/>\n" \
- " </interface>\n"
-
-#define INTROSPECTION \
- DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
- "<node>\n" \
- BUS_UNIT_INTERFACE \
- BUS_MOUNT_INTERFACE \
- BUS_PROPERTIES_INTERFACE \
- BUS_PEER_INTERFACE \
- BUS_INTROSPECTABLE_INTERFACE \
- "</node>\n"
-
-#define INTERFACES_LIST \
- BUS_UNIT_INTERFACES_LIST \
- "org.freedesktop.systemd1.Mount\0"
-
-const char bus_mount_interface[] _introspect_("Mount") = BUS_MOUNT_INTERFACE;
-
-const char bus_mount_invalidating_properties[] =
- "What\0"
- "Options\0"
- "Type\0"
- "ExecMount\0"
- "ExecUnmount\0"
- "ExecRemount\0"
- "ControlPID\0"
- "Result\0";
-
-static int bus_mount_append_what(DBusMessageIter *i, const char *property, void *data) {
- Mount *m = data;
- const char *d;
-
- assert(i);
- assert(property);
- 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 = "";
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d))
- return -ENOMEM;
-
- return 0;
-}
-
-static int bus_mount_append_options(DBusMessageIter *i, const char *property, void *data) {
- Mount *m = data;
- const char *d;
-
- assert(i);
- assert(property);
- 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 = "";
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d))
- return -ENOMEM;
-
- return 0;
-}
-
-static int bus_mount_append_type(DBusMessageIter *i, const char *property, void *data) {
- Mount *m = data;
- const char *d;
-
- assert(i);
- assert(property);
- 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 = "";
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d))
- return -ENOMEM;
-
- return 0;
-}
-
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_mount_append_mount_result, mount_result, MountResult);
-
-static const BusProperty bus_mount_properties[] = {
- { "Where", bus_property_append_string, "s", offsetof(Mount, where), true },
- { "What", bus_mount_append_what, "s", 0 },
- { "Options", bus_mount_append_options, "s", 0 },
- { "Type", bus_mount_append_type, "s", 0 },
- { "TimeoutUSec", bus_property_append_usec, "t", offsetof(Mount, timeout_usec) },
- BUS_EXEC_COMMAND_PROPERTY("ExecMount", offsetof(Mount, exec_command[MOUNT_EXEC_MOUNT]), false),
- BUS_EXEC_COMMAND_PROPERTY("ExecUnmount", offsetof(Mount, exec_command[MOUNT_EXEC_UNMOUNT]), false),
- BUS_EXEC_COMMAND_PROPERTY("ExecRemount", offsetof(Mount, exec_command[MOUNT_EXEC_REMOUNT]), false),
- { "ControlPID", bus_property_append_pid, "u", offsetof(Mount, control_pid) },
- { "DirectoryMode", bus_property_append_mode, "u", offsetof(Mount, directory_mode) },
- { "Result", bus_mount_append_mount_result, "s", offsetof(Mount, result) },
- { NULL, }
-};
-
-DBusHandlerResult bus_mount_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
- Mount *m = MOUNT(u);
-
- const BusBoundProperties bps[] = {
- { "org.freedesktop.systemd1.Unit", bus_unit_properties, u },
- { "org.freedesktop.systemd1.Mount", bus_mount_properties, m },
- { "org.freedesktop.systemd1.Mount", bus_exec_context_properties, &m->exec_context },
- { "org.freedesktop.systemd1.Mount", bus_kill_context_properties, &m->kill_context },
- { NULL, }
- };
-
- SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status");
-
- return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps );
-}
diff --git a/src/core/dbus-mount.h b/src/core/dbus-mount.h
deleted file mode 100644
index 8597394373..0000000000
--- a/src/core/dbus-mount.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You 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/dbus.h>
-
-#include "unit.h"
-
-DBusHandlerResult bus_mount_message_handler(Unit *u, DBusConnection *c, DBusMessage *message);
-
-extern const char bus_mount_interface[];
-extern const char bus_mount_invalidating_properties[];
diff --git a/src/core/dbus-path.c b/src/core/dbus-path.c
deleted file mode 100644
index f7fed1754d..0000000000
--- a/src/core/dbus-path.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-
-#include "dbus-unit.h"
-#include "dbus-path.h"
-#include "dbus-execute.h"
-#include "dbus-common.h"
-#include "selinux-access.h"
-
-#define BUS_PATH_INTERFACE \
- " <interface name=\"org.freedesktop.systemd1.Path\">\n" \
- " <property name=\"Unit\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"Paths\" type=\"a(ss)\" access=\"read\"/>\n" \
- " <property name=\"MakeDirectory\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"DirectoryMode\" type=\"u\" access=\"read\"/>\n" \
- " <property name=\"Result\" type=\"s\" access=\"read\"/>\n" \
- " </interface>\n"
-
-#define INTROSPECTION \
- DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
- "<node>\n" \
- BUS_UNIT_INTERFACE \
- BUS_PATH_INTERFACE \
- BUS_PROPERTIES_INTERFACE \
- BUS_PEER_INTERFACE \
- BUS_INTROSPECTABLE_INTERFACE \
- "</node>\n"
-
-#define INTERFACES_LIST \
- BUS_UNIT_INTERFACES_LIST \
- "org.freedesktop.systemd1.Path\0"
-
-const char bus_path_interface[] _introspect_("Path") = BUS_PATH_INTERFACE;
-
-const char bus_path_invalidating_properties[] =
- "Result\0";
-
-static int bus_path_append_paths(DBusMessageIter *i, const char *property, void *data) {
- Path *p = data;
- DBusMessageIter sub, sub2;
- PathSpec *k;
-
- assert(i);
- assert(property);
- assert(p);
-
- if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(ss)", &sub))
- return -ENOMEM;
-
- LIST_FOREACH(spec, k, p->specs) {
- const char *t = path_type_to_string(k->type);
-
- if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &t) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &k->path) ||
- !dbus_message_iter_close_container(&sub, &sub2))
- return -ENOMEM;
- }
-
- if (!dbus_message_iter_close_container(i, &sub))
- return -ENOMEM;
-
- return 0;
-}
-
-static int bus_path_append_unit(DBusMessageIter *i, const char *property, void *data) {
- Unit *u = data;
- Path *p = PATH(u);
- const char *t;
-
- assert(i);
- assert(property);
- assert(u);
-
- t = UNIT_DEREF(p->unit) ? UNIT_DEREF(p->unit)->id : "";
-
- return dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t) ? 0 : -ENOMEM;
-}
-
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_path_append_path_result, path_result, PathResult);
-
-static const BusProperty bus_path_properties[] = {
- { "Unit", bus_path_append_unit, "s", 0 },
- { "Paths", bus_path_append_paths, "a(ss)", 0 },
- { "MakeDirectory", bus_property_append_bool, "b", offsetof(Path, make_directory) },
- { "DirectoryMode", bus_property_append_mode, "u", offsetof(Path, directory_mode) },
- { "Result", bus_path_append_path_result, "s", offsetof(Path, result) },
- { NULL, }
-};
-
-DBusHandlerResult bus_path_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
- Path *p = PATH(u);
- const BusBoundProperties bps[] = {
- { "org.freedesktop.systemd1.Unit", bus_unit_properties, u },
- { "org.freedesktop.systemd1.Path", bus_path_properties, p },
- { NULL, }
- };
-
- SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status");
-
- return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
-}
diff --git a/src/core/dbus-path.h b/src/core/dbus-path.h
deleted file mode 100644
index c945f7d588..0000000000
--- a/src/core/dbus-path.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus/dbus.h>
-
-#include "unit.h"
-
-DBusHandlerResult bus_path_message_handler(Unit *u, DBusConnection *c, DBusMessage *message);
-
-extern const char bus_path_interface[];
-
-extern const char bus_path_invalidating_properties[];
diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
deleted file mode 100644
index d99058dd46..0000000000
--- a/src/core/dbus-service.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-
-#include "dbus-unit.h"
-#include "dbus-execute.h"
-#include "dbus-kill.h"
-#include "dbus-service.h"
-#include "dbus-common.h"
-#include "selinux-access.h"
-
-#define BUS_SERVICE_INTERFACE \
- " <interface name=\"org.freedesktop.systemd1.Service\">\n" \
- " <property name=\"Type\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"Restart\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"PIDFile\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"NotifyAccess\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"RestartUSec\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"WatchdogUSec\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"WatchdogTimestamp\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"WatchdogTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"StartLimitInterval\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"StartLimitBurst\" type=\"u\" access=\"read\"/>\n" \
- " <property name=\"StartLimitAction\" type=\"s\" access=\"readwrite\"/>\n" \
- BUS_EXEC_COMMAND_INTERFACE("ExecStartPre") \
- BUS_EXEC_COMMAND_INTERFACE("ExecStart") \
- BUS_EXEC_COMMAND_INTERFACE("ExecStartPost") \
- BUS_EXEC_COMMAND_INTERFACE("ExecReload") \
- BUS_EXEC_COMMAND_INTERFACE("ExecStop") \
- BUS_EXEC_COMMAND_INTERFACE("ExecStopPost") \
- BUS_EXEC_CONTEXT_INTERFACE \
- BUS_KILL_CONTEXT_INTERFACE \
- " <property name=\"PermissionsStartOnly\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"RootDirectoryStartOnly\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"RemainAfterExit\" type=\"b\" access=\"read\"/>\n" \
- BUS_EXEC_STATUS_INTERFACE("ExecMain") \
- " <property name=\"MainPID\" type=\"u\" access=\"read\"/>\n" \
- " <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \
- " <property name=\"BusName\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"StatusText\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"Result\" type=\"s\" access=\"read\"/>\n" \
- " </interface>\n"
-
-#define INTROSPECTION \
- DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
- "<node>\n" \
- BUS_UNIT_INTERFACE \
- BUS_SERVICE_INTERFACE \
- BUS_PROPERTIES_INTERFACE \
- BUS_PEER_INTERFACE \
- BUS_INTROSPECTABLE_INTERFACE \
- "</node>\n"
-
-#define INTERFACES_LIST \
- BUS_UNIT_INTERFACES_LIST \
- "org.freedesktop.systemd1.Service\0"
-
-const char bus_service_interface[] _introspect_("Service") = BUS_SERVICE_INTERFACE;
-
-const char bus_service_invalidating_properties[] =
- "ExecStartPre\0"
- "ExecStart\0"
- "ExecStartPost\0"
- "ExecReload\0"
- "ExecStop\0"
- "ExecStopPost\0"
- "ExecMain\0"
- "WatchdogTimestamp\0"
- "WatchdogTimestampMonotonic\0"
- "MainPID\0"
- "ControlPID\0"
- "StatusText\0"
- "Result\0";
-
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_type, service_type, ServiceType);
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_restart, service_restart, ServiceRestart);
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_notify_access, notify_access, NotifyAccess);
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_service_result, service_result, ServiceResult);
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_start_limit_action, start_limit_action, StartLimitAction);
-static DEFINE_BUS_PROPERTY_SET_ENUM(bus_service_set_start_limit_action, start_limit_action, StartLimitAction);
-
-static const BusProperty bus_exec_main_status_properties[] = {
- { "ExecMainStartTimestamp", bus_property_append_usec, "t", offsetof(ExecStatus, start_timestamp.realtime) },
- { "ExecMainStartTimestampMonotonic",bus_property_append_usec, "t", offsetof(ExecStatus, start_timestamp.monotonic) },
- { "ExecMainExitTimestamp", bus_property_append_usec, "t", offsetof(ExecStatus, start_timestamp.realtime) },
- { "ExecMainExitTimestampMonotonic", bus_property_append_usec, "t", offsetof(ExecStatus, start_timestamp.monotonic) },
- { "ExecMainPID", bus_property_append_pid, "u", offsetof(ExecStatus, pid) },
- { "ExecMainCode", bus_property_append_int, "i", offsetof(ExecStatus, code) },
- { "ExecMainStatus", bus_property_append_int, "i", offsetof(ExecStatus, status) },
- { NULL, }
-};
-
-static const BusProperty bus_service_properties[] = {
- { "Type", bus_service_append_type, "s", offsetof(Service, type) },
- { "Restart", bus_service_append_restart, "s", offsetof(Service, restart) },
- { "PIDFile", bus_property_append_string, "s", offsetof(Service, pid_file), true },
- { "NotifyAccess", bus_service_append_notify_access, "s", offsetof(Service, notify_access) },
- { "RestartUSec", bus_property_append_usec, "t", offsetof(Service, restart_usec) },
- { "TimeoutUSec", bus_property_append_usec, "t", offsetof(Service, timeout_start_usec) },
- { "TimeoutStartUSec", bus_property_append_usec, "t", offsetof(Service, timeout_start_usec) },
- { "TimeoutStopUSec", bus_property_append_usec, "t", offsetof(Service, timeout_stop_usec) },
- { "WatchdogUSec", bus_property_append_usec, "t", offsetof(Service, watchdog_usec) },
- { "WatchdogTimestamp", bus_property_append_usec, "t", offsetof(Service, watchdog_timestamp.realtime) },
- { "WatchdogTimestampMonotonic",bus_property_append_usec, "t", offsetof(Service, watchdog_timestamp.monotonic) },
- { "StartLimitInterval", bus_property_append_usec, "t", offsetof(Service, start_limit.interval) },
- { "StartLimitBurst", bus_property_append_uint32, "u", offsetof(Service, start_limit.burst) },
- { "StartLimitAction", bus_service_append_start_limit_action,"s", offsetof(Service, start_limit_action), false, bus_service_set_start_limit_action},
- BUS_EXEC_COMMAND_PROPERTY("ExecStartPre", offsetof(Service, exec_command[SERVICE_EXEC_START_PRE]), true ),
- BUS_EXEC_COMMAND_PROPERTY("ExecStart", offsetof(Service, exec_command[SERVICE_EXEC_START]), true ),
- BUS_EXEC_COMMAND_PROPERTY("ExecStartPost", offsetof(Service, exec_command[SERVICE_EXEC_START_POST]), true ),
- BUS_EXEC_COMMAND_PROPERTY("ExecReload", offsetof(Service, exec_command[SERVICE_EXEC_RELOAD]), true ),
- BUS_EXEC_COMMAND_PROPERTY("ExecStop", offsetof(Service, exec_command[SERVICE_EXEC_STOP]), true ),
- BUS_EXEC_COMMAND_PROPERTY("ExecStopPost", offsetof(Service, exec_command[SERVICE_EXEC_STOP_POST]), true ),
- { "PermissionsStartOnly", bus_property_append_bool, "b", offsetof(Service, permissions_start_only) },
- { "RootDirectoryStartOnly", bus_property_append_bool, "b", offsetof(Service, root_directory_start_only) },
- { "RemainAfterExit", bus_property_append_bool, "b", offsetof(Service, remain_after_exit) },
- { "GuessMainPID", bus_property_append_bool, "b", offsetof(Service, guess_main_pid) },
- { "MainPID", bus_property_append_pid, "u", offsetof(Service, main_pid) },
- { "ControlPID", bus_property_append_pid, "u", offsetof(Service, control_pid) },
- { "BusName", bus_property_append_string, "s", offsetof(Service, bus_name), true },
- { "StatusText", bus_property_append_string, "s", offsetof(Service, status_text), true },
- { "Result", bus_service_append_service_result,"s", offsetof(Service, result) },
- { NULL, }
-};
-
-DBusHandlerResult bus_service_message_handler(Unit *u, DBusConnection *connection, DBusMessage *message) {
- Service *s = SERVICE(u);
-
- const BusBoundProperties bps[] = {
- { "org.freedesktop.systemd1.Unit", bus_unit_properties, u },
- { "org.freedesktop.systemd1.Service", bus_service_properties, s },
- { "org.freedesktop.systemd1.Service", bus_exec_context_properties, &s->exec_context },
- { "org.freedesktop.systemd1.Service", bus_kill_context_properties, &s->kill_context },
- { "org.freedesktop.systemd1.Service", bus_exec_main_status_properties, &s->main_exec_status },
- { NULL, }
- };
-
- SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
-
- return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, bps);
-}
diff --git a/src/core/dbus-service.h b/src/core/dbus-service.h
deleted file mode 100644
index 143aed7ae5..0000000000
--- a/src/core/dbus-service.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You 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/dbus.h>
-
-#include "unit.h"
-
-DBusHandlerResult bus_service_message_handler(Unit *u, DBusConnection *c, DBusMessage *message);
-
-extern const char bus_service_interface[];
-extern const char bus_service_invalidating_properties[];
diff --git a/src/core/dbus-snapshot.c b/src/core/dbus-snapshot.c
deleted file mode 100644
index 435c6df39c..0000000000
--- a/src/core/dbus-snapshot.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "dbus-unit.h"
-#include "dbus-snapshot.h"
-#include "dbus-common.h"
-#include "selinux-access.h"
-
-#define BUS_SNAPSHOT_INTERFACE \
- " <interface name=\"org.freedesktop.systemd1.Snapshot\">\n" \
- " <method name=\"Remove\"/>\n" \
- " <property name=\"Cleanup\" type=\"b\" access=\"read\"/>\n" \
- " </interface>\n"
-
-#define INTROSPECTION \
- DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
- "<node>\n" \
- BUS_UNIT_INTERFACE \
- BUS_SNAPSHOT_INTERFACE \
- BUS_PROPERTIES_INTERFACE \
- BUS_PEER_INTERFACE \
- BUS_INTROSPECTABLE_INTERFACE \
- "</node>\n"
-
-#define INTERFACES_LIST \
- BUS_UNIT_INTERFACES_LIST \
- "org.freedesktop.systemd1.Snapshot\0"
-
-const char bus_snapshot_interface[] _introspect_("Snapshot") = BUS_SNAPSHOT_INTERFACE;
-
-static const BusProperty bus_snapshot_properties[] = {
- { "Cleanup", bus_property_append_bool, "b", offsetof(Snapshot, cleanup) },
- { NULL, }
-};
-
-DBusHandlerResult bus_snapshot_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
- Snapshot *s = SNAPSHOT(u);
- _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
- DBusError error;
-
- dbus_error_init(&error);
-
- if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Snapshot", "Remove")) {
-
- SELINUX_UNIT_ACCESS_CHECK(u, c, message, "stop");
-
- snapshot_remove(SNAPSHOT(u));
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- } else {
- const BusBoundProperties bps[] = {
- { "org.freedesktop.systemd1.Unit", bus_unit_properties, u },
- { "org.freedesktop.systemd1.Snapshot", bus_snapshot_properties, s },
- { NULL, }
- };
-
- SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status");
-
- return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
- }
-
- if (reply) {
- if (!dbus_connection_send(c, reply, NULL))
- goto oom;
- }
-
- return DBUS_HANDLER_RESULT_HANDLED;
-
-oom:
- dbus_error_free(&error);
-
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
-}
diff --git a/src/core/dbus-snapshot.h b/src/core/dbus-snapshot.h
deleted file mode 100644
index 1208aafff6..0000000000
--- a/src/core/dbus-snapshot.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus/dbus.h>
-
-#include "unit.h"
-
-DBusHandlerResult bus_snapshot_message_handler(Unit *u, DBusConnection *c, DBusMessage *message);
-
-extern const char bus_snapshot_interface[];
diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c
deleted file mode 100644
index 095a031612..0000000000
--- a/src/core/dbus-socket.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-
-#include "dbus-unit.h"
-#include "dbus-socket.h"
-#include "dbus-execute.h"
-#include "dbus-kill.h"
-#include "dbus-common.h"
-#include "selinux-access.h"
-
-#define BUS_SOCKET_INTERFACE \
- " <interface name=\"org.freedesktop.systemd1.Socket\">\n" \
- " <property name=\"BindIPv6Only\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"Backlog\" type=\"u\" access=\"read\"/>\n" \
- " <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>\n" \
- BUS_EXEC_COMMAND_INTERFACE("ExecStartPre") \
- BUS_EXEC_COMMAND_INTERFACE("ExecStartPost") \
- BUS_EXEC_COMMAND_INTERFACE("ExecStopPre") \
- BUS_EXEC_COMMAND_INTERFACE("ExecStopPost") \
- BUS_EXEC_CONTEXT_INTERFACE \
- BUS_KILL_CONTEXT_INTERFACE \
- " <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \
- " <property name=\"BindToDevice\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"DirectoryMode\" type=\"u\" access=\"read\"/>\n" \
- " <property name=\"SocketMode\" type=\"u\" access=\"read\"/>\n" \
- " <property name=\"Accept\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"KeepAlive\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"Priority\" type=\"i\" access=\"read\"/>\n" \
- " <property name=\"ReceiveBuffer\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"SendBuffer\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"IPTOS\" type=\"i\" access=\"read\"/>\n" \
- " <property name=\"IPTTL\" type=\"i\" access=\"read\"/>\n" \
- " <property name=\"PipeSize\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"FreeBind\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"Transparent\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"Broadcast\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"PassCredentials\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"PassSecurity\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"Mark\" type=\"i\" access=\"read\"/>\n" \
- " <property name=\"MaxConnections\" type=\"u\" access=\"read\"/>\n" \
- " <property name=\"NAccepted\" type=\"u\" access=\"read\"/>\n" \
- " <property name=\"NConnections\" type=\"u\" access=\"read\"/>\n" \
- " <property name=\"MessageQueueMaxMessages\" type=\"x\" access=\"read\"/>\n" \
- " <property name=\"MessageQueueMessageSize\" type=\"x\" access=\"read\"/>\n" \
- " <property name=\"Result\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"SmackLabel\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"SmackLabelIPIn\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"SmackLabelIPOut\" type=\"s\" access=\"read\"/>\n" \
- " </interface>\n" \
-
-#define INTROSPECTION \
- DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
- "<node>\n" \
- BUS_UNIT_INTERFACE \
- BUS_SOCKET_INTERFACE \
- BUS_PROPERTIES_INTERFACE \
- BUS_PEER_INTERFACE \
- BUS_INTROSPECTABLE_INTERFACE \
- "</node>\n"
-
-#define INTERFACES_LIST \
- BUS_UNIT_INTERFACES_LIST \
- "org.freedesktop.systemd1.Socket\0"
-
-const char bus_socket_interface[] _introspect_("Socket") = BUS_SOCKET_INTERFACE;
-
-const char bus_socket_invalidating_properties[] =
- "ExecStartPre\0"
- "ExecStartPost\0"
- "ExecStopPre\0"
- "ExecStopPost\0"
- "ControlPID\0"
- "NAccepted\0"
- "NConnections\0"
- "Result\0";
-
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_socket_append_bind_ipv6_only, socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_socket_append_socket_result, socket_result, SocketResult);
-
-static const BusProperty bus_socket_properties[] = {
- { "BindIPv6Only", bus_socket_append_bind_ipv6_only, "s", offsetof(Socket, bind_ipv6_only) },
- { "Backlog", bus_property_append_unsigned, "u", offsetof(Socket, backlog) },
- { "TimeoutUSec", bus_property_append_usec, "t", offsetof(Socket, timeout_usec) },
- BUS_EXEC_COMMAND_PROPERTY("ExecStartPre", offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]), true ),
- BUS_EXEC_COMMAND_PROPERTY("ExecStartPost", offsetof(Socket, exec_command[SOCKET_EXEC_START_POST]), true ),
- BUS_EXEC_COMMAND_PROPERTY("ExecStopPre", offsetof(Socket, exec_command[SOCKET_EXEC_STOP_PRE]), true ),
- BUS_EXEC_COMMAND_PROPERTY("ExecStopPost", offsetof(Socket, exec_command[SOCKET_EXEC_STOP_POST]), true ),
- { "ControlPID", bus_property_append_pid, "u", offsetof(Socket, control_pid) },
- { "BindToDevice", bus_property_append_string, "s", offsetof(Socket, bind_to_device), true },
- { "DirectoryMode", bus_property_append_mode, "u", offsetof(Socket, directory_mode) },
- { "SocketMode", bus_property_append_mode, "u", offsetof(Socket, socket_mode) },
- { "Accept", bus_property_append_bool, "b", offsetof(Socket, accept) },
- { "KeepAlive", bus_property_append_bool, "b", offsetof(Socket, keep_alive) },
- { "Priority", bus_property_append_int, "i", offsetof(Socket, priority) },
- { "ReceiveBuffer", bus_property_append_size, "t", offsetof(Socket, receive_buffer) },
- { "SendBuffer", bus_property_append_size, "t", offsetof(Socket, send_buffer) },
- { "IPTOS", bus_property_append_int, "i", offsetof(Socket, ip_tos) },
- { "IPTTL", bus_property_append_int, "i", offsetof(Socket, ip_ttl) },
- { "PipeSize", bus_property_append_size, "t", offsetof(Socket, pipe_size) },
- { "FreeBind", bus_property_append_bool, "b", offsetof(Socket, free_bind) },
- { "Transparent", bus_property_append_bool, "b", offsetof(Socket, transparent) },
- { "Broadcast", bus_property_append_bool, "b", offsetof(Socket, broadcast) },
- { "PassCredentials",bus_property_append_bool, "b", offsetof(Socket, pass_cred) },
- { "PassSecurity", bus_property_append_bool, "b", offsetof(Socket, pass_sec) },
- { "Mark", bus_property_append_int, "i", offsetof(Socket, mark) },
- { "MaxConnections", bus_property_append_unsigned, "u", offsetof(Socket, max_connections) },
- { "NConnections", bus_property_append_unsigned, "u", offsetof(Socket, n_connections) },
- { "NAccepted", bus_property_append_unsigned, "u", offsetof(Socket, n_accepted) },
- { "MessageQueueMaxMessages", bus_property_append_long, "x", offsetof(Socket, mq_maxmsg) },
- { "MessageQueueMessageSize", bus_property_append_long, "x", offsetof(Socket, mq_msgsize) },
- { "Result", bus_socket_append_socket_result, "s", offsetof(Socket, result) },
- { "SmackLabel", bus_property_append_string, "s", offsetof(Socket, smack), true },
- { "SmackLabelIPIn", bus_property_append_string, "s", offsetof(Socket, smack_ip_in), true },
- { "SmackLabelIPOut",bus_property_append_string, "s", offsetof(Socket, smack_ip_out), true },
- { NULL, }
-};
-
-DBusHandlerResult bus_socket_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
- Socket *s = SOCKET(u);
- const BusBoundProperties bps[] = {
- { "org.freedesktop.systemd1.Unit", bus_unit_properties, u },
- { "org.freedesktop.systemd1.Socket", bus_socket_properties, s },
- { "org.freedesktop.systemd1.Socket", bus_exec_context_properties, &s->exec_context },
- { "org.freedesktop.systemd1.Socket", bus_kill_context_properties, &s->kill_context },
- { NULL, }
- };
-
- SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status");
-
- return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
-}
diff --git a/src/core/dbus-socket.h b/src/core/dbus-socket.h
deleted file mode 100644
index 5369b22e5e..0000000000
--- a/src/core/dbus-socket.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You 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/dbus.h>
-
-#include "unit.h"
-
-DBusHandlerResult bus_socket_message_handler(Unit *u, DBusConnection *c, DBusMessage *message);
-
-extern const char bus_socket_interface[];
-extern const char bus_socket_invalidating_properties[];
diff --git a/src/core/dbus-swap.c b/src/core/dbus-swap.c
deleted file mode 100644
index 67ea0f24fe..0000000000
--- a/src/core/dbus-swap.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
- Copyright 2010 Maarten Lankhorst
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-
-#include "dbus-unit.h"
-#include "dbus-swap.h"
-#include "dbus-execute.h"
-#include "dbus-kill.h"
-#include "dbus-common.h"
-#include "selinux-access.h"
-
-#define BUS_SWAP_INTERFACE \
- " <interface name=\"org.freedesktop.systemd1.Swap\">\n" \
- " <property name=\"What\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"Priority\" type=\"i\" access=\"read\"/>\n" \
- " <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>\n" \
- BUS_EXEC_COMMAND_INTERFACE("ExecActivate") \
- BUS_EXEC_COMMAND_INTERFACE("ExecDeactivate") \
- BUS_EXEC_CONTEXT_INTERFACE \
- BUS_KILL_CONTEXT_INTERFACE \
- " <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \
- " <property name=\"Result\" type=\"s\" access=\"read\"/>\n" \
- " </interface>\n"
-
-#define INTROSPECTION \
- DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
- "<node>\n" \
- BUS_UNIT_INTERFACE \
- BUS_SWAP_INTERFACE \
- BUS_PROPERTIES_INTERFACE \
- BUS_PEER_INTERFACE \
- BUS_INTROSPECTABLE_INTERFACE \
- "</node>\n"
-
-#define INTERFACES_LIST \
- BUS_UNIT_INTERFACES_LIST \
- "org.freedesktop.systemd1.Swap\0"
-
-const char bus_swap_interface[] _introspect_("Swap") = BUS_SWAP_INTERFACE;
-
-const char bus_swap_invalidating_properties[] =
- "What\0"
- "Priority\0"
- "ExecActivate\0"
- "ExecDeactivate\0"
- "ControlPID\0"
- "Result\0";
-
-static int bus_swap_append_priority(DBusMessageIter *i, const char *property, void *data) {
- Swap *s = data;
- dbus_int32_t j;
-
- assert(i);
- assert(property);
- assert(s);
-
- if (s->from_proc_swaps)
- j = s->parameters_proc_swaps.priority;
- else if (s->from_fragment)
- j = s->parameters_fragment.priority;
- else
- j = -1;
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_INT32, &j))
- return -ENOMEM;
-
- return 0;
-}
-
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_swap_append_swap_result, swap_result, SwapResult);
-
-static const BusProperty bus_swap_properties[] = {
- { "What", bus_property_append_string, "s", offsetof(Swap, what), true },
- { "Priority", bus_swap_append_priority, "i", 0 },
- BUS_EXEC_COMMAND_PROPERTY("ExecActivate", offsetof(Swap, exec_command[SWAP_EXEC_ACTIVATE]), false),
- BUS_EXEC_COMMAND_PROPERTY("ExecDeactivate", offsetof(Swap, exec_command[SWAP_EXEC_DEACTIVATE]), false),
- { "ControlPID", bus_property_append_pid, "u", offsetof(Swap, control_pid) },
- { "Result", bus_swap_append_swap_result,"s", offsetof(Swap, result) },
- { NULL, }
-};
-
-DBusHandlerResult bus_swap_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
- Swap *s = SWAP(u);
- const BusBoundProperties bps[] = {
- { "org.freedesktop.systemd1.Unit", bus_unit_properties, u },
- { "org.freedesktop.systemd1.Swap", bus_swap_properties, s },
- { "org.freedesktop.systemd1.Swap", bus_exec_context_properties, &s->exec_context },
- { "org.freedesktop.systemd1.Swap", bus_kill_context_properties, &s->kill_context },
- { NULL, }
- };
-
- SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status");
-
- return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
-}
diff --git a/src/core/dbus-swap.h b/src/core/dbus-swap.h
deleted file mode 100644
index 41fe4447ff..0000000000
--- a/src/core/dbus-swap.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
- 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 <dbus/dbus.h>
-
-#include "unit.h"
-
-DBusHandlerResult bus_swap_message_handler(Unit *u, DBusConnection *c, DBusMessage *message);
-
-extern const char bus_swap_interface[];
-extern const char bus_swap_invalidating_properties[];
diff --git a/src/core/dbus-target.c b/src/core/dbus-target.c
deleted file mode 100644
index 6a775506cc..0000000000
--- a/src/core/dbus-target.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-
-#include "dbus-unit.h"
-#include "dbus-target.h"
-#include "dbus-common.h"
-#include "selinux-access.h"
-
-#define BUS_TARGET_INTERFACE \
- " <interface name=\"org.freedesktop.systemd1.Target\">\n" \
- " </interface>\n"
-
-#define INTROSPECTION \
- DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
- "<node>\n" \
- BUS_UNIT_INTERFACE \
- BUS_TARGET_INTERFACE \
- BUS_PROPERTIES_INTERFACE \
- BUS_PEER_INTERFACE \
- BUS_INTROSPECTABLE_INTERFACE \
- "</node>\n"
-
-#define INTERFACES_LIST \
- BUS_UNIT_INTERFACES_LIST \
- "org.freedesktop.systemd1.Target\0"
-
-const char bus_target_interface[] _introspect_("Target") = BUS_TARGET_INTERFACE;
-
-DBusHandlerResult bus_target_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
- const BusBoundProperties bps[] = {
- { "org.freedesktop.systemd1.Unit", bus_unit_properties, u },
- { NULL, }
- };
-
- SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status");
-
- return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
-}
diff --git a/src/core/dbus-target.h b/src/core/dbus-target.h
deleted file mode 100644
index a8a0304c75..0000000000
--- a/src/core/dbus-target.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus/dbus.h>
-
-#include "unit.h"
-
-DBusHandlerResult bus_target_message_handler(Unit *u, DBusConnection *c, DBusMessage *message);
-
-extern const char bus_target_interface[];
diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c
deleted file mode 100644
index 84b823c9a4..0000000000
--- a/src/core/dbus-timer.c
+++ /dev/null
@@ -1,140 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-
-#include "dbus-unit.h"
-#include "dbus-timer.h"
-#include "dbus-execute.h"
-#include "dbus-common.h"
-#include "selinux-access.h"
-
-#define BUS_TIMER_INTERFACE \
- " <interface name=\"org.freedesktop.systemd1.Timer\">\n" \
- " <property name=\"Unit\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"Timers\" type=\"a(stt)\" access=\"read\"/>\n" \
- " <property name=\"NextElapseUSec\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"Result\" type=\"s\" access=\"read\"/>\n" \
- " </interface>\n"
-
-#define INTROSPECTION \
- DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
- "<node>\n" \
- BUS_UNIT_INTERFACE \
- BUS_TIMER_INTERFACE \
- BUS_PROPERTIES_INTERFACE \
- BUS_PEER_INTERFACE \
- BUS_INTROSPECTABLE_INTERFACE \
- "</node>\n"
-
-#define INTERFACES_LIST \
- BUS_UNIT_INTERFACES_LIST \
- "org.freedesktop.systemd1.Timer\0"
-
-const char bus_timer_interface[] _introspect_("Timer") = BUS_TIMER_INTERFACE;
-
-const char bus_timer_invalidating_properties[] =
- "Timers\0"
- "NextElapseUSec\0"
- "Result\0";
-
-static int bus_timer_append_timers(DBusMessageIter *i, const char *property, void *data) {
- Timer *p = data;
- DBusMessageIter sub, sub2;
- TimerValue *k;
-
- assert(i);
- assert(property);
- assert(p);
-
- if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(stt)", &sub))
- return -ENOMEM;
-
- LIST_FOREACH(value, k, p->values) {
- char *buf;
- const char *t;
- size_t l;
- bool b;
-
- t = timer_base_to_string(k->base);
- assert(endswith(t, "Sec"));
-
- /* s/Sec/USec/ */
- l = strlen(t);
- if (!(buf = new(char, l+2)))
- return -ENOMEM;
-
- memcpy(buf, t, l-3);
- memcpy(buf+l-3, "USec", 5);
-
- b = dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) &&
- dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &buf) &&
- dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &k->value) &&
- dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT64, &k->next_elapse) &&
- dbus_message_iter_close_container(&sub, &sub2);
-
- free(buf);
- if (!b)
- return -ENOMEM;
- }
-
- if (!dbus_message_iter_close_container(i, &sub))
- return -ENOMEM;
-
- return 0;
-}
-
-static int bus_timer_append_unit(DBusMessageIter *i, const char *property, void *data) {
- Unit *u = data;
- Timer *timer = TIMER(u);
- const char *t;
-
- assert(i);
- assert(property);
- assert(u);
-
- t = UNIT_DEREF(timer->unit) ? UNIT_DEREF(timer->unit)->id : "";
-
- return dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t) ? 0 : -ENOMEM;
-}
-
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_timer_append_timer_result, timer_result, TimerResult);
-
-static const BusProperty bus_timer_properties[] = {
- { "Unit", bus_timer_append_unit, "s", 0 },
- { "Timers", bus_timer_append_timers, "a(stt)", 0 },
- { "NextElapseUSec", bus_property_append_usec, "t", offsetof(Timer, next_elapse) },
- { "Result", bus_timer_append_timer_result,"s", offsetof(Timer, result) },
- { NULL, }
-};
-
-DBusHandlerResult bus_timer_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
- Timer *t = TIMER(u);
- const BusBoundProperties bps[] = {
- { "org.freedesktop.systemd1.Unit", bus_unit_properties, u },
- { "org.freedesktop.systemd1.Timer", bus_timer_properties, t },
- { NULL, }
- };
-
- SELINUX_UNIT_ACCESS_CHECK(u, c, message, "status");
-
- return bus_default_message_handler(c, message, INTROSPECTION, INTERFACES_LIST, bps);
-}
diff --git a/src/core/dbus-timer.h b/src/core/dbus-timer.h
deleted file mode 100644
index 9ac30501d1..0000000000
--- a/src/core/dbus-timer.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You 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/dbus.h>
-
-#include "unit.h"
-
-DBusHandlerResult bus_timer_message_handler(Unit *u, DBusConnection *c, DBusMessage *message);
-
-extern const char bus_timer_interface[];
-extern const char bus_timer_invalidating_properties[];
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
deleted file mode 100644
index 83ee018ff3..0000000000
--- a/src/core/dbus-unit.c
+++ /dev/null
@@ -1,887 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-
-#include "dbus.h"
-#include "log.h"
-#include "dbus-unit.h"
-#include "bus-errors.h"
-#include "dbus-common.h"
-#include "selinux-access.h"
-
-const char bus_unit_interface[] _introspect_("Unit") = BUS_UNIT_INTERFACE;
-
-#define INVALIDATING_PROPERTIES \
- "LoadState\0" \
- "ActiveState\0" \
- "SubState\0" \
- "InactiveExitTimestamp\0" \
- "ActiveEnterTimestamp\0" \
- "ActiveExitTimestamp\0" \
- "InactiveEnterTimestamp\0" \
- "Job\0" \
- "NeedDaemonReload\0"
-
-static int bus_unit_append_names(DBusMessageIter *i, const char *property, void *data) {
- char *t;
- Iterator j;
- DBusMessageIter sub;
- Unit *u = data;
-
- if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub))
- return -ENOMEM;
-
- SET_FOREACH(t, u->names, j)
- if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &t))
- return -ENOMEM;
-
- if (!dbus_message_iter_close_container(i, &sub))
- return -ENOMEM;
-
- return 0;
-}
-
-static int bus_unit_append_following(DBusMessageIter *i, const char *property, void *data) {
- Unit *u = data, *f;
- const char *d;
-
- assert(i);
- assert(property);
- assert(u);
-
- f = unit_following(u);
- d = f ? f->id : "";
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d))
- return -ENOMEM;
-
- return 0;
-}
-
-static int bus_unit_append_dependencies(DBusMessageIter *i, const char *property, void *data) {
- Unit *u;
- Iterator j;
- DBusMessageIter sub;
- Set *s = data;
-
- if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub))
- return -ENOMEM;
-
- SET_FOREACH(u, s, j)
- if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &u->id))
- return -ENOMEM;
-
- if (!dbus_message_iter_close_container(i, &sub))
- return -ENOMEM;
-
- return 0;
-}
-
-static int bus_unit_append_description(DBusMessageIter *i, const char *property, void *data) {
- Unit *u = data;
- const char *d;
-
- assert(i);
- assert(property);
- assert(u);
-
- d = unit_description(u);
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &d))
- return -ENOMEM;
-
- return 0;
-}
-
-static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_unit_append_load_state, unit_load_state, UnitLoadState);
-
-static int bus_unit_append_active_state(DBusMessageIter *i, const char *property, void *data) {
- Unit *u = data;
- const char *state;
-
- assert(i);
- assert(property);
- assert(u);
-
- state = unit_active_state_to_string(unit_active_state(u));
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
- return -ENOMEM;
-
- return 0;
-}
-
-static int bus_unit_append_sub_state(DBusMessageIter *i, const char *property, void *data) {
- Unit *u = data;
- const char *state;
-
- assert(i);
- assert(property);
- assert(u);
-
- state = unit_sub_state_to_string(u);
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
- return -ENOMEM;
-
- return 0;
-}
-
-static int bus_unit_append_file_state(DBusMessageIter *i, const char *property, void *data) {
- Unit *u = data;
- const char *state;
-
- assert(i);
- assert(property);
- assert(u);
-
- state = strempty(unit_file_state_to_string(unit_get_unit_file_state(u)));
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &state))
- return -ENOMEM;
-
- return 0;
-}
-
-static int bus_unit_append_can_start(DBusMessageIter *i, const char *property, void *data) {
- Unit *u = data;
- dbus_bool_t b;
-
- assert(i);
- assert(property);
- assert(u);
-
- b = unit_can_start(u) &&
- !u->refuse_manual_start;
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
- return -ENOMEM;
-
- return 0;
-}
-
-static int bus_unit_append_can_stop(DBusMessageIter *i, const char *property, void *data) {
- Unit *u = data;
- dbus_bool_t b;
-
- assert(i);
- assert(property);
- assert(u);
-
- /* On the lower levels we assume that every unit we can start
- * we can also stop */
-
- b = unit_can_start(u) &&
- !u->refuse_manual_stop;
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
- return -ENOMEM;
-
- return 0;
-}
-
-static int bus_unit_append_can_reload(DBusMessageIter *i, const char *property, void *data) {
- Unit *u = data;
- dbus_bool_t b;
-
- assert(i);
- assert(property);
- assert(u);
-
- b = unit_can_reload(u);
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
- return -ENOMEM;
-
- return 0;
-}
-
-static int bus_unit_append_can_isolate(DBusMessageIter *i, const char *property, void *data) {
- Unit *u = data;
- dbus_bool_t b;
-
- assert(i);
- assert(property);
- assert(u);
-
- b = unit_can_isolate(u) &&
- !u->refuse_manual_start;
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
- return -ENOMEM;
-
- return 0;
-}
-
-static int bus_unit_append_job(DBusMessageIter *i, const char *property, void *data) {
- Unit *u = data;
- DBusMessageIter sub;
- char *p;
-
- assert(i);
- assert(property);
- assert(u);
-
- if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub))
- return -ENOMEM;
-
- if (u->job) {
-
- if (!(p = job_dbus_path(u->job)))
- return -ENOMEM;
-
- if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &u->job->id) ||
- !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
- free(p);
- return -ENOMEM;
- }
- } else {
- uint32_t id = 0;
-
- /* No job, so let's fill in some placeholder
- * data. Since we need to fill in a valid path we
- * simple point to ourselves. */
-
- if (!(p = unit_dbus_path(u)))
- return -ENOMEM;
-
- if (!dbus_message_iter_append_basic(&sub, DBUS_TYPE_UINT32, &id) ||
- !dbus_message_iter_append_basic(&sub, DBUS_TYPE_OBJECT_PATH, &p)) {
- free(p);
- return -ENOMEM;
- }
- }
-
- free(p);
-
- if (!dbus_message_iter_close_container(i, &sub))
- return -ENOMEM;
-
- return 0;
-}
-
-static int bus_unit_append_default_cgroup(DBusMessageIter *i, const char *property, void *data) {
- Unit *u = data;
- char *t;
- CGroupBonding *cgb;
- bool success;
-
- assert(i);
- assert(property);
- assert(u);
-
- if ((cgb = unit_get_default_cgroup(u))) {
- if (!(t = cgroup_bonding_to_string(cgb)))
- return -ENOMEM;
- } else
- t = (char*) "";
-
- success = dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t);
-
- if (cgb)
- free(t);
-
- return success ? 0 : -ENOMEM;
-}
-
-static int bus_unit_append_cgroups(DBusMessageIter *i, const char *property, void *data) {
- Unit *u = data;
- CGroupBonding *cgb;
- DBusMessageIter sub;
-
- if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "s", &sub))
- return -ENOMEM;
-
- LIST_FOREACH(by_unit, cgb, u->cgroup_bondings) {
- char *t;
- bool success;
-
- if (!(t = cgroup_bonding_to_string(cgb)))
- return -ENOMEM;
-
- success = dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &t);
- free(t);
-
- if (!success)
- return -ENOMEM;
- }
-
- if (!dbus_message_iter_close_container(i, &sub))
- return -ENOMEM;
-
- return 0;
-}
-
-static int bus_unit_append_cgroup_attrs(DBusMessageIter *i, const char *property, void *data) {
- Unit *u = data;
- CGroupAttribute *a;
- DBusMessageIter sub, sub2;
-
- if (!dbus_message_iter_open_container(i, DBUS_TYPE_ARRAY, "(sss)", &sub))
- return -ENOMEM;
-
- LIST_FOREACH(by_unit, a, u->cgroup_attributes) {
- char *v = NULL;
- bool success;
-
- if (a->map_callback)
- a->map_callback(a->controller, a->name, a->value, &v);
-
- success =
- dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) &&
- dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &a->controller) &&
- dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &a->name) &&
- dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, v ? &v : &a->value) &&
- dbus_message_iter_close_container(&sub, &sub2);
-
- free(v);
-
- if (!success)
- return -ENOMEM;
- }
-
- if (!dbus_message_iter_close_container(i, &sub))
- return -ENOMEM;
-
- return 0;
-}
-
-static int bus_unit_append_need_daemon_reload(DBusMessageIter *i, const char *property, void *data) {
- Unit *u = data;
- dbus_bool_t b;
-
- assert(i);
- assert(property);
- assert(u);
-
- b = unit_need_daemon_reload(u);
-
- if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
- return -ENOMEM;
-
- return 0;
-}
-
-static int bus_unit_append_load_error(DBusMessageIter *i, const char *property, void *data) {
- Unit *u = data;
- const char *name, *message;
- DBusMessageIter sub;
-
- assert(i);
- assert(property);
- assert(u);
-
- if (u->load_error != 0) {
- name = bus_errno_to_dbus(u->load_error);
- message = strempty(strerror(-u->load_error));
- } else
- name = message = "";
-
- if (!dbus_message_iter_open_container(i, DBUS_TYPE_STRUCT, NULL, &sub) ||
- !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &name) ||
- !dbus_message_iter_append_basic(&sub, DBUS_TYPE_STRING, &message) ||
- !dbus_message_iter_close_container(i, &sub))
- return -ENOMEM;
-
- return 0;
-}
-
-static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *connection, DBusMessage *message) {
- _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
- DBusError error;
- JobType job_type = _JOB_TYPE_INVALID;
- bool reload_if_possible = false;
- int r;
-
- dbus_error_init(&error);
-
- if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Start"))
- job_type = JOB_START;
- else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Stop"))
- job_type = JOB_STOP;
- else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Reload"))
- job_type = JOB_RELOAD;
- else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Restart"))
- job_type = JOB_RESTART;
- else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "TryRestart"))
- job_type = JOB_TRY_RESTART;
- else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "ReloadOrRestart")) {
- reload_if_possible = true;
- job_type = JOB_RESTART;
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "ReloadOrTryRestart")) {
- reload_if_possible = true;
- job_type = JOB_TRY_RESTART;
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "Kill")) {
- const char *swho;
- int32_t signo;
- KillWho who;
-
- if (!dbus_message_get_args(
- message,
- &error,
- DBUS_TYPE_STRING, &swho,
- DBUS_TYPE_INT32, &signo,
- DBUS_TYPE_INVALID))
- return bus_send_error_reply(connection, message, &error, -EINVAL);
-
- if (isempty(swho))
- who = KILL_ALL;
- else {
- who = kill_who_from_string(swho);
- if (who < 0)
- return bus_send_error_reply(connection, message, &error, -EINVAL);
- }
-
- if (signo <= 0 || signo >= _NSIG)
- return bus_send_error_reply(connection, message, &error, -EINVAL);
-
- SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
-
- r = unit_kill(u, who, signo, &error);
- if (r < 0)
- return bus_send_error_reply(connection, message, &error, r);
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Unit", "ResetFailed")) {
-
- SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "reload");
-
- unit_reset_failed(u);
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- } else if (UNIT_VTABLE(u)->bus_message_handler)
- return UNIT_VTABLE(u)->bus_message_handler(u, connection, message);
- else
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
- if (job_type != _JOB_TYPE_INVALID) {
- const char *smode;
- JobMode mode;
-
- if (!dbus_message_get_args(
- message,
- &error,
- DBUS_TYPE_STRING, &smode,
- DBUS_TYPE_INVALID))
- return bus_send_error_reply(connection, message, &error, -EINVAL);
-
- mode = job_mode_from_string(smode);
- if (mode < 0) {
- dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
- return bus_send_error_reply(connection, message, &error, -EINVAL);
- }
-
- return bus_unit_queue_job(connection, message, u, job_type, mode, reload_if_possible);
- }
-
- if (reply)
- if (!dbus_connection_send(connection, reply, NULL))
- goto oom;
-
- return DBUS_HANDLER_RESULT_HANDLED;
-
-oom:
- dbus_error_free(&error);
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
-}
-
-static DBusHandlerResult bus_unit_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
- Manager *m = data;
- Unit *u;
- int r;
- _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
- DBusError error;
-
- assert(connection);
- assert(message);
- assert(m);
-
- dbus_error_init(&error);
-
- if (streq(dbus_message_get_path(message), "/org/freedesktop/systemd1/unit")) {
- /* Be nice to gdbus and return introspection data for our mid-level paths */
-
- SELINUX_ACCESS_CHECK(connection, message, "status");
-
- if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
- char *introspection = NULL;
- FILE *f;
- Iterator i;
- const char *k;
- size_t size;
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- /* We roll our own introspection code here, instead of
- * relying on bus_default_message_handler() because we
- * need to generate our introspection string
- * dynamically. */
-
- f = open_memstream(&introspection, &size);
- if (!f)
- goto oom;
-
- fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
- "<node>\n", f);
-
- fputs(BUS_INTROSPECTABLE_INTERFACE, f);
- fputs(BUS_PEER_INTERFACE, f);
-
- HASHMAP_FOREACH_KEY(u, k, m->units, i) {
- char *p;
-
- if (k != u->id)
- continue;
-
- p = bus_path_escape(k);
- if (!p) {
- fclose(f);
- free(introspection);
- goto oom;
- }
-
- fprintf(f, "<node name=\"%s\"/>", p);
- free(p);
- }
-
- fputs("</node>\n", f);
-
- if (ferror(f)) {
- fclose(f);
- free(introspection);
- goto oom;
- }
-
- fclose(f);
-
- if (!introspection)
- goto oom;
-
- if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
- free(introspection);
- goto oom;
- }
-
- free(introspection);
-
- if (!dbus_connection_send(connection, reply, NULL))
- goto oom;
-
- return DBUS_HANDLER_RESULT_HANDLED;
- }
-
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- }
-
- r = manager_load_unit_from_dbus_path(m, dbus_message_get_path(message), &error, &u);
- if (r == -ENOMEM)
- goto oom;
- if (r < 0)
- return bus_send_error_reply(connection, message, &error, r);
-
- return bus_unit_message_dispatch(u, connection, message);
-
-oom:
- dbus_error_free(&error);
-
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
-}
-
-const DBusObjectPathVTable bus_unit_vtable = {
- .message_function = bus_unit_message_handler
-};
-
-void bus_unit_send_change_signal(Unit *u) {
- char *p = NULL;
- DBusMessage *m = NULL;
-
- assert(u);
-
- if (u->in_dbus_queue) {
- LIST_REMOVE(Unit, dbus_queue, u->manager->dbus_unit_queue, u);
- u->in_dbus_queue = false;
- }
-
- if (!u->id)
- return;
-
- if (!bus_has_subscriber(u->manager)) {
- u->sent_dbus_new_signal = true;
- return;
- }
-
- if (!(p = unit_dbus_path(u)))
- goto oom;
-
- if (u->sent_dbus_new_signal) {
- /* 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. */
-
- if (UNIT_VTABLE(u)->bus_invalidating_properties) {
-
- if (!(m = bus_properties_changed_new(p,
- UNIT_VTABLE(u)->bus_interface,
- UNIT_VTABLE(u)->bus_invalidating_properties)))
- goto oom;
-
- if (bus_broadcast(u->manager, m) < 0)
- goto oom;
-
- dbus_message_unref(m);
- }
-
- if (!(m = bus_properties_changed_new(p, "org.freedesktop.systemd1.Unit", INVALIDATING_PROPERTIES)))
- goto oom;
-
- } else {
- /* Send a new signal */
-
- if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitNew")))
- goto oom;
-
- if (!dbus_message_append_args(m,
- DBUS_TYPE_STRING, &u->id,
- DBUS_TYPE_OBJECT_PATH, &p,
- DBUS_TYPE_INVALID))
- goto oom;
- }
-
- if (bus_broadcast(u->manager, m) < 0)
- goto oom;
-
- free(p);
- dbus_message_unref(m);
-
- u->sent_dbus_new_signal = true;
-
- return;
-
-oom:
- free(p);
-
- if (m)
- dbus_message_unref(m);
-
- log_error("Failed to allocate unit change/new signal.");
-}
-
-void bus_unit_send_removed_signal(Unit *u) {
- char *p = NULL;
- DBusMessage *m = NULL;
-
- assert(u);
-
- if (!bus_has_subscriber(u->manager))
- return;
-
- if (!u->sent_dbus_new_signal)
- bus_unit_send_change_signal(u);
-
- if (!u->id)
- return;
-
- if (!(p = unit_dbus_path(u)))
- goto oom;
-
- if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitRemoved")))
- goto oom;
-
- if (!dbus_message_append_args(m,
- DBUS_TYPE_STRING, &u->id,
- DBUS_TYPE_OBJECT_PATH, &p,
- DBUS_TYPE_INVALID))
- goto oom;
-
- if (bus_broadcast(u->manager, m) < 0)
- goto oom;
-
- free(p);
- dbus_message_unref(m);
-
- return;
-
-oom:
- free(p);
-
- if (m)
- dbus_message_unref(m);
-
- log_error("Failed to allocate unit remove signal.");
-}
-
-DBusHandlerResult bus_unit_queue_job(
- DBusConnection *connection,
- DBusMessage *message,
- Unit *u,
- JobType type,
- JobMode mode,
- bool reload_if_possible) {
-
- _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
- _cleanup_free_ char *path = NULL;
- Job *j;
- JobBusClient *cl;
- DBusError error;
- int r;
-
- assert(connection);
- assert(message);
- assert(u);
- assert(type >= 0 && type < _JOB_TYPE_MAX);
- assert(mode >= 0 && mode < _JOB_MODE_MAX);
-
- dbus_error_init(&error);
-
- if (reload_if_possible && unit_can_reload(u)) {
- if (type == JOB_RESTART)
- type = JOB_RELOAD_OR_START;
- else if (type == JOB_TRY_RESTART)
- type = JOB_RELOAD;
- }
-
- SELINUX_UNIT_ACCESS_CHECK(u, connection, message,
- (type == JOB_START || type == JOB_RESTART || type == JOB_TRY_RESTART) ? "start" :
- type == JOB_STOP ? "stop" : "reload");
-
- if (type == JOB_STOP && u->load_state == UNIT_ERROR && unit_active_state(u) == UNIT_INACTIVE) {
- dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id);
- return bus_send_error_reply(connection, message, &error, -EPERM);
- }
-
- 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))) {
- dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id);
- return bus_send_error_reply(connection, message, &error, -EPERM);
- }
-
- r = manager_add_job(u->manager, type, u, mode, true, &error, &j);
- if (r < 0)
- return bus_send_error_reply(connection, message, &error, r);
-
- cl = job_bus_client_new(connection, bus_message_get_sender_with_fallback(message));
- if (!cl)
- goto oom;
-
- LIST_PREPEND(JobBusClient, client, j->bus_client_list, cl);
-
- reply = dbus_message_new_method_return(message);
- if (!reply)
- goto oom;
-
- path = job_dbus_path(j);
- if (!path)
- goto oom;
-
- if (!dbus_message_append_args(
- reply,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID))
- goto oom;
-
- if (!dbus_connection_send(connection, reply, NULL))
- goto oom;
-
- return DBUS_HANDLER_RESULT_HANDLED;
-
-oom:
- dbus_error_free(&error);
-
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
-}
-
-const BusProperty bus_unit_properties[] = {
- { "Id", bus_property_append_string, "s", offsetof(Unit, id), true },
- { "Names", bus_unit_append_names, "as", 0 },
- { "Following", bus_unit_append_following, "s", 0 },
- { "Requires", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_REQUIRES]), true },
- { "RequiresOverridable", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]), true },
- { "Requisite", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_REQUISITE]), true },
- { "RequisiteOverridable", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]), true },
- { "Wants", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_WANTS]), true },
- { "BindsTo", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_BINDS_TO]), true },
- { "PartOf", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_PART_OF]), true },
- { "RequiredBy", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), true },
- { "RequiredByOverridable",bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), true },
- { "WantedBy", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_WANTED_BY]), true },
- { "BoundBy", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_BOUND_BY]), true },
- { "ConsistsOf", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), true },
- { "Conflicts", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_CONFLICTS]), true },
- { "ConflictedBy", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]), true },
- { "Before", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_BEFORE]), true },
- { "After", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_AFTER]), true },
- { "OnFailure", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_ON_FAILURE]), true },
- { "Triggers", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_TRIGGERS]), true },
- { "TriggeredBy", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), true },
- { "PropagatesReloadTo", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), true },
- { "ReloadPropagatedFrom", bus_unit_append_dependencies, "as", offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), true },
- { "RequiresMountsFor", bus_property_append_strv, "as", offsetof(Unit, requires_mounts_for), true },
- { "Documentation", bus_property_append_strv, "as", offsetof(Unit, documentation), true },
- { "Description", bus_unit_append_description, "s", 0 },
- { "LoadState", bus_unit_append_load_state, "s", offsetof(Unit, load_state) },
- { "ActiveState", bus_unit_append_active_state, "s", 0 },
- { "SubState", bus_unit_append_sub_state, "s", 0 },
- { "FragmentPath", bus_property_append_string, "s", offsetof(Unit, fragment_path), true },
- { "SourcePath", bus_property_append_string, "s", offsetof(Unit, source_path), true },
- { "UnitFileState", bus_unit_append_file_state, "s", 0 },
- { "InactiveExitTimestamp",bus_property_append_usec, "t", offsetof(Unit, inactive_exit_timestamp.realtime) },
- { "InactiveExitTimestampMonotonic", bus_property_append_usec, "t", offsetof(Unit, inactive_exit_timestamp.monotonic) },
- { "ActiveEnterTimestamp", bus_property_append_usec, "t", offsetof(Unit, active_enter_timestamp.realtime) },
- { "ActiveEnterTimestampMonotonic", bus_property_append_usec, "t", offsetof(Unit, active_enter_timestamp.monotonic) },
- { "ActiveExitTimestamp", bus_property_append_usec, "t", offsetof(Unit, active_exit_timestamp.realtime) },
- { "ActiveExitTimestampMonotonic", bus_property_append_usec, "t", offsetof(Unit, active_exit_timestamp.monotonic) },
- { "InactiveEnterTimestamp", bus_property_append_usec, "t", offsetof(Unit, inactive_enter_timestamp.realtime) },
- { "InactiveEnterTimestampMonotonic",bus_property_append_usec, "t", offsetof(Unit, inactive_enter_timestamp.monotonic) },
- { "CanStart", bus_unit_append_can_start, "b", 0 },
- { "CanStop", bus_unit_append_can_stop, "b", 0 },
- { "CanReload", bus_unit_append_can_reload, "b", 0 },
- { "CanIsolate", bus_unit_append_can_isolate, "b", 0 },
- { "Job", bus_unit_append_job, "(uo)", 0 },
- { "StopWhenUnneeded", bus_property_append_bool, "b", offsetof(Unit, stop_when_unneeded) },
- { "RefuseManualStart", bus_property_append_bool, "b", offsetof(Unit, refuse_manual_start) },
- { "RefuseManualStop", bus_property_append_bool, "b", offsetof(Unit, refuse_manual_stop) },
- { "AllowIsolate", bus_property_append_bool, "b", offsetof(Unit, allow_isolate) },
- { "DefaultDependencies", bus_property_append_bool, "b", offsetof(Unit, default_dependencies) },
- { "OnFailureIsolate", bus_property_append_bool, "b", offsetof(Unit, on_failure_isolate) },
- { "IgnoreOnIsolate", bus_property_append_bool, "b", offsetof(Unit, ignore_on_isolate) },
- { "IgnoreOnSnapshot", bus_property_append_bool, "b", offsetof(Unit, ignore_on_snapshot) },
- { "DefaultControlGroup", bus_unit_append_default_cgroup, "s", 0 },
- { "ControlGroup", bus_unit_append_cgroups, "as", 0 },
- { "ControlGroupAttributes", bus_unit_append_cgroup_attrs,"a(sss)", 0 },
- { "NeedDaemonReload", bus_unit_append_need_daemon_reload, "b", 0 },
- { "JobTimeoutUSec", bus_property_append_usec, "t", offsetof(Unit, job_timeout) },
- { "ConditionTimestamp", bus_property_append_usec, "t", offsetof(Unit, condition_timestamp.realtime) },
- { "ConditionTimestampMonotonic", bus_property_append_usec, "t", offsetof(Unit, condition_timestamp.monotonic) },
- { "ConditionResult", bus_property_append_bool, "b", offsetof(Unit, condition_result) },
- { "LoadError", bus_unit_append_load_error, "(ss)", 0 },
- { NULL, }
-};
diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h
deleted file mode 100644
index ac6785a949..0000000000
--- a/src/core/dbus-unit.h
+++ /dev/null
@@ -1,147 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus/dbus.h>
-
-#include "manager.h"
-#include "dbus-common.h"
-
-#define BUS_UNIT_INTERFACE \
- " <interface name=\"org.freedesktop.systemd1.Unit\">\n" \
- " <method name=\"Start\">\n" \
- " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"Stop\">\n" \
- " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"Reload\">\n" \
- " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"Restart\">\n" \
- " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"TryRestart\">\n" \
- " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"ReloadOrRestart\">\n" \
- " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"ReloadOrTryRestart\">\n" \
- " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
- " </method>\n" \
- " <method name=\"Kill\">\n" \
- " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
- " <arg name=\"signal\" type=\"i\" direction=\"in\"/>\n" \
- " </method>\n" \
- " <method name=\"ResetFailed\"/>\n" \
- " <property name=\"Id\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"Names\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"Following\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"Requires\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"RequiresOverridable\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"Requisite\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"RequisiteOverridable\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"Wants\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"BindsTo\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"RequiredBy\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"RequiredByOverridable\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"WantedBy\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"BoundBy\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"Conflicts\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"ConflictedBy\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"Before\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"After\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"OnFailure\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"Triggers\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"TriggeredBy\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"PropagatesReloadTo\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"ReloadPropagatedFrom\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"RequiresMountsFor\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"Description\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"SourcePath\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"Documentation\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"LoadState\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"ActiveState\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"SubState\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"FragmentPath\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"UnitFileState\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"InactiveExitTimestamp\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"InactiveExitTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"ActiveEnterTimestamp\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"ActiveEnterTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"ActiveExitTimestamp\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"ActiveExitTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"InactiveEnterTimestamp\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"InactiveEnterTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"CanStart\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"CanStop\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"CanReload\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"CanIsolate\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"Job\" type=\"(uo)\" access=\"read\"/>\n" \
- " <property name=\"StopWhenUnneeded\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"RefuseManualStart\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"RefuseManualStop\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"AllowIsolate\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"DefaultDependencies\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"OnFailureIsolate\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"IgnoreOnIsolate\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"IgnoreOnSnapshot\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"DefaultControlGroup\" type=\"s\" access=\"read\"/>\n" \
- " <property name=\"ControlGroup\" type=\"as\" access=\"read\"/>\n" \
- " <property name=\"ControlGroupAttributes\" type=\"a(sss)\" access=\"read\"/>\n" \
- " <property name=\"NeedDaemonReload\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"JobTimeoutUSec\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"ConditionTimestamp\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"ConditionTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
- " <property name=\"ConditionResult\" type=\"b\" access=\"read\"/>\n" \
- " <property name=\"LoadError\" type=\"(ss)\" access=\"read\"/>\n" \
- " </interface>\n"
-
-#define BUS_UNIT_INTERFACES_LIST \
- BUS_GENERIC_INTERFACES_LIST \
- "org.freedesktop.systemd1.Unit\0"
-
-extern const BusProperty bus_unit_properties[];
-
-void bus_unit_send_change_signal(Unit *u);
-void bus_unit_send_removed_signal(Unit *u);
-
-
-DBusHandlerResult bus_unit_queue_job(
- DBusConnection *connection,
- DBusMessage *message,
- Unit *u,
- JobType type,
- JobMode mode,
- bool reload_if_possible);
-
-extern const DBusObjectPathVTable bus_unit_vtable;
-
-extern const char bus_unit_interface[];
diff --git a/src/core/dbus.c b/src/core/dbus.c
deleted file mode 100644
index 2a1c66054a..0000000000
--- a/src/core/dbus.c
+++ /dev/null
@@ -1,1479 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/epoll.h>
-#include <sys/timerfd.h>
-#include <errno.h>
-#include <unistd.h>
-#include <dbus/dbus.h>
-
-#include "dbus.h"
-#include "log.h"
-#include "strv.h"
-#include "cgroup.h"
-#include "mkdir.h"
-#include "missing.h"
-#include "dbus-unit.h"
-#include "dbus-job.h"
-#include "dbus-manager.h"
-#include "dbus-service.h"
-#include "dbus-socket.h"
-#include "dbus-target.h"
-#include "dbus-device.h"
-#include "dbus-mount.h"
-#include "dbus-automount.h"
-#include "dbus-snapshot.h"
-#include "dbus-swap.h"
-#include "dbus-timer.h"
-#include "dbus-path.h"
-#include "bus-errors.h"
-#include "special.h"
-#include "dbus-common.h"
-
-#define CONNECTIONS_MAX 52
-
-/* Well-known address (http://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-types) */
-#define DBUS_SYSTEM_BUS_DEFAULT_ADDRESS "unix:path=/var/run/dbus/system_bus_socket"
-/* Only used as a fallback */
-#define DBUS_SESSION_BUS_DEFAULT_ADDRESS "autolaunch:"
-
-static const char bus_properties_interface[] = BUS_PROPERTIES_INTERFACE;
-static const char bus_introspectable_interface[] = BUS_INTROSPECTABLE_INTERFACE;
-
-const char *const bus_interface_table[] = {
- "org.freedesktop.DBus.Properties", bus_properties_interface,
- "org.freedesktop.DBus.Introspectable", bus_introspectable_interface,
- "org.freedesktop.systemd1.Manager", bus_manager_interface,
- "org.freedesktop.systemd1.Job", bus_job_interface,
- "org.freedesktop.systemd1.Unit", bus_unit_interface,
- "org.freedesktop.systemd1.Service", bus_service_interface,
- "org.freedesktop.systemd1.Socket", bus_socket_interface,
- "org.freedesktop.systemd1.Target", bus_target_interface,
- "org.freedesktop.systemd1.Device", bus_device_interface,
- "org.freedesktop.systemd1.Mount", bus_mount_interface,
- "org.freedesktop.systemd1.Automount", bus_automount_interface,
- "org.freedesktop.systemd1.Snapshot", bus_snapshot_interface,
- "org.freedesktop.systemd1.Swap", bus_swap_interface,
- "org.freedesktop.systemd1.Timer", bus_timer_interface,
- "org.freedesktop.systemd1.Path", bus_path_interface,
- NULL
-};
-
-static void bus_done_api(Manager *m);
-static void bus_done_system(Manager *m);
-static void bus_done_private(Manager *m);
-static void shutdown_connection(Manager *m, DBusConnection *c);
-
-static void bus_dispatch_status(DBusConnection *bus, DBusDispatchStatus status, void *data) {
- Manager *m = data;
-
- assert(bus);
- assert(m);
-
- /* We maintain two sets, one for those connections where we
- * requested a dispatch, and another where we didn't. And then,
- * we move the connections between the two sets. */
-
- if (status == DBUS_DISPATCH_COMPLETE)
- set_move_one(m->bus_connections, m->bus_connections_for_dispatch, bus);
- else
- set_move_one(m->bus_connections_for_dispatch, m->bus_connections, bus);
-}
-
-void bus_watch_event(Manager *m, Watch *w, int events) {
- assert(m);
- assert(w);
-
- /* This is called by the event loop whenever there is
- * something happening on D-Bus' file handles. */
-
- if (!dbus_watch_get_enabled(w->data.bus_watch))
- return;
-
- dbus_watch_handle(w->data.bus_watch, bus_events_to_flags(events));
-}
-
-static dbus_bool_t bus_add_watch(DBusWatch *bus_watch, void *data) {
- Manager *m = data;
- Watch *w;
- struct epoll_event ev;
-
- assert(bus_watch);
- assert(m);
-
- if (!(w = new0(Watch, 1)))
- return FALSE;
-
- w->fd = dbus_watch_get_unix_fd(bus_watch);
- w->type = WATCH_DBUS_WATCH;
- w->data.bus_watch = bus_watch;
-
- zero(ev);
- ev.events = bus_flags_to_events(bus_watch);
- ev.data.ptr = w;
-
- if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) {
-
- if (errno != EEXIST) {
- free(w);
- return FALSE;
- }
-
- /* Hmm, bloody D-Bus creates multiple watches on the
- * same fd. epoll() does not like that. As a dirty
- * hack we simply dup() the fd and hence get a second
- * one we can safely add to the epoll(). */
-
- if ((w->fd = dup(w->fd)) < 0) {
- free(w);
- return FALSE;
- }
-
- if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) {
- close_nointr_nofail(w->fd);
- free(w);
- return FALSE;
- }
-
- w->fd_is_dupped = true;
- }
-
- dbus_watch_set_data(bus_watch, w, NULL);
-
- return TRUE;
-}
-
-static void bus_remove_watch(DBusWatch *bus_watch, void *data) {
- Manager *m = data;
- Watch *w;
-
- assert(bus_watch);
- assert(m);
-
- w = dbus_watch_get_data(bus_watch);
- if (!w)
- return;
-
- assert(w->type == WATCH_DBUS_WATCH);
- assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
-
- if (w->fd_is_dupped)
- close_nointr_nofail(w->fd);
-
- free(w);
-}
-
-static void bus_toggle_watch(DBusWatch *bus_watch, void *data) {
- Manager *m = data;
- Watch *w;
- struct epoll_event ev;
-
- assert(bus_watch);
- assert(m);
-
- w = dbus_watch_get_data(bus_watch);
- if (!w)
- return;
-
- assert(w->type == WATCH_DBUS_WATCH);
-
- zero(ev);
- ev.events = bus_flags_to_events(bus_watch);
- ev.data.ptr = w;
-
- assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_MOD, w->fd, &ev) == 0);
-}
-
-static int bus_timeout_arm(Manager *m, Watch *w) {
- struct itimerspec its;
-
- assert(m);
- assert(w);
-
- zero(its);
-
- if (dbus_timeout_get_enabled(w->data.bus_timeout)) {
- timespec_store(&its.it_value, dbus_timeout_get_interval(w->data.bus_timeout) * USEC_PER_MSEC);
- its.it_interval = its.it_value;
- }
-
- if (timerfd_settime(w->fd, 0, &its, NULL) < 0)
- return -errno;
-
- return 0;
-}
-
-void bus_timeout_event(Manager *m, Watch *w, int events) {
- assert(m);
- assert(w);
-
- /* This is called by the event loop whenever there is
- * something happening on D-Bus' file handles. */
-
- if (!(dbus_timeout_get_enabled(w->data.bus_timeout)))
- return;
-
- dbus_timeout_handle(w->data.bus_timeout);
-}
-
-static dbus_bool_t bus_add_timeout(DBusTimeout *timeout, void *data) {
- Manager *m = data;
- Watch *w;
- struct epoll_event ev;
-
- assert(timeout);
- assert(m);
-
- if (!(w = new0(Watch, 1)))
- return FALSE;
-
- if ((w->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0)
- goto fail;
-
- w->type = WATCH_DBUS_TIMEOUT;
- w->data.bus_timeout = timeout;
-
- if (bus_timeout_arm(m, w) < 0)
- goto fail;
-
- zero(ev);
- ev.events = EPOLLIN;
- ev.data.ptr = w;
-
- if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0)
- goto fail;
-
- dbus_timeout_set_data(timeout, w, NULL);
-
- return TRUE;
-
-fail:
- if (w->fd >= 0)
- close_nointr_nofail(w->fd);
-
- free(w);
- return FALSE;
-}
-
-static void bus_remove_timeout(DBusTimeout *timeout, void *data) {
- Manager *m = data;
- Watch *w;
-
- assert(timeout);
- assert(m);
-
- w = dbus_timeout_get_data(timeout);
- if (!w)
- return;
-
- assert(w->type == WATCH_DBUS_TIMEOUT);
-
- assert_se(epoll_ctl(m->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
- close_nointr_nofail(w->fd);
- free(w);
-}
-
-static void bus_toggle_timeout(DBusTimeout *timeout, void *data) {
- Manager *m = data;
- Watch *w;
- int r;
-
- assert(timeout);
- assert(m);
-
- w = dbus_timeout_get_data(timeout);
- if (!w)
- return;
-
- assert(w->type == WATCH_DBUS_TIMEOUT);
-
- if ((r = bus_timeout_arm(m, w)) < 0)
- log_error("Failed to rearm timer: %s", strerror(-r));
-}
-
-static DBusHandlerResult api_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) {
- Manager *m = data;
- DBusError error;
- DBusMessage *reply = NULL;
-
- assert(connection);
- assert(message);
- assert(m);
-
- dbus_error_init(&error);
-
- if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL ||
- dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)
- log_debug("Got D-Bus request: %s.%s() on %s",
- dbus_message_get_interface(message),
- dbus_message_get_member(message),
- dbus_message_get_path(message));
-
- if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
- log_debug("API D-Bus connection terminated.");
- bus_done_api(m);
-
- } else if (dbus_message_is_signal(message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) {
- const char *name, *old_owner, *new_owner;
-
- if (!dbus_message_get_args(message, &error,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_STRING, &old_owner,
- DBUS_TYPE_STRING, &new_owner,
- DBUS_TYPE_INVALID))
- log_error("Failed to parse NameOwnerChanged message: %s", bus_error_message(&error));
- else {
- if (set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) name))
- log_debug("Subscription client vanished: %s (left: %u)", name, set_size(BUS_CONNECTION_SUBSCRIBED(m, connection)));
-
- if (old_owner[0] == 0)
- old_owner = NULL;
-
- if (new_owner[0] == 0)
- new_owner = NULL;
-
- manager_dispatch_bus_name_owner_changed(m, name, old_owner, new_owner);
- }
- } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Activator", "ActivationRequest")) {
- const char *name;
-
- if (!dbus_message_get_args(message, &error,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_INVALID))
- log_error("Failed to parse ActivationRequest message: %s", bus_error_message(&error));
- else {
- int r;
- Unit *u;
-
- log_debug("Got D-Bus activation request for %s", name);
-
- if (manager_unit_pending_inactive(m, SPECIAL_DBUS_SERVICE) ||
- manager_unit_pending_inactive(m, SPECIAL_DBUS_SOCKET)) {
- r = -EADDRNOTAVAIL;
- dbus_set_error(&error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is shutting down.");
- } else {
- r = manager_load_unit(m, name, NULL, &error, &u);
-
- if (r >= 0 && u->refuse_manual_start)
- r = -EPERM;
-
- if (r >= 0)
- r = manager_add_job(m, JOB_START, u, JOB_REPLACE, true, &error, NULL);
- }
-
- if (r < 0) {
- const char *id, *text;
-
- log_debug("D-Bus activation failed for %s: %s", name, strerror(-r));
-
- if (!(reply = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure")))
- goto oom;
-
- id = error.name ? error.name : bus_errno_to_dbus(r);
- text = bus_error(&error, r);
-
- if (!dbus_message_set_destination(reply, DBUS_SERVICE_DBUS) ||
- !dbus_message_append_args(reply,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_STRING, &id,
- DBUS_TYPE_STRING, &text,
- DBUS_TYPE_INVALID))
- goto oom;
- }
-
- /* On success we don't do anything, the service will be spawned now */
- }
- }
-
- dbus_error_free(&error);
-
- if (reply) {
- if (!dbus_connection_send(connection, reply, NULL))
- goto oom;
-
- dbus_message_unref(reply);
- }
-
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-oom:
- if (reply)
- dbus_message_unref(reply);
-
- dbus_error_free(&error);
-
- return DBUS_HANDLER_RESULT_NEED_MEMORY;
-}
-
-static DBusHandlerResult system_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) {
- Manager *m = data;
- DBusError error;
-
- assert(connection);
- assert(message);
- assert(m);
-
- dbus_error_init(&error);
-
- if (m->api_bus != m->system_bus &&
- (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL ||
- dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL))
- log_debug("Got D-Bus request on system bus: %s.%s() on %s",
- dbus_message_get_interface(message),
- dbus_message_get_member(message),
- dbus_message_get_path(message));
-
- if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected")) {
- log_debug("System D-Bus connection terminated.");
- bus_done_system(m);
-
- } else if (m->running_as != SYSTEMD_SYSTEM &&
- dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
-
- const char *cgroup;
-
- if (!dbus_message_get_args(message, &error,
- DBUS_TYPE_STRING, &cgroup,
- DBUS_TYPE_INVALID))
- log_error("Failed to parse Released message: %s", bus_error_message(&error));
- else
- cgroup_notify_empty(m, cgroup);
- }
-
- dbus_error_free(&error);
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-static DBusHandlerResult private_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) {
- Manager *m = data;
- DBusError error;
-
- assert(connection);
- assert(message);
- assert(m);
-
- dbus_error_init(&error);
-
- if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL ||
- dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL)
- log_debug("Got D-Bus request: %s.%s() on %s",
- dbus_message_get_interface(message),
- dbus_message_get_member(message),
- dbus_message_get_path(message));
-
- if (dbus_message_is_signal(message, DBUS_INTERFACE_LOCAL, "Disconnected"))
- shutdown_connection(m, connection);
- else if (m->running_as == SYSTEMD_SYSTEM &&
- dbus_message_is_signal(message, "org.freedesktop.systemd1.Agent", "Released")) {
-
- const char *cgroup;
-
- if (!dbus_message_get_args(message, &error,
- DBUS_TYPE_STRING, &cgroup,
- DBUS_TYPE_INVALID))
- log_error("Failed to parse Released message: %s", bus_error_message(&error));
- else
- cgroup_notify_empty(m, cgroup);
-
- /* Forward the message to the system bus, so that user
- * instances are notified as well */
-
- if (m->system_bus)
- dbus_connection_send(m->system_bus, message, NULL);
- }
-
- dbus_error_free(&error);
-
- return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-unsigned bus_dispatch(Manager *m) {
- DBusConnection *c;
-
- assert(m);
-
- if (m->queued_message) {
- /* 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. */
-
- if (m->queued_message_connection)
- if (!dbus_connection_send(m->queued_message_connection, m->queued_message, NULL))
- return 0;
-
- dbus_message_unref(m->queued_message);
- m->queued_message = NULL;
- m->queued_message_connection = NULL;
- }
-
- if ((c = set_first(m->bus_connections_for_dispatch))) {
- if (dbus_connection_dispatch(c) == DBUS_DISPATCH_COMPLETE)
- set_move_one(m->bus_connections, m->bus_connections_for_dispatch, c);
-
- return 1;
- }
-
- return 0;
-}
-
-static void request_name_pending_cb(DBusPendingCall *pending, void *userdata) {
- DBusMessage *reply;
- DBusError error;
-
- dbus_error_init(&error);
-
- assert_se(reply = dbus_pending_call_steal_reply(pending));
-
- switch (dbus_message_get_type(reply)) {
-
- case DBUS_MESSAGE_TYPE_ERROR:
-
- assert_se(dbus_set_error_from_message(&error, reply));
- log_warning("RequestName() failed: %s", bus_error_message(&error));
- break;
-
- case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
- uint32_t r;
-
- if (!dbus_message_get_args(reply,
- &error,
- DBUS_TYPE_UINT32, &r,
- DBUS_TYPE_INVALID)) {
- log_error("Failed to parse RequestName() reply: %s", bus_error_message(&error));
- break;
- }
-
- if (r == 1)
- log_debug("Successfully acquired name.");
- else
- log_error("Name already owned.");
-
- break;
- }
-
- default:
- assert_not_reached("Invalid reply message");
- }
-
- dbus_message_unref(reply);
- dbus_error_free(&error);
-}
-
-static int request_name(Manager *m) {
- const char *name = "org.freedesktop.systemd1";
- /* 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 */
- uint32_t flags = DBUS_NAME_FLAG_ALLOW_REPLACEMENT|DBUS_NAME_FLAG_REPLACE_EXISTING;
- DBusMessage *message = NULL;
- DBusPendingCall *pending = NULL;
-
- if (!(message = dbus_message_new_method_call(
- DBUS_SERVICE_DBUS,
- DBUS_PATH_DBUS,
- DBUS_INTERFACE_DBUS,
- "RequestName")))
- goto oom;
-
- if (!dbus_message_append_args(
- message,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_UINT32, &flags,
- DBUS_TYPE_INVALID))
- goto oom;
-
- if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
- goto oom;
-
- if (!dbus_pending_call_set_notify(pending, request_name_pending_cb, m, NULL))
- goto oom;
-
- dbus_message_unref(message);
- dbus_pending_call_unref(pending);
-
- /* We simple ask for the name and don't wait for it. Sooner or
- * later we'll have it. */
-
- return 0;
-
-oom:
- if (pending) {
- dbus_pending_call_cancel(pending);
- dbus_pending_call_unref(pending);
- }
-
- if (message)
- dbus_message_unref(message);
-
- return -ENOMEM;
-}
-
-static void query_name_list_pending_cb(DBusPendingCall *pending, void *userdata) {
- DBusMessage *reply;
- DBusError error;
- Manager *m = userdata;
-
- assert(m);
-
- dbus_error_init(&error);
-
- assert_se(reply = dbus_pending_call_steal_reply(pending));
-
- switch (dbus_message_get_type(reply)) {
-
- case DBUS_MESSAGE_TYPE_ERROR:
-
- assert_se(dbus_set_error_from_message(&error, reply));
- log_warning("ListNames() failed: %s", bus_error_message(&error));
- break;
-
- case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
- int r;
- char **l;
-
- if ((r = bus_parse_strv(reply, &l)) < 0)
- log_warning("Failed to parse ListNames() reply: %s", strerror(-r));
- else {
- char **t;
-
- STRV_FOREACH(t, l)
- /* This is a bit hacky, we say the
- * owner of the name is the name
- * itself, because we don't want the
- * extra traffic to figure out the
- * real owner. */
- manager_dispatch_bus_name_owner_changed(m, *t, NULL, *t);
-
- strv_free(l);
- }
-
- break;
- }
-
- default:
- assert_not_reached("Invalid reply message");
- }
-
- dbus_message_unref(reply);
- dbus_error_free(&error);
-}
-
-static int query_name_list(Manager *m) {
- DBusMessage *message = NULL;
- DBusPendingCall *pending = NULL;
-
- /* Asks for the currently installed bus names */
-
- if (!(message = dbus_message_new_method_call(
- DBUS_SERVICE_DBUS,
- DBUS_PATH_DBUS,
- DBUS_INTERFACE_DBUS,
- "ListNames")))
- goto oom;
-
- if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
- goto oom;
-
- if (!dbus_pending_call_set_notify(pending, query_name_list_pending_cb, m, NULL))
- goto oom;
-
- dbus_message_unref(message);
- dbus_pending_call_unref(pending);
-
- /* We simple ask for the list and don't wait for it. Sooner or
- * later we'll get it. */
-
- return 0;
-
-oom:
- if (pending) {
- dbus_pending_call_cancel(pending);
- dbus_pending_call_unref(pending);
- }
-
- if (message)
- dbus_message_unref(message);
-
- return -ENOMEM;
-}
-
-static int bus_setup_loop(Manager *m, DBusConnection *bus) {
- assert(m);
- assert(bus);
-
- dbus_connection_set_exit_on_disconnect(bus, FALSE);
-
- if (!dbus_connection_set_watch_functions(bus, bus_add_watch, bus_remove_watch, bus_toggle_watch, m, NULL) ||
- !dbus_connection_set_timeout_functions(bus, bus_add_timeout, bus_remove_timeout, bus_toggle_timeout, m, NULL))
- return log_oom();
-
- if (set_put(m->bus_connections_for_dispatch, bus) < 0)
- return log_oom();
-
- dbus_connection_set_dispatch_status_function(bus, bus_dispatch_status, m, NULL);
- return 0;
-}
-
-static dbus_bool_t allow_only_same_user(DBusConnection *connection, unsigned long uid, void *data) {
- return uid == 0 || uid == geteuid();
-}
-
-static void bus_new_connection(
- DBusServer *server,
- DBusConnection *new_connection,
- void *data) {
-
- Manager *m = data;
-
- assert(m);
-
- if (set_size(m->bus_connections) >= CONNECTIONS_MAX) {
- log_error("Too many concurrent connections.");
- return;
- }
-
- dbus_connection_set_unix_user_function(new_connection, allow_only_same_user, NULL, NULL);
-
- if (bus_setup_loop(m, new_connection) < 0)
- return;
-
- if (!dbus_connection_register_object_path(new_connection, "/org/freedesktop/systemd1", &bus_manager_vtable, m) ||
- !dbus_connection_register_fallback(new_connection, "/org/freedesktop/systemd1/unit", &bus_unit_vtable, m) ||
- !dbus_connection_register_fallback(new_connection, "/org/freedesktop/systemd1/job", &bus_job_vtable, m) ||
- !dbus_connection_add_filter(new_connection, private_bus_message_filter, m, NULL)) {
- log_oom();
- return;
- }
-
- log_debug("Accepted connection on private bus.");
-
- dbus_connection_ref(new_connection);
-}
-
-static int init_registered_system_bus(Manager *m) {
- char *id;
-
- if (!dbus_connection_add_filter(m->system_bus, system_bus_message_filter, m, NULL))
- return log_oom();
-
- if (m->running_as != SYSTEMD_SYSTEM) {
- DBusError error;
-
- dbus_error_init(&error);
-
- dbus_bus_add_match(m->system_bus,
- "type='signal',"
- "interface='org.freedesktop.systemd1.Agent',"
- "member='Released',"
- "path='/org/freedesktop/systemd1/agent'",
- &error);
-
- if (dbus_error_is_set(&error)) {
- log_error("Failed to register match: %s", bus_error_message(&error));
- dbus_error_free(&error);
- return -1;
- }
- }
-
- log_debug("Successfully connected to system D-Bus bus %s as %s",
- strnull((id = dbus_connection_get_server_id(m->system_bus))),
- strnull(dbus_bus_get_unique_name(m->system_bus)));
- dbus_free(id);
-
- return 0;
-}
-
-static int init_registered_api_bus(Manager *m) {
- int r;
-
- if (!dbus_connection_register_object_path(m->api_bus, "/org/freedesktop/systemd1", &bus_manager_vtable, m) ||
- !dbus_connection_register_fallback(m->api_bus, "/org/freedesktop/systemd1/unit", &bus_unit_vtable, m) ||
- !dbus_connection_register_fallback(m->api_bus, "/org/freedesktop/systemd1/job", &bus_job_vtable, m) ||
- !dbus_connection_add_filter(m->api_bus, api_bus_message_filter, m, NULL))
- return log_oom();
-
- /* Get NameOwnerChange messages */
- dbus_bus_add_match(m->api_bus,
- "type='signal',"
- "sender='"DBUS_SERVICE_DBUS"',"
- "interface='"DBUS_INTERFACE_DBUS"',"
- "member='NameOwnerChanged',"
- "path='"DBUS_PATH_DBUS"'",
- NULL);
-
- /* Get activation requests */
- dbus_bus_add_match(m->api_bus,
- "type='signal',"
- "sender='"DBUS_SERVICE_DBUS"',"
- "interface='org.freedesktop.systemd1.Activator',"
- "member='ActivationRequest',"
- "path='"DBUS_PATH_DBUS"'",
- NULL);
-
- r = request_name(m);
- if (r < 0)
- return r;
-
- r = query_name_list(m);
- if (r < 0)
- return r;
-
- if (m->running_as == SYSTEMD_USER) {
- char *id;
- log_debug("Successfully connected to API D-Bus bus %s as %s",
- strnull((id = dbus_connection_get_server_id(m->api_bus))),
- strnull(dbus_bus_get_unique_name(m->api_bus)));
- dbus_free(id);
- } else
- log_debug("Successfully initialized API on the system bus");
-
- return 0;
-}
-
-static void bus_register_cb(DBusPendingCall *pending, void *userdata) {
- Manager *m = userdata;
- DBusConnection **conn;
- DBusMessage *reply;
- DBusError error;
- const char *name;
- int r = 0;
-
- dbus_error_init(&error);
-
- conn = dbus_pending_call_get_data(pending, m->conn_data_slot);
- assert(conn == &m->system_bus || conn == &m->api_bus);
-
- reply = dbus_pending_call_steal_reply(pending);
-
- switch (dbus_message_get_type(reply)) {
- case DBUS_MESSAGE_TYPE_ERROR:
- assert_se(dbus_set_error_from_message(&error, reply));
- log_warning("Failed to register to bus: %s", bus_error_message(&error));
- r = -1;
- break;
- case DBUS_MESSAGE_TYPE_METHOD_RETURN:
- if (!dbus_message_get_args(reply, &error,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_INVALID)) {
- log_error("Failed to parse Hello reply: %s", bus_error_message(&error));
- r = -1;
- break;
- }
-
- log_debug("Received name %s in reply to Hello", name);
- if (!dbus_bus_set_unique_name(*conn, name)) {
- log_error("Failed to set unique name");
- r = -1;
- break;
- }
-
- if (conn == &m->system_bus) {
- r = init_registered_system_bus(m);
- if (r == 0 && m->running_as == SYSTEMD_SYSTEM)
- r = init_registered_api_bus(m);
- } else
- r = init_registered_api_bus(m);
-
- break;
- default:
- assert_not_reached("Invalid reply message");
- }
-
- dbus_message_unref(reply);
- dbus_error_free(&error);
-
- if (r < 0) {
- if (conn == &m->system_bus) {
- log_debug("Failed setting up the system bus");
- bus_done_system(m);
- } else {
- log_debug("Failed setting up the API bus");
- bus_done_api(m);
- }
- }
-}
-
-static int manager_bus_async_register(Manager *m, DBusConnection **conn) {
- DBusMessage *message = NULL;
- DBusPendingCall *pending = NULL;
-
- message = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
- DBUS_PATH_DBUS,
- DBUS_INTERFACE_DBUS,
- "Hello");
- if (!message)
- goto oom;
-
- if (!dbus_connection_send_with_reply(*conn, message, &pending, -1))
- goto oom;
-
- if (!dbus_pending_call_set_data(pending, m->conn_data_slot, conn, NULL))
- goto oom;
-
- if (!dbus_pending_call_set_notify(pending, bus_register_cb, m, NULL))
- goto oom;
-
- dbus_message_unref(message);
- dbus_pending_call_unref(pending);
-
- return 0;
-oom:
- if (pending) {
- dbus_pending_call_cancel(pending);
- dbus_pending_call_unref(pending);
- }
-
- if (message)
- dbus_message_unref(message);
-
- return -ENOMEM;
-}
-
-static DBusConnection* manager_bus_connect_private(Manager *m, DBusBusType type) {
- const char *address;
- DBusConnection *connection;
- DBusError error;
-
- switch (type) {
- case DBUS_BUS_SYSTEM:
- address = secure_getenv("DBUS_SYSTEM_BUS_ADDRESS");
- if (!address || !address[0])
- address = DBUS_SYSTEM_BUS_DEFAULT_ADDRESS;
- break;
- case DBUS_BUS_SESSION:
- address = secure_getenv("DBUS_SESSION_BUS_ADDRESS");
- if (!address || !address[0])
- address = DBUS_SESSION_BUS_DEFAULT_ADDRESS;
- break;
- default:
- assert_not_reached("Invalid bus type");
- }
-
- dbus_error_init(&error);
-
- connection = dbus_connection_open_private(address, &error);
- if (!connection) {
- log_warning("Failed to open private bus connection: %s", bus_error_message(&error));
- goto fail;
- }
-
- return connection;
-fail:
- if (connection)
- dbus_connection_close(connection);
- dbus_error_free(&error);
- return NULL;
-}
-
-static int bus_init_system(Manager *m) {
- int r;
-
- if (m->system_bus)
- return 0;
-
- m->system_bus = manager_bus_connect_private(m, DBUS_BUS_SYSTEM);
- if (!m->system_bus) {
- log_debug("Failed to connect to system D-Bus, retrying later");
- r = 0;
- goto fail;
- }
-
- r = bus_setup_loop(m, m->system_bus);
- if (r < 0)
- goto fail;
-
- r = manager_bus_async_register(m, &m->system_bus);
- if (r < 0)
- goto fail;
-
- return 0;
-fail:
- bus_done_system(m);
-
- return r;
-}
-
-static int bus_init_api(Manager *m) {
- int r;
-
- if (m->api_bus)
- return 0;
-
- if (m->running_as == SYSTEMD_SYSTEM) {
- m->api_bus = m->system_bus;
- /* In this mode there is no distinct connection to the API bus,
- * the API is published on the system bus.
- * bus_register_cb() is aware of that and will init the API
- * when the system bus gets registered.
- * No need to setup anything here. */
- return 0;
- }
-
- m->api_bus = manager_bus_connect_private(m, DBUS_BUS_SESSION);
- if (!m->api_bus) {
- log_debug("Failed to connect to API D-Bus, retrying later");
- r = 0;
- goto fail;
- }
-
- r = bus_setup_loop(m, m->api_bus);
- if (r < 0)
- goto fail;
-
- r = manager_bus_async_register(m, &m->api_bus);
- if (r < 0)
- goto fail;
-
- return 0;
-fail:
- bus_done_api(m);
-
- return r;
-}
-
-static int bus_init_private(Manager *m) {
- DBusError error;
- int r;
- const char *const external_only[] = {
- "EXTERNAL",
- NULL
- };
-
- assert(m);
-
- dbus_error_init(&error);
-
- if (m->private_bus)
- return 0;
-
- if (m->running_as == SYSTEMD_SYSTEM) {
-
- /* We want the private bus only when running as init */
- if (getpid() != 1)
- return 0;
-
- unlink("/run/systemd/private");
- m->private_bus = dbus_server_listen("unix:path=/run/systemd/private", &error);
- } else {
- const char *e;
- char *p;
-
- e = secure_getenv("XDG_RUNTIME_DIR");
- if (!e)
- return 0;
-
- if (asprintf(&p, "unix:path=%s/systemd/private", e) < 0) {
- r = log_oom();
- goto fail;
- }
-
- mkdir_parents_label(p+10, 0755);
- unlink(p+10);
- m->private_bus = dbus_server_listen(p, &error);
- free(p);
- }
-
- if (!m->private_bus) {
- log_error("Failed to create private D-Bus server: %s", bus_error_message(&error));
- r = -EIO;
- goto fail;
- }
-
- if (!dbus_server_set_auth_mechanisms(m->private_bus, (const char**) external_only) ||
- !dbus_server_set_watch_functions(m->private_bus, bus_add_watch, bus_remove_watch, bus_toggle_watch, m, NULL) ||
- !dbus_server_set_timeout_functions(m->private_bus, bus_add_timeout, bus_remove_timeout, bus_toggle_timeout, m, NULL)) {
- r = log_oom();
- goto fail;
- }
-
- dbus_server_set_new_connection_function(m->private_bus, bus_new_connection, m, NULL);
-
- log_debug("Successfully created private D-Bus server.");
-
- return 0;
-
-fail:
- bus_done_private(m);
- dbus_error_free(&error);
-
- return r;
-}
-
-int bus_init(Manager *m, bool try_bus_connect) {
- int r;
-
- if (set_ensure_allocated(&m->bus_connections, trivial_hash_func, trivial_compare_func) < 0 ||
- set_ensure_allocated(&m->bus_connections_for_dispatch, trivial_hash_func, trivial_compare_func) < 0)
- goto oom;
-
- if (m->name_data_slot < 0)
- if (!dbus_pending_call_allocate_data_slot(&m->name_data_slot))
- goto oom;
-
- if (m->conn_data_slot < 0)
- if (!dbus_pending_call_allocate_data_slot(&m->conn_data_slot))
- goto oom;
-
- if (m->subscribed_data_slot < 0)
- if (!dbus_connection_allocate_data_slot(&m->subscribed_data_slot))
- goto oom;
-
- if (try_bus_connect) {
- if ((r = bus_init_system(m)) < 0 ||
- (r = bus_init_api(m)) < 0)
- return r;
- }
-
- if ((r = bus_init_private(m)) < 0)
- return r;
-
- return 0;
-oom:
- return log_oom();
-}
-
-static void shutdown_connection(Manager *m, DBusConnection *c) {
- Set *s;
- Job *j;
- Iterator i;
-
- HASHMAP_FOREACH(j, m->jobs, i) {
- JobBusClient *cl, *nextcl;
- LIST_FOREACH_SAFE(client, cl, nextcl, j->bus_client_list) {
- if (cl->bus == c) {
- LIST_REMOVE(JobBusClient, client, j->bus_client_list, cl);
- free(cl);
- }
- }
- }
-
- set_remove(m->bus_connections, c);
- set_remove(m->bus_connections_for_dispatch, c);
-
- if ((s = BUS_CONNECTION_SUBSCRIBED(m, c))) {
- char *t;
-
- while ((t = set_steal_first(s)))
- free(t);
-
- set_free(s);
- }
-
- if (m->queued_message_connection == c) {
- m->queued_message_connection = NULL;
-
- if (m->queued_message) {
- dbus_message_unref(m->queued_message);
- m->queued_message = NULL;
- }
- }
-
- dbus_connection_set_dispatch_status_function(c, NULL, NULL, NULL);
- /* system manager cannot afford to block on DBus */
- if (m->running_as != SYSTEMD_SYSTEM)
- dbus_connection_flush(c);
- dbus_connection_close(c);
- dbus_connection_unref(c);
-}
-
-static void bus_done_api(Manager *m) {
- if (!m->api_bus)
- return;
-
- if (m->running_as == SYSTEMD_USER)
- shutdown_connection(m, m->api_bus);
-
- m->api_bus = NULL;
-
- if (m->queued_message) {
- dbus_message_unref(m->queued_message);
- m->queued_message = NULL;
- }
-}
-
-static void bus_done_system(Manager *m) {
- if (!m->system_bus)
- return;
-
- if (m->running_as == SYSTEMD_SYSTEM)
- bus_done_api(m);
-
- shutdown_connection(m, m->system_bus);
- m->system_bus = NULL;
-}
-
-static void bus_done_private(Manager *m) {
- if (!m->private_bus)
- return;
-
- dbus_server_disconnect(m->private_bus);
- dbus_server_unref(m->private_bus);
- m->private_bus = NULL;
-}
-
-void bus_done(Manager *m) {
- DBusConnection *c;
-
- bus_done_api(m);
- bus_done_system(m);
- bus_done_private(m);
-
- while ((c = set_steal_first(m->bus_connections)))
- shutdown_connection(m, c);
-
- while ((c = set_steal_first(m->bus_connections_for_dispatch)))
- shutdown_connection(m, c);
-
- set_free(m->bus_connections);
- set_free(m->bus_connections_for_dispatch);
-
- if (m->name_data_slot >= 0)
- dbus_pending_call_free_data_slot(&m->name_data_slot);
-
- if (m->conn_data_slot >= 0)
- dbus_pending_call_free_data_slot(&m->conn_data_slot);
-
- if (m->subscribed_data_slot >= 0)
- dbus_connection_free_data_slot(&m->subscribed_data_slot);
-}
-
-static void query_pid_pending_cb(DBusPendingCall *pending, void *userdata) {
- Manager *m = userdata;
- DBusMessage *reply;
- DBusError error;
- const char *name;
-
- dbus_error_init(&error);
-
- assert_se(name = BUS_PENDING_CALL_NAME(m, pending));
- assert_se(reply = dbus_pending_call_steal_reply(pending));
-
- switch (dbus_message_get_type(reply)) {
-
- case DBUS_MESSAGE_TYPE_ERROR:
-
- assert_se(dbus_set_error_from_message(&error, reply));
- log_warning("GetConnectionUnixProcessID() failed: %s", bus_error_message(&error));
- break;
-
- case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
- uint32_t r;
-
- if (!dbus_message_get_args(reply,
- &error,
- DBUS_TYPE_UINT32, &r,
- DBUS_TYPE_INVALID)) {
- log_error("Failed to parse GetConnectionUnixProcessID() reply: %s", bus_error_message(&error));
- break;
- }
-
- manager_dispatch_bus_query_pid_done(m, name, (pid_t) r);
- break;
- }
-
- default:
- assert_not_reached("Invalid reply message");
- }
-
- dbus_message_unref(reply);
- dbus_error_free(&error);
-}
-
-int bus_query_pid(Manager *m, const char *name) {
- DBusMessage *message = NULL;
- DBusPendingCall *pending = NULL;
- char *n = NULL;
-
- assert(m);
- assert(name);
-
- if (!(message = dbus_message_new_method_call(
- DBUS_SERVICE_DBUS,
- DBUS_PATH_DBUS,
- DBUS_INTERFACE_DBUS,
- "GetConnectionUnixProcessID")))
- goto oom;
-
- if (!(dbus_message_append_args(
- message,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_INVALID)))
- goto oom;
-
- if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
- goto oom;
-
- if (!(n = strdup(name)))
- goto oom;
-
- if (!dbus_pending_call_set_data(pending, m->name_data_slot, n, free))
- goto oom;
-
- n = NULL;
-
- if (!dbus_pending_call_set_notify(pending, query_pid_pending_cb, m, NULL))
- goto oom;
-
- dbus_message_unref(message);
- dbus_pending_call_unref(pending);
-
- return 0;
-
-oom:
- free(n);
-
- if (pending) {
- dbus_pending_call_cancel(pending);
- dbus_pending_call_unref(pending);
- }
-
- if (message)
- dbus_message_unref(message);
-
- return -ENOMEM;
-}
-
-int bus_broadcast(Manager *m, DBusMessage *message) {
- bool oom = false;
- Iterator i;
- DBusConnection *c;
-
- assert(m);
- assert(message);
-
- SET_FOREACH(c, m->bus_connections_for_dispatch, i)
- if (c != m->system_bus || m->running_as == SYSTEMD_SYSTEM)
- oom = !dbus_connection_send(c, message, NULL);
-
- SET_FOREACH(c, m->bus_connections, i)
- if (c != m->system_bus || m->running_as == SYSTEMD_SYSTEM)
- oom = !dbus_connection_send(c, message, NULL);
-
- return oom ? -ENOMEM : 0;
-}
-
-bool bus_has_subscriber(Manager *m) {
- Iterator i;
- DBusConnection *c;
-
- assert(m);
-
- SET_FOREACH(c, m->bus_connections_for_dispatch, i)
- if (bus_connection_has_subscriber(m, c))
- return true;
-
- SET_FOREACH(c, m->bus_connections, i)
- if (bus_connection_has_subscriber(m, c))
- return true;
-
- return false;
-}
-
-bool bus_connection_has_subscriber(Manager *m, DBusConnection *c) {
- assert(m);
- assert(c);
-
- return !set_isempty(BUS_CONNECTION_SUBSCRIBED(m, c));
-}
-
-int bus_fdset_add_all(Manager *m, FDSet *fds) {
- Iterator i;
- DBusConnection *c;
-
- 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 that 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 */
-
- SET_FOREACH(c, m->bus_connections_for_dispatch, i) {
- int fd;
-
- if (dbus_connection_get_unix_fd(c, &fd)) {
- fd = fdset_put_dup(fds, fd);
-
- if (fd < 0)
- return fd;
- }
- }
-
- SET_FOREACH(c, m->bus_connections, i) {
- int fd;
-
- if (dbus_connection_get_unix_fd(c, &fd)) {
- fd = fdset_put_dup(fds, fd);
-
- if (fd < 0)
- return fd;
- }
- }
-
- return 0;
-}
-
-void bus_broadcast_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) {
-
- DBusMessage *message;
-
- assert(m);
-
- message = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartupFinished");
- if (!message) {
- log_oom();
- return;
- }
-
- assert_cc(sizeof(usec_t) == sizeof(uint64_t));
- if (!dbus_message_append_args(message,
- DBUS_TYPE_UINT64, &firmware_usec,
- DBUS_TYPE_UINT64, &loader_usec,
- DBUS_TYPE_UINT64, &kernel_usec,
- DBUS_TYPE_UINT64, &initrd_usec,
- DBUS_TYPE_UINT64, &userspace_usec,
- DBUS_TYPE_UINT64, &total_usec,
- DBUS_TYPE_INVALID)) {
- log_oom();
- goto finish;
- }
-
-
- if (bus_broadcast(m, message) < 0) {
- log_oom();
- goto finish;
- }
-
-finish:
- if (message)
- dbus_message_unref(message);
-}
diff --git a/src/core/dbus.h b/src/core/dbus.h
deleted file mode 100644
index c7a058e198..0000000000
--- a/src/core/dbus.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 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/dbus.h>
-
-#include "manager.h"
-
-int bus_init(Manager *m, bool try_bus_connect);
-void bus_done(Manager *m);
-
-unsigned bus_dispatch(Manager *m);
-
-void bus_watch_event(Manager *m, Watch *w, int events);
-void bus_timeout_event(Manager *m, Watch *w, int events);
-
-int bus_query_pid(Manager *m, const char *name);
-
-int bus_broadcast(Manager *m, DBusMessage *message);
-
-bool bus_has_subscriber(Manager *m);
-bool bus_connection_has_subscriber(Manager *m, DBusConnection *c);
-
-int bus_fdset_add_all(Manager *m, FDSet *fds);
-
-void bus_broadcast_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);
-
-#define BUS_CONNECTION_SUBSCRIBED(m, c) dbus_connection_get_data((c), (m)->subscribed_data_slot)
-#define BUS_PENDING_CALL_NAME(m, p) dbus_pending_call_get_data((p), (m)->name_data_slot)
-
-extern const char * const bus_interface_table[];
diff --git a/src/core/device.c b/src/core/device.c
deleted file mode 100644
index be76cafaed..0000000000
--- a/src/core/device.c
+++ /dev/null
@@ -1,644 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <sys/epoll.h>
-#include <libudev.h>
-
-#include "unit.h"
-#include "device.h"
-#include "strv.h"
-#include "log.h"
-#include "unit-name.h"
-#include "dbus-device.h"
-#include "def.h"
-#include "path-util.h"
-
-static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
- [DEVICE_DEAD] = UNIT_INACTIVE,
- [DEVICE_PLUGGED] = UNIT_ACTIVE
-};
-
-static void device_unset_sysfs(Device *d) {
- Device *first;
-
- assert(d);
-
- if (!d->sysfs)
- return;
-
- /* Remove this unit from the chain of devices which share the
- * same sysfs path. */
- first = hashmap_get(UNIT(d)->manager->devices_by_sysfs, d->sysfs);
- LIST_REMOVE(Device, same_sysfs, first, d);
-
- if (first)
- hashmap_remove_and_replace(UNIT(d)->manager->devices_by_sysfs, d->sysfs, first->sysfs, first);
- else
- hashmap_remove(UNIT(d)->manager->devices_by_sysfs, d->sysfs);
-
- free(d->sysfs);
- d->sysfs = NULL;
-}
-
-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. */
- UNIT(d)->job_timeout = DEFAULT_TIMEOUT_USEC;
-
- UNIT(d)->ignore_on_isolate = true;
- UNIT(d)->ignore_on_snapshot = true;
-}
-
-static void device_done(Unit *u) {
- Device *d = DEVICE(u);
-
- assert(d);
-
- device_unset_sysfs(d);
-}
-
-static void device_set_state(Device *d, DeviceState state) {
- DeviceState old_state;
- assert(d);
-
- old_state = d->state;
- d->state = state;
-
- if (state != old_state)
- log_debug("%s changed %s -> %s",
- UNIT(d)->id,
- device_state_to_string(old_state),
- device_state_to_string(state));
-
- unit_notify(UNIT(d), state_translation_table[old_state], state_translation_table[state], true);
-}
-
-static int device_coldplug(Unit *u) {
- Device *d = DEVICE(u);
-
- assert(d);
- assert(d->state == DEVICE_DEAD);
-
- if (d->sysfs)
- device_set_state(d, DEVICE_PLUGGED);
-
- 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));
-}
-
-static UnitActiveState device_active_state(Unit *u) {
- assert(u);
-
- return state_translation_table[DEVICE(u)->state];
-}
-
-static const char *device_sub_state_to_string(Unit *u) {
- assert(u);
-
- return device_state_to_string(DEVICE(u)->state);
-}
-
-static int device_add_escaped_name(Unit *u, const char *dn) {
- char *e;
- int r;
-
- assert(u);
- assert(dn);
- assert(dn[0] == '/');
-
- e = unit_name_from_path(dn, ".device");
- if (!e)
- return -ENOMEM;
-
- r = unit_add_name(u, e);
- free(e);
-
- if (r < 0 && r != -EEXIST)
- return r;
-
- return 0;
-}
-
-static int device_find_escape_name(Manager *m, const char *dn, Unit **_u) {
- char *e;
- Unit *u;
-
- assert(m);
- assert(dn);
- assert(dn[0] == '/');
- assert(_u);
-
- e = unit_name_from_path(dn, ".device");
- if (!e)
- return -ENOMEM;
-
- u = manager_get_unit(m, e);
- free(e);
-
- if (u) {
- *_u = u;
- return 1;
- }
-
- return 0;
-}
-
-static int device_update_unit(Manager *m, struct udev_device *dev, const char *path, bool main) {
- const char *sysfs, *model;
- Unit *u = NULL;
- int r;
- bool delete;
-
- assert(m);
-
- if (!(sysfs = udev_device_get_syspath(dev)))
- return -ENOMEM;
-
- if ((r = device_find_escape_name(m, path, &u)) < 0)
- return r;
-
- if (u && DEVICE(u)->sysfs && !path_equal(DEVICE(u)->sysfs, sysfs))
- return -EEXIST;
-
- if (!u) {
- delete = true;
-
- u = unit_new(m, sizeof(Device));
- if (!u)
- return -ENOMEM;
-
- r = device_add_escaped_name(u, path);
- 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 (!DEVICE(u)->sysfs) {
- Device *first;
-
- if (!(DEVICE(u)->sysfs = strdup(sysfs))) {
- r = -ENOMEM;
- goto fail;
- }
-
- if (!m->devices_by_sysfs)
- if (!(m->devices_by_sysfs = hashmap_new(string_hash_func, string_compare_func))) {
- r = -ENOMEM;
- goto fail;
- }
-
- first = hashmap_get(m->devices_by_sysfs, sysfs);
- LIST_PREPEND(Device, same_sysfs, first, DEVICE(u));
-
- if ((r = hashmap_replace(m->devices_by_sysfs, DEVICE(u)->sysfs, first)) < 0)
- goto fail;
- }
-
- if ((model = udev_device_get_property_value(dev, "ID_MODEL_FROM_DATABASE")) ||
- (model = udev_device_get_property_value(dev, "ID_MODEL"))) {
- if ((r = unit_set_description(u, model)) < 0)
- goto fail;
- } else
- if ((r = unit_set_description(u, path)) < 0)
- goto fail;
-
- if (main) {
- /* The additional systemd udev properties we only
- * interpret for the main object */
- const char *wants, *alias;
-
- alias = udev_device_get_property_value(dev, "SYSTEMD_ALIAS");
- if (alias) {
- char *state, *w;
- size_t l;
-
- FOREACH_WORD_QUOTED(w, l, alias, state) {
- char *e;
-
- e = strndup(w, l);
- if (!e) {
- r = -ENOMEM;
- goto fail;
- }
-
- if (!is_path(e)) {
- log_warning("SYSTEMD_ALIAS for %s is not a path, ignoring: %s", sysfs, e);
- free(e);
- } else {
- device_update_unit(m, dev, e, false);
- free(e);
- }
- }
- }
-
- wants = udev_device_get_property_value(dev, "SYSTEMD_WANTS");
- if (wants) {
- char *state, *w;
- size_t l;
-
- FOREACH_WORD_QUOTED(w, l, wants, state) {
- char *e;
-
- e = strndup(w, l);
- if (!e) {
- r = -ENOMEM;
- goto fail;
- }
-
- r = unit_add_dependency_by_name(u, UNIT_WANTS, e, NULL, true);
- free(e);
- if (r < 0)
- goto fail;
- }
- }
- }
-
- unit_add_to_dbus_queue(u);
- return 0;
-
-fail:
- log_warning("Failed to load device unit: %s", strerror(-r));
-
- if (delete && u)
- unit_free(u);
-
- return r;
-}
-
-static int device_process_new_device(Manager *m, struct udev_device *dev, bool update_state) {
- const char *sysfs, *dn;
- struct udev_list_entry *item = NULL, *first = NULL;
-
- assert(m);
-
- if (!(sysfs = udev_device_get_syspath(dev)))
- return -ENOMEM;
-
- /* Add the main unit named after the sysfs path */
- device_update_unit(m, dev, sysfs, true);
-
- /* Add an additional unit for the device node */
- if ((dn = udev_device_get_devnode(dev)))
- device_update_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;
-
- device_update_unit(m, dev, p, false);
- }
-
- if (update_state) {
- Device *d, *l;
-
- manager_dispatch_load_queue(m);
-
- l = hashmap_get(m->devices_by_sysfs, sysfs);
- LIST_FOREACH(same_sysfs, d, l)
- device_set_state(d, DEVICE_PLUGGED);
- }
-
- return 0;
-}
-
-static int device_process_path(Manager *m, const char *path, bool update_state) {
- int r;
- struct udev_device *dev;
-
- assert(m);
- assert(path);
-
- if (!(dev = udev_device_new_from_syspath(m->udev, path))) {
- log_warning("Failed to get udev device object from udev for path %s.", path);
- return -ENOMEM;
- }
-
- r = device_process_new_device(m, dev, update_state);
- udev_device_unref(dev);
- return r;
-}
-
-static int device_process_removed_device(Manager *m, struct udev_device *dev) {
- const char *sysfs;
- Device *d;
-
- assert(m);
- assert(dev);
-
- if (!(sysfs = udev_device_get_syspath(dev)))
- return -ENOMEM;
-
- /* Remove all units of this sysfs path */
- while ((d = hashmap_get(m->devices_by_sysfs, sysfs))) {
- device_unset_sysfs(d);
- device_set_state(d, DEVICE_DEAD);
- }
-
- return 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 **_s) {
- Device *d = DEVICE(u);
- Device *other;
- Set *s;
- int r;
-
- assert(d);
- assert(_s);
-
- if (!d->same_sysfs_prev && !d->same_sysfs_next) {
- *_s = NULL;
- return 0;
- }
-
- if (!(s = set_new(NULL, NULL)))
- return -ENOMEM;
-
- for (other = d->same_sysfs_next; other; other = other->same_sysfs_next)
- if ((r = set_put(s, other)) < 0)
- goto fail;
-
- for (other = d->same_sysfs_prev; other; other = other->same_sysfs_prev)
- if ((r = set_put(s, other)) < 0)
- goto fail;
-
- *_s = s;
- return 1;
-
-fail:
- set_free(s);
- return r;
-}
-
-static void device_shutdown(Manager *m) {
- assert(m);
-
- if (m->udev_monitor) {
- udev_monitor_unref(m->udev_monitor);
- m->udev_monitor = NULL;
- }
-
- if (m->udev) {
- udev_unref(m->udev);
- m->udev = NULL;
- }
-
- hashmap_free(m->devices_by_sysfs);
- m->devices_by_sysfs = NULL;
-}
-
-static int device_enumerate(Manager *m) {
- struct epoll_event ev;
- int r;
- struct udev_enumerate *e = NULL;
- struct udev_list_entry *item = NULL, *first = NULL;
-
- assert(m);
-
- if (!m->udev) {
- if (!(m->udev = udev_new()))
- return -ENOMEM;
-
- if (!(m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev"))) {
- r = -ENOMEM;
- goto fail;
- }
-
- /* This will fail if we are unprivileged, but that
- * should not matter much, as user instances won't run
- * during boot. */
- udev_monitor_set_receive_buffer_size(m->udev_monitor, 128*1024*1024);
-
- if (udev_monitor_filter_add_match_tag(m->udev_monitor, "systemd") < 0) {
- r = -ENOMEM;
- goto fail;
- }
-
- if (udev_monitor_enable_receiving(m->udev_monitor) < 0) {
- r = -EIO;
- goto fail;
- }
-
- m->udev_watch.type = WATCH_UDEV;
- m->udev_watch.fd = udev_monitor_get_fd(m->udev_monitor);
-
- zero(ev);
- ev.events = EPOLLIN;
- ev.data.ptr = &m->udev_watch;
-
- if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->udev_watch.fd, &ev) < 0)
- return -errno;
- }
-
- if (!(e = udev_enumerate_new(m->udev))) {
- r = -ENOMEM;
- goto fail;
- }
- if (udev_enumerate_add_match_tag(e, "systemd") < 0) {
- r = -EIO;
- goto fail;
- }
-
- if (udev_enumerate_scan_devices(e) < 0) {
- r = -EIO;
- goto fail;
- }
-
- first = udev_enumerate_get_list_entry(e);
- udev_list_entry_foreach(item, first)
- device_process_path(m, udev_list_entry_get_name(item), false);
-
- udev_enumerate_unref(e);
- return 0;
-
-fail:
- if (e)
- udev_enumerate_unref(e);
-
- device_shutdown(m);
- return r;
-}
-
-void device_fd_event(Manager *m, int events) {
- struct udev_device *dev;
- int r;
- const char *action, *ready;
-
- assert(m);
-
- if (events != EPOLLIN) {
- static RATELIMIT_DEFINE(limit, 10*USEC_PER_SEC, 5);
-
- if (!ratelimit_test(&limit))
- log_error("Failed to get udev event: %m");
- if (!(events & EPOLLIN))
- return;
- }
-
- if (!(dev = udev_monitor_receive_device(m->udev_monitor))) {
- /*
- * libudev might filter-out devices which pass the bloom filter,
- * so getting NULL here is not necessarily an error
- */
- return;
- }
-
- if (!(action = udev_device_get_action(dev))) {
- log_error("Failed to get udev action string.");
- goto fail;
- }
-
- ready = udev_device_get_property_value(dev, "SYSTEMD_READY");
-
- if (streq(action, "remove") || (ready && parse_boolean(ready) == 0)) {
- if ((r = device_process_removed_device(m, dev)) < 0) {
- log_error("Failed to process udev device event: %s", strerror(-r));
- goto fail;
- }
- } else {
- if ((r = device_process_new_device(m, dev, true)) < 0) {
- log_error("Failed to process udev device event: %s", strerror(-r));
- goto fail;
- }
- }
-
-fail:
- udev_device_unref(dev);
-}
-
-static const char* const device_state_table[_DEVICE_STATE_MAX] = {
- [DEVICE_DEAD] = "dead",
- [DEVICE_PLUGGED] = "plugged"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(device_state, DeviceState);
-
-const UnitVTable device_vtable = {
- .object_size = sizeof(Device),
- .sections =
- "Unit\0"
- "Device\0"
- "Install\0",
-
- .no_instances = true,
-
- .init = device_init,
-
- .load = unit_load_fragment_and_dropin_optional,
- .done = device_done,
- .coldplug = device_coldplug,
-
- .dump = device_dump,
-
- .active_state = device_active_state,
- .sub_state_to_string = device_sub_state_to_string,
-
- .bus_interface = "org.freedesktop.systemd1.Device",
- .bus_message_handler = bus_device_message_handler,
- .bus_invalidating_properties = bus_device_invalidating_properties,
-
- .following = device_following,
- .following_set = device_following_set,
-
- .enumerate = device_enumerate,
- .shutdown = device_shutdown,
-
- .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 3c4604f60e..0000000000
--- a/src/core/device.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct Device Device;
-
-#include "unit.h"
-
-/* We simply watch devices, we cannot plug/unplug them. That
- * simplifies the state engine greatly */
-typedef enum DeviceState {
- DEVICE_DEAD,
- DEVICE_PLUGGED,
- _DEVICE_STATE_MAX,
- _DEVICE_STATE_INVALID = -1
-} DeviceState;
-
-struct Device {
- Unit meta;
-
- char *sysfs;
-
- /* In order to be able to distinguish dependencies on
- different device nodes we might end up creating multiple
- devices for the same sysfs path. We chain them up here. */
-
- LIST_FIELDS(struct Device, same_sysfs);
-
- DeviceState state;
-};
-
-extern const UnitVTable device_vtable;
-
-void device_fd_event(Manager *m, int events);
-
-const char* device_state_to_string(DeviceState i);
-DeviceState device_state_from_string(const char *s);
diff --git a/src/core/execute.c b/src/core/execute.c
deleted file mode 100644
index e236d38e0f..0000000000
--- a/src/core/execute.c
+++ /dev/null
@@ -1,2132 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <assert.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
-#include <signal.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/prctl.h>
-#include <linux/sched.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <grp.h>
-#include <pwd.h>
-#include <sys/mount.h>
-#include <linux/fs.h>
-#include <linux/oom.h>
-#include <sys/poll.h>
-#include <linux/seccomp-bpf.h>
-
-#ifdef HAVE_PAM
-#include <security/pam_appl.h>
-#endif
-
-#include "execute.h"
-#include "strv.h"
-#include "macro.h"
-#include "capability.h"
-#include "util.h"
-#include "log.h"
-#include "ioprio.h"
-#include "securebits.h"
-#include "cgroup.h"
-#include "namespace.h"
-#include "tcpwrap.h"
-#include "exit-status.h"
-#include "missing.h"
-#include "utmp-wtmp.h"
-#include "def.h"
-#include "loopback-setup.h"
-#include "path-util.h"
-#include "syscall-list.h"
-#include "sd-id128.h"
-#include "sd-messages.h"
-
-#define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC)
-
-/* This assumes there is a 'tty' group */
-#define TTY_MODE 0620
-
-static int shift_fds(int fds[], unsigned n_fds) {
- int start, restart_from;
-
- if (n_fds <= 0)
- return 0;
-
- /* Modifies the fds array! (sorts it) */
-
- assert(fds);
-
- start = 0;
- for (;;) {
- int i;
-
- restart_from = -1;
-
- for (i = start; i < (int) n_fds; i++) {
- int nfd;
-
- /* Already at right index? */
- if (fds[i] == i+3)
- continue;
-
- if ((nfd = fcntl(fds[i], F_DUPFD, i+3)) < 0)
- return -errno;
-
- close_nointr_nofail(fds[i]);
- fds[i] = nfd;
-
- /* Hmm, the fd we wanted isn't free? Then
- * let's remember that and try again from here*/
- if (nfd != i+3 && restart_from < 0)
- restart_from = i;
- }
-
- if (restart_from < 0)
- break;
-
- start = restart_from;
- }
-
- return 0;
-}
-
-static int flags_fds(const int fds[], unsigned n_fds, bool nonblock) {
- unsigned i;
- int r;
-
- if (n_fds <= 0)
- return 0;
-
- assert(fds);
-
- /* Drops/Sets O_NONBLOCK and FD_CLOEXEC from the file flags */
-
- for (i = 0; i < n_fds; i++) {
-
- if ((r = fd_nonblock(fds[i], nonblock)) < 0)
- return r;
-
- /* We unconditionally drop FD_CLOEXEC from the fds,
- * since after all we want to pass these fds to our
- * children */
-
- if ((r = fd_cloexec(fds[i], false)) < 0)
- return r;
- }
-
- return 0;
-}
-
-static const char *tty_path(const ExecContext *context) {
- assert(context);
-
- if (context->tty_path)
- return context->tty_path;
-
- return "/dev/console";
-}
-
-void exec_context_tty_reset(const ExecContext *context) {
- assert(context);
-
- if (context->tty_vhangup)
- terminal_vhangup(tty_path(context));
-
- if (context->tty_reset)
- reset_terminal(tty_path(context));
-
- if (context->tty_vt_disallocate && context->tty_path)
- vt_disallocate(context->tty_path);
-}
-
-static int open_null_as(int flags, int nfd) {
- int fd, r;
-
- assert(nfd >= 0);
-
- if ((fd = open("/dev/null", flags|O_NOCTTY)) < 0)
- return -errno;
-
- if (fd != nfd) {
- r = dup2(fd, nfd) < 0 ? -errno : nfd;
- close_nointr_nofail(fd);
- } else
- r = nfd;
-
- return r;
-}
-
-static int connect_logger_as(const ExecContext *context, ExecOutput output, const char *ident, const char *unit_id, int nfd) {
- int fd, r;
- union sockaddr_union sa;
-
- assert(context);
- assert(output < _EXEC_OUTPUT_MAX);
- assert(ident);
- assert(nfd >= 0);
-
- fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (fd < 0)
- return -errno;
-
- zero(sa);
- sa.un.sun_family = AF_UNIX;
- strncpy(sa.un.sun_path, "/run/systemd/journal/stdout", sizeof(sa.un.sun_path));
-
- r = connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path));
- if (r < 0) {
- close_nointr_nofail(fd);
- return -errno;
- }
-
- if (shutdown(fd, SHUT_RD) < 0) {
- close_nointr_nofail(fd);
- return -errno;
- }
-
- 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,
- output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE || output == EXEC_OUTPUT_KMSG_AND_CONSOLE || output == EXEC_OUTPUT_JOURNAL_AND_CONSOLE);
-
- if (fd != nfd) {
- r = dup2(fd, nfd) < 0 ? -errno : nfd;
- close_nointr_nofail(fd);
- } else
- r = nfd;
-
- return r;
-}
-static int open_terminal_as(const char *path, mode_t mode, int nfd) {
- int fd, r;
-
- assert(path);
- assert(nfd >= 0);
-
- if ((fd = open_terminal(path, mode | O_NOCTTY)) < 0)
- return fd;
-
- if (fd != nfd) {
- r = dup2(fd, nfd) < 0 ? -errno : nfd;
- close_nointr_nofail(fd);
- } else
- r = nfd;
-
- return r;
-}
-
-static bool is_terminal_input(ExecInput i) {
- return
- i == EXEC_INPUT_TTY ||
- i == EXEC_INPUT_TTY_FORCE ||
- i == EXEC_INPUT_TTY_FAIL;
-}
-
-static int fixup_input(ExecInput std_input, int socket_fd, bool apply_tty_stdin) {
-
- if (is_terminal_input(std_input) && !apply_tty_stdin)
- return EXEC_INPUT_NULL;
-
- if (std_input == EXEC_INPUT_SOCKET && socket_fd < 0)
- return EXEC_INPUT_NULL;
-
- return std_input;
-}
-
-static int fixup_output(ExecOutput std_output, int socket_fd) {
-
- if (std_output == EXEC_OUTPUT_SOCKET && socket_fd < 0)
- return EXEC_OUTPUT_INHERIT;
-
- return std_output;
-}
-
-static int setup_input(const ExecContext *context, int socket_fd, bool apply_tty_stdin) {
- ExecInput i;
-
- assert(context);
-
- i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
-
- switch (i) {
-
- case EXEC_INPUT_NULL:
- return open_null_as(O_RDONLY, STDIN_FILENO);
-
- case EXEC_INPUT_TTY:
- case EXEC_INPUT_TTY_FORCE:
- case EXEC_INPUT_TTY_FAIL: {
- int fd, r;
-
- if ((fd = acquire_terminal(
- tty_path(context),
- i == EXEC_INPUT_TTY_FAIL,
- i == EXEC_INPUT_TTY_FORCE,
- false,
- (usec_t) -1)) < 0)
- return fd;
-
- if (fd != STDIN_FILENO) {
- r = dup2(fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO;
- close_nointr_nofail(fd);
- } else
- r = STDIN_FILENO;
-
- return r;
- }
-
- case EXEC_INPUT_SOCKET:
- return dup2(socket_fd, STDIN_FILENO) < 0 ? -errno : STDIN_FILENO;
-
- default:
- assert_not_reached("Unknown input type");
- }
-}
-
-static int setup_output(const ExecContext *context, int socket_fd, const char *ident, const char *unit_id, bool apply_tty_stdin) {
- ExecOutput o;
- ExecInput i;
-
- assert(context);
- assert(ident);
-
- i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
- o = fixup_output(context->std_output, socket_fd);
-
- /* This expects the input is already set up */
-
- switch (o) {
-
- case EXEC_OUTPUT_INHERIT:
-
- /* If input got downgraded, inherit the original value */
- if (i == EXEC_INPUT_NULL && is_terminal_input(context->std_input))
- return open_terminal_as(tty_path(context), O_WRONLY, STDOUT_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, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO;
-
- /* If we are not started from PID 1 we just inherit STDOUT from our parent process. */
- if (getppid() != 1)
- return STDOUT_FILENO;
-
- /* We need to open /dev/null here anew, to get the
- * right access mode. So we fall through */
-
- case EXEC_OUTPUT_NULL:
- return open_null_as(O_WRONLY, STDOUT_FILENO);
-
- case EXEC_OUTPUT_TTY:
- if (is_terminal_input(i))
- return dup2(STDIN_FILENO, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO;
-
- /* We don't reset the terminal if this is just about output */
- return open_terminal_as(tty_path(context), O_WRONLY, STDOUT_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:
- return connect_logger_as(context, o, ident, unit_id, STDOUT_FILENO);
-
- case EXEC_OUTPUT_SOCKET:
- assert(socket_fd >= 0);
- return dup2(socket_fd, STDOUT_FILENO) < 0 ? -errno : STDOUT_FILENO;
-
- default:
- assert_not_reached("Unknown output type");
- }
-}
-
-static int setup_error(const ExecContext *context, int socket_fd, const char *ident, const char *unit_id, bool apply_tty_stdin) {
- ExecOutput o, e;
- ExecInput i;
-
- assert(context);
- assert(ident);
-
- i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
- o = fixup_output(context->std_output, socket_fd);
- 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 STDERR_FILENO;
-
- /* Duplicate from stdout if possible */
- if (e == o || e == EXEC_OUTPUT_INHERIT)
- return dup2(STDOUT_FILENO, STDERR_FILENO) < 0 ? -errno : STDERR_FILENO;
-
- switch (e) {
-
- case EXEC_OUTPUT_NULL:
- return open_null_as(O_WRONLY, STDERR_FILENO);
-
- case EXEC_OUTPUT_TTY:
- if (is_terminal_input(i))
- return dup2(STDIN_FILENO, STDERR_FILENO) < 0 ? -errno : STDERR_FILENO;
-
- /* We don't reset the terminal if this is just about output */
- return open_terminal_as(tty_path(context), O_WRONLY, STDERR_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:
- return connect_logger_as(context, e, ident, unit_id, STDERR_FILENO);
-
- case EXEC_OUTPUT_SOCKET:
- assert(socket_fd >= 0);
- return dup2(socket_fd, STDERR_FILENO) < 0 ? -errno : STDERR_FILENO;
-
- default:
- assert_not_reached("Unknown error type");
- }
-}
-
-static int chown_terminal(int fd, uid_t uid) {
- struct stat st;
-
- assert(fd >= 0);
-
- /* This might fail. What matters are the results. */
- (void) fchown(fd, uid, -1);
- (void) fchmod(fd, TTY_MODE);
-
- if (fstat(fd, &st) < 0)
- return -errno;
-
- if (st.st_uid != uid || (st.st_mode & 0777) != TTY_MODE)
- return -EPERM;
-
- return 0;
-}
-
-static int setup_confirm_stdio(int *_saved_stdin,
- int *_saved_stdout) {
- int fd = -1, saved_stdin, saved_stdout = -1, r;
-
- assert(_saved_stdin);
- assert(_saved_stdout);
-
- saved_stdin = fcntl(STDIN_FILENO, F_DUPFD, 3);
- if (saved_stdin < 0)
- return -errno;
-
- saved_stdout = fcntl(STDOUT_FILENO, F_DUPFD, 3);
- if (saved_stdout < 0) {
- r = errno;
- goto fail;
- }
-
- fd = acquire_terminal(
- "/dev/console",
- false,
- false,
- false,
- DEFAULT_CONFIRM_USEC);
- if (fd < 0) {
- r = fd;
- goto fail;
- }
-
- r = chown_terminal(fd, getuid());
- if (r < 0)
- goto fail;
-
- if (dup2(fd, STDIN_FILENO) < 0) {
- r = -errno;
- goto fail;
- }
-
- if (dup2(fd, STDOUT_FILENO) < 0) {
- r = -errno;
- goto fail;
- }
-
- if (fd >= 2)
- close_nointr_nofail(fd);
-
- *_saved_stdin = saved_stdin;
- *_saved_stdout = saved_stdout;
-
- return 0;
-
-fail:
- if (saved_stdout >= 0)
- close_nointr_nofail(saved_stdout);
-
- if (saved_stdin >= 0)
- close_nointr_nofail(saved_stdin);
-
- if (fd >= 0)
- close_nointr_nofail(fd);
-
- return r;
-}
-
-static int write_confirm_message(const char *format, ...) {
- int fd;
- 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);
-
- close_nointr_nofail(fd);
-
- 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;
-
- if (*saved_stdin >= 0)
- close_nointr_nofail(*saved_stdin);
-
- if (*saved_stdout >= 0)
- close_nointr_nofail(*saved_stdout);
-
- return r;
-}
-
-static int ask_for_confirmation(char *response, char **argv) {
- int saved_stdout = -1, saved_stdin = -1, r;
- char *line;
-
- r = setup_confirm_stdio(&saved_stdin, &saved_stdout);
- if (r < 0)
- return r;
-
- line = exec_command_line(argv);
- if (!line)
- return -ENOMEM;
-
- r = ask(response, "yns", "Execute %s? [Yes, No, Skip] ", line);
- free(line);
-
- restore_confirm_stdio(&saved_stdin, &saved_stdout);
-
- return r;
-}
-
-static int enforce_groups(const ExecContext *context, const char *username, gid_t gid) {
- bool keep_groups = false;
- int r;
-
- assert(context);
-
- /* Lookup and set GID and supplementary group list. Here too
- * we avoid NSS lookups for gid=0. */
-
- if (context->group || username) {
-
- if (context->group) {
- const char *g = context->group;
-
- if ((r = get_group_creds(&g, &gid)) < 0)
- return r;
- }
-
- /* First step, initialize groups from /etc/groups */
- if (username && gid != 0) {
- if (initgroups(username, gid) < 0)
- return -errno;
-
- keep_groups = true;
- }
-
- /* Second step, set our gids */
- if (setresgid(gid, gid, gid) < 0)
- return -errno;
- }
-
- if (context->supplementary_groups) {
- int ngroups_max, k;
- gid_t *gids;
- char **i;
-
- /* Final step, initialize any manually set supplementary groups */
- assert_se((ngroups_max = (int) sysconf(_SC_NGROUPS_MAX)) > 0);
-
- if (!(gids = new(gid_t, ngroups_max)))
- return -ENOMEM;
-
- if (keep_groups) {
- if ((k = getgroups(ngroups_max, gids)) < 0) {
- free(gids);
- return -errno;
- }
- } else
- k = 0;
-
- STRV_FOREACH(i, context->supplementary_groups) {
- const char *g;
-
- if (k >= ngroups_max) {
- free(gids);
- return -E2BIG;
- }
-
- g = *i;
- r = get_group_creds(&g, gids+k);
- if (r < 0) {
- free(gids);
- return r;
- }
-
- k++;
- }
-
- if (setgroups(k, gids) < 0) {
- free(gids);
- return -errno;
- }
-
- free(gids);
- }
-
- return 0;
-}
-
-static int enforce_user(const ExecContext *context, uid_t uid) {
- int r;
- assert(context);
-
- /* Sets (but doesn't lookup) the uid and make sure we keep the
- * capabilities while doing so. */
-
- if (context->capabilities) {
- cap_t d;
- static const cap_value_t bits[] = {
- CAP_SETUID, /* Necessary so that we can run setresuid() below */
- CAP_SETPCAP /* Necessary so that we can set PR_SET_SECUREBITS later on */
- };
-
- /* First step: If we need to keep capabilities but
- * drop privileges we need to make sure we keep our
- * caps, whiel we drop privileges. */
- if (uid != 0) {
- int sb = context->secure_bits|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 (!(d = cap_dup(context->capabilities)))
- 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) {
- r = -errno;
- cap_free(d);
- return r;
- }
-
- if (cap_set_proc(d) < 0) {
- r = -errno;
- cap_free(d);
- return r;
- }
-
- cap_free(d);
- }
-
- /* Third step: actually set the uids */
- if (setresuid(uid, uid, uid) < 0)
- return -errno;
-
- /* At this point we should have all necessary capabilities but
- are otherwise a normal user. However, the caps might got
- corrupted due to the setresuid() so we need clean them up
- later. This is done outside of this call. */
-
- return 0;
-}
-
-#ifdef HAVE_PAM
-
-static int null_conv(
- int num_msg,
- const struct pam_message **msg,
- struct pam_response **resp,
- void *appdata_ptr) {
-
- /* We don't support conversations */
-
- return PAM_CONV_ERR;
-}
-
-static int setup_pam(
- const char *name,
- const char *user,
- uid_t uid,
- const char *tty,
- char ***pam_env,
- int fds[], unsigned n_fds) {
-
- static const struct pam_conv conv = {
- .conv = null_conv,
- .appdata_ptr = NULL
- };
-
- pam_handle_t *handle = NULL;
- sigset_t ss, old_ss;
- int pam_code = PAM_SUCCESS;
- int err;
- char **e = NULL;
- bool close_session = false;
- pid_t pam_pid = 0, parent_pid;
-
- assert(name);
- assert(user);
- assert(pam_env);
-
- /* We set up PAM in the parent process, then fork. The child
- * will then stay around until killed via PR_GET_PDEATHSIG or
- * systemd via the cgroup logic. It will then remove the PAM
- * session again. The parent process will exec() the actual
- * daemon. We do things this way to ensure that the main PID
- * of the daemon is the one we initially fork()ed. */
-
- if ((pam_code = pam_start(name, user, &conv, &handle)) != PAM_SUCCESS) {
- handle = NULL;
- goto fail;
- }
-
- if (tty)
- if ((pam_code = pam_set_item(handle, PAM_TTY, tty)) != PAM_SUCCESS)
- goto fail;
-
- if ((pam_code = pam_acct_mgmt(handle, PAM_SILENT)) != PAM_SUCCESS)
- goto fail;
-
- if ((pam_code = pam_open_session(handle, PAM_SILENT)) != PAM_SUCCESS)
- goto fail;
-
- close_session = true;
-
- if ((!(e = pam_getenvlist(handle)))) {
- pam_code = PAM_BUF_ERR;
- goto fail;
- }
-
- /* Block SIGTERM, so that we know that it won't get lost in
- * the child */
- if (sigemptyset(&ss) < 0 ||
- sigaddset(&ss, SIGTERM) < 0 ||
- sigprocmask(SIG_BLOCK, &ss, &old_ss) < 0)
- goto fail;
-
- parent_pid = getpid();
-
- if ((pam_pid = fork()) < 0)
- goto fail;
-
- if (pam_pid == 0) {
- int sig;
- int r = EXIT_PAM;
-
- /* The child's job is to reset the PAM session on
- * termination */
-
- /* This string must fit in 10 chars (i.e. the length
- * of "/sbin/init"), to look pretty in /bin/ps */
- rename_process("(sd-pam)");
-
- /* Make sure we don't keep open the passed fds in this
- child. We assume that otherwise only those fds are
- open here that have been opened by PAM. */
- close_many(fds, n_fds);
-
- /* Drop privileges - we don't need any to pam_close_session
- * and this will make PR_SET_PDEATHSIG work in most cases.
- * If this fails, ignore the error - but expect sd-pam threads
- * to fail to exit normally */
- if (setresuid(uid, uid, uid) < 0)
- log_error("Error: Failed to setresuid() in sd-pam: %s", strerror(-r));
-
- /* Wait until our parent died. This will only work if
- * the above setresuid() succeeds, otherwise the kernel
- * will not allow unprivileged parents kill their privileged
- * children this way. We rely on the control groups kill logic
- * to do the rest for us. */
- if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
- goto child_finish;
-
- /* Check if our parent process might already have
- * died? */
- if (getppid() == parent_pid) {
- for (;;) {
- if (sigwait(&ss, &sig) < 0) {
- if (errno == EINTR)
- continue;
-
- goto child_finish;
- }
-
- assert(sig == SIGTERM);
- break;
- }
- }
-
- /* If our parent died we'll end the session */
- if (getppid() != parent_pid)
- if ((pam_code = pam_close_session(handle, PAM_DATA_SILENT)) != PAM_SUCCESS)
- goto child_finish;
-
- r = 0;
-
- child_finish:
- pam_end(handle, pam_code | PAM_DATA_SILENT);
- _exit(r);
- }
-
- /* If the child was forked off successfully it will do all the
- * cleanups, so forget about the handle here. */
- handle = NULL;
-
- /* Unblock SIGTERM again in the parent */
- if (sigprocmask(SIG_SETMASK, &old_ss, NULL) < 0)
- goto fail;
-
- /* We close the log explicitly here, since the PAM modules
- * might have opened it, but we don't want this fd around. */
- closelog();
-
- *pam_env = e;
- e = NULL;
-
- return 0;
-
-fail:
- if (pam_code != PAM_SUCCESS)
- err = -EPERM; /* PAM errors do not map to errno */
- else
- err = -errno;
-
- if (handle) {
- if (close_session)
- pam_code = pam_close_session(handle, PAM_DATA_SILENT);
-
- pam_end(handle, pam_code | PAM_DATA_SILENT);
- }
-
- strv_free(e);
-
- closelog();
-
- if (pam_pid > 1) {
- kill(pam_pid, SIGTERM);
- kill(pam_pid, SIGCONT);
- }
-
- return err;
-}
-#endif
-
-static void rename_process_from_path(const char *path) {
- char process_name[11];
- const char *p;
- size_t l;
-
- /* This resulting string must fit in 10 chars (i.e. the length
- * of "/sbin/init") to look pretty in /bin/ps */
-
- p = path_get_file_name(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);
-}
-
-static int apply_seccomp(uint32_t *syscall_filter) {
- static const struct sock_filter header[] = {
- VALIDATE_ARCHITECTURE,
- EXAMINE_SYSCALL
- };
- static const struct sock_filter footer[] = {
- _KILL_PROCESS
- };
-
- int i;
- unsigned n;
- struct sock_filter *f;
- struct sock_fprog prog;
-
- assert(syscall_filter);
-
- /* First: count the syscalls to check for */
- for (i = 0, n = 0; i < syscall_max(); i++)
- if (syscall_filter[i >> 4] & (1 << (i & 31)))
- n++;
-
- /* Second: build the filter program from a header the syscall
- * matches and the footer */
- f = alloca(sizeof(struct sock_filter) * (ELEMENTSOF(header) + 2*n + ELEMENTSOF(footer)));
- memcpy(f, header, sizeof(header));
-
- for (i = 0, n = 0; i < syscall_max(); i++)
- if (syscall_filter[i >> 4] & (1 << (i & 31))) {
- struct sock_filter item[] = {
- BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, i, 0, 1),
- BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW)
- };
-
- assert_cc(ELEMENTSOF(item) == 2);
-
- f[ELEMENTSOF(header) + 2*n] = item[0];
- f[ELEMENTSOF(header) + 2*n+1] = item[1];
-
- n++;
- }
-
- memcpy(f + (ELEMENTSOF(header) + 2*n), footer, sizeof(footer));
-
- /* Third: install the filter */
- zero(prog);
- prog.len = ELEMENTSOF(header) + ELEMENTSOF(footer) + 2*n;
- prog.filter = f;
- if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) < 0)
- return -errno;
-
- return 0;
-}
-
-int exec_spawn(ExecCommand *command,
- char **argv,
- const ExecContext *context,
- int fds[], unsigned n_fds,
- char **environment,
- bool apply_permissions,
- bool apply_chroot,
- bool apply_tty_stdin,
- bool confirm_spawn,
- CGroupBonding *cgroup_bondings,
- CGroupAttribute *cgroup_attributes,
- const char *cgroup_suffix,
- const char *unit_id,
- int idle_pipe[2],
- pid_t *ret) {
-
- pid_t pid;
- int r;
- char *line;
- int socket_fd;
- char _cleanup_strv_free_ **files_env = NULL;
-
- assert(command);
- assert(context);
- assert(ret);
- assert(fds || n_fds <= 0);
-
- if (context->std_input == EXEC_INPUT_SOCKET ||
- context->std_output == EXEC_OUTPUT_SOCKET ||
- context->std_error == EXEC_OUTPUT_SOCKET) {
-
- if (n_fds != 1)
- return -EINVAL;
-
- socket_fd = fds[0];
-
- fds = NULL;
- n_fds = 0;
- } else
- socket_fd = -1;
-
- r = exec_context_load_environment(context, &files_env);
- if (r < 0) {
- log_struct(LOG_ERR,
- "UNIT=%s", unit_id,
- "MESSAGE=Failed to load environment files: %s", strerror(-r),
- "ERRNO=%d", -r,
- NULL);
- return r;
- }
-
- if (!argv)
- argv = command->argv;
-
- line = exec_command_line(argv);
- if (!line)
- return log_oom();
-
- log_struct(LOG_DEBUG,
- "UNIT=%s", unit_id,
- "MESSAGE=About to execute %s", line,
- NULL);
- free(line);
-
- r = cgroup_bonding_realize_list(cgroup_bondings);
- if (r < 0)
- return r;
-
- cgroup_attribute_apply_list(cgroup_attributes, cgroup_bondings);
-
- pid = fork();
- if (pid < 0)
- return -errno;
-
- if (pid == 0) {
- int i, err;
- sigset_t ss;
- const char *username = NULL, *home = NULL;
- uid_t uid = (uid_t) -1;
- gid_t gid = (gid_t) -1;
- char _cleanup_strv_free_ **our_env = NULL, **pam_env = NULL,
- **final_env = NULL, **final_argv = NULL;
- unsigned n_env = 0;
- bool set_access = false;
-
- /* child */
-
- rename_process_from_path(command->path);
-
- /* We reset exactly these signals, since they are the
- * only ones we set to SIG_IGN in the main daemon. All
- * others we leave untouched because we set them to
- * SIG_DFL or a valid handler initially, both of which
- * will be demoted to SIG_DFL. */
- default_signals(SIGNALS_CRASH_HANDLER,
- SIGNALS_IGNORE, -1);
-
- if (context->ignore_sigpipe)
- ignore_signals(SIGPIPE, -1);
-
- assert_se(sigemptyset(&ss) == 0);
- if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0) {
- err = -errno;
- r = EXIT_SIGNAL_MASK;
- goto fail_child;
- }
-
- if (idle_pipe) {
- if (idle_pipe[1] >= 0)
- close_nointr_nofail(idle_pipe[1]);
- if (idle_pipe[0] >= 0) {
- fd_wait_for_event(idle_pipe[0], POLLHUP, IDLE_TIMEOUT_USEC);
- close_nointr_nofail(idle_pipe[0]);
- }
- }
-
- /* Close sockets very early to make sure we don't
- * block init reexecution because it cannot bind its
- * sockets */
- log_forget_fds();
- err = close_all_fds(socket_fd >= 0 ? &socket_fd : fds,
- socket_fd >= 0 ? 1 : n_fds);
- if (err < 0) {
- r = EXIT_FDS;
- goto fail_child;
- }
-
- if (!context->same_pgrp)
- if (setsid() < 0) {
- err = -errno;
- r = EXIT_SETSID;
- goto fail_child;
- }
-
- if (context->tcpwrap_name) {
- if (socket_fd >= 0)
- if (!socket_tcpwrap(socket_fd, context->tcpwrap_name)) {
- err = -EACCES;
- r = EXIT_TCPWRAP;
- goto fail_child;
- }
-
- for (i = 0; i < (int) n_fds; i++) {
- if (!socket_tcpwrap(fds[i], context->tcpwrap_name)) {
- err = -EACCES;
- r = EXIT_TCPWRAP;
- goto fail_child;
- }
- }
- }
-
- exec_context_tty_reset(context);
-
- if (confirm_spawn) {
- char response;
-
- err = ask_for_confirmation(&response, argv);
- if (err == -ETIMEDOUT)
- write_confirm_message("Confirmation question timed out, assuming positive response.\n");
- else if (err < 0)
- write_confirm_message("Couldn't ask confirmation question, assuming positive response: %s\n", strerror(-err));
- else if (response == 's') {
- write_confirm_message("Skipping execution.\n");
- err = -ECANCELED;
- r = EXIT_CONFIRM;
- goto fail_child;
- } else if (response == 'n') {
- write_confirm_message("Failing execution.\n");
- err = r = 0;
- goto fail_child;
- }
- }
-
- /* If a socket is connected to STDIN/STDOUT/STDERR, we
- * must sure to drop O_NONBLOCK */
- if (socket_fd >= 0)
- fd_nonblock(socket_fd, false);
-
- err = setup_input(context, socket_fd, apply_tty_stdin);
- if (err < 0) {
- r = EXIT_STDIN;
- goto fail_child;
- }
-
- err = setup_output(context, socket_fd, path_get_file_name(command->path), unit_id, apply_tty_stdin);
- if (err < 0) {
- r = EXIT_STDOUT;
- goto fail_child;
- }
-
- err = setup_error(context, socket_fd, path_get_file_name(command->path), unit_id, apply_tty_stdin);
- if (err < 0) {
- r = EXIT_STDERR;
- goto fail_child;
- }
-
- if (cgroup_bondings) {
- err = cgroup_bonding_install_list(cgroup_bondings, 0, cgroup_suffix);
- if (err < 0) {
- r = EXIT_CGROUP;
- goto fail_child;
- }
- }
-
- if (context->oom_score_adjust_set) {
- char t[16];
-
- snprintf(t, sizeof(t), "%i", context->oom_score_adjust);
- char_array_0(t);
-
- if (write_one_line_file("/proc/self/oom_score_adj", t) < 0) {
- err = -errno;
- r = EXIT_OOM_ADJUST;
- goto fail_child;
- }
- }
-
- if (context->nice_set)
- if (setpriority(PRIO_PROCESS, 0, context->nice) < 0) {
- err = -errno;
- r = EXIT_NICE;
- goto fail_child;
- }
-
- if (context->cpu_sched_set) {
- struct sched_param param;
-
- zero(param);
- param.sched_priority = context->cpu_sched_priority;
-
- if (sched_setscheduler(0, context->cpu_sched_policy |
- (context->cpu_sched_reset_on_fork ? SCHED_RESET_ON_FORK : 0), &param) < 0) {
- err = -errno;
- r = EXIT_SETSCHEDULER;
- goto fail_child;
- }
- }
-
- if (context->cpuset)
- if (sched_setaffinity(0, CPU_ALLOC_SIZE(context->cpuset_ncpus), context->cpuset) < 0) {
- err = -errno;
- r = EXIT_CPUAFFINITY;
- goto fail_child;
- }
-
- if (context->ioprio_set)
- if (ioprio_set(IOPRIO_WHO_PROCESS, 0, context->ioprio) < 0) {
- err = -errno;
- r = EXIT_IOPRIO;
- goto fail_child;
- }
-
- if (context->timer_slack_nsec != (nsec_t) -1)
- if (prctl(PR_SET_TIMERSLACK, context->timer_slack_nsec) < 0) {
- err = -errno;
- r = EXIT_TIMERSLACK;
- goto fail_child;
- }
-
- if (context->utmp_id)
- utmp_put_init_process(context->utmp_id, getpid(), getsid(0), context->tty_path);
-
- if (context->user) {
- username = context->user;
- err = get_user_creds(&username, &uid, &gid, &home, NULL);
- if (err < 0) {
- r = EXIT_USER;
- goto fail_child;
- }
-
- if (is_terminal_input(context->std_input)) {
- err = chown_terminal(STDIN_FILENO, uid);
- if (err < 0) {
- r = EXIT_STDIN;
- goto fail_child;
- }
- }
-
- if (cgroup_bondings && context->control_group_modify) {
- err = cgroup_bonding_set_group_access_list(cgroup_bondings, 0755, uid, gid);
- if (err >= 0)
- err = cgroup_bonding_set_task_access_list(cgroup_bondings, 0644, uid, gid, context->control_group_persistent);
- if (err < 0) {
- r = EXIT_CGROUP;
- goto fail_child;
- }
-
- set_access = true;
- }
- }
-
- if (cgroup_bondings && !set_access && context->control_group_persistent >= 0) {
- err = cgroup_bonding_set_task_access_list(cgroup_bondings, (mode_t) -1, (uid_t) -1, (uid_t) -1, context->control_group_persistent);
- if (err < 0) {
- r = EXIT_CGROUP;
- goto fail_child;
- }
- }
-
- if (apply_permissions) {
- err = enforce_groups(context, username, gid);
- if (err < 0) {
- r = EXIT_GROUP;
- goto fail_child;
- }
- }
-
- umask(context->umask);
-
-#ifdef HAVE_PAM
- if (apply_permissions && context->pam_name && username) {
- err = setup_pam(context->pam_name, username, uid, context->tty_path, &pam_env, fds, n_fds);
- if (err < 0) {
- r = EXIT_PAM;
- goto fail_child;
- }
- }
-#endif
- if (context->private_network) {
- if (unshare(CLONE_NEWNET) < 0) {
- err = -errno;
- r = EXIT_NETWORK;
- goto fail_child;
- }
-
- loopback_setup();
- }
-
- if (strv_length(context->read_write_dirs) > 0 ||
- strv_length(context->read_only_dirs) > 0 ||
- strv_length(context->inaccessible_dirs) > 0 ||
- context->mount_flags != 0 ||
- context->private_tmp) {
- err = setup_namespace(context->read_write_dirs,
- context->read_only_dirs,
- context->inaccessible_dirs,
- context->private_tmp,
- context->mount_flags);
- if (err < 0) {
- r = EXIT_NAMESPACE;
- goto fail_child;
- }
- }
-
- if (apply_chroot) {
- if (context->root_directory)
- if (chroot(context->root_directory) < 0) {
- err = -errno;
- r = EXIT_CHROOT;
- goto fail_child;
- }
-
- if (chdir(context->working_directory ? context->working_directory : "/") < 0) {
- err = -errno;
- r = EXIT_CHDIR;
- goto fail_child;
- }
- } else {
- char _cleanup_free_ *d = NULL;
-
- if (asprintf(&d, "%s/%s",
- context->root_directory ? context->root_directory : "",
- context->working_directory ? context->working_directory : "") < 0) {
- err = -ENOMEM;
- r = EXIT_MEMORY;
- goto fail_child;
- }
-
- if (chdir(d) < 0) {
- err = -errno;
- r = EXIT_CHDIR;
- goto fail_child;
- }
- }
-
- /* We repeat the fd closing here, to make sure that
- * nothing is leaked from the PAM modules */
- err = close_all_fds(fds, n_fds);
- if (err >= 0)
- err = shift_fds(fds, n_fds);
- if (err >= 0)
- err = flags_fds(fds, n_fds, context->non_blocking);
- if (err < 0) {
- r = EXIT_FDS;
- goto fail_child;
- }
-
- if (apply_permissions) {
-
- for (i = 0; i < RLIMIT_NLIMITS; i++) {
- if (!context->rlimit[i])
- continue;
-
- if (setrlimit_closest(i, context->rlimit[i]) < 0) {
- err = -errno;
- r = EXIT_LIMITS;
- goto fail_child;
- }
- }
-
- if (context->capability_bounding_set_drop) {
- err = capability_bounding_set_drop(context->capability_bounding_set_drop, false);
- if (err < 0) {
- r = EXIT_CAPABILITIES;
- goto fail_child;
- }
- }
-
- if (context->user) {
- err = enforce_user(context, uid);
- if (err < 0) {
- r = EXIT_USER;
- goto fail_child;
- }
- }
-
- /* PR_GET_SECUREBITS is not privileged, while
- * PR_SET_SECUREBITS is. So to suppress
- * potential EPERMs we'll try not to call
- * PR_SET_SECUREBITS unless necessary. */
- if (prctl(PR_GET_SECUREBITS) != context->secure_bits)
- if (prctl(PR_SET_SECUREBITS, context->secure_bits) < 0) {
- err = -errno;
- r = EXIT_SECUREBITS;
- goto fail_child;
- }
-
- if (context->capabilities)
- if (cap_set_proc(context->capabilities) < 0) {
- err = -errno;
- r = EXIT_CAPABILITIES;
- goto fail_child;
- }
-
- if (context->no_new_privileges)
- if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
- err = -errno;
- r = EXIT_NO_NEW_PRIVILEGES;
- goto fail_child;
- }
-
- if (context->syscall_filter) {
- err = apply_seccomp(context->syscall_filter);
- if (err < 0) {
- r = EXIT_SECCOMP;
- goto fail_child;
- }
- }
- }
-
- if (!(our_env = new0(char*, 7))) {
- err = -ENOMEM;
- r = EXIT_MEMORY;
- goto fail_child;
- }
-
- if (n_fds > 0)
- if (asprintf(our_env + n_env++, "LISTEN_PID=%lu", (unsigned long) getpid()) < 0 ||
- asprintf(our_env + n_env++, "LISTEN_FDS=%u", n_fds) < 0) {
- err = -ENOMEM;
- r = EXIT_MEMORY;
- goto fail_child;
- }
-
- if (home)
- if (asprintf(our_env + n_env++, "HOME=%s", home) < 0) {
- err = -ENOMEM;
- r = EXIT_MEMORY;
- goto fail_child;
- }
-
- if (username)
- if (asprintf(our_env + n_env++, "LOGNAME=%s", username) < 0 ||
- asprintf(our_env + n_env++, "USER=%s", username) < 0) {
- err = -ENOMEM;
- r = EXIT_MEMORY;
- goto fail_child;
- }
-
- if (is_terminal_input(context->std_input) ||
- context->std_output == EXEC_OUTPUT_TTY ||
- context->std_error == EXEC_OUTPUT_TTY)
- if (!(our_env[n_env++] = strdup(default_term_for_tty(tty_path(context))))) {
- err = -ENOMEM;
- r = EXIT_MEMORY;
- goto fail_child;
- }
-
- assert(n_env <= 7);
-
- if (!(final_env = strv_env_merge(
- 5,
- environment,
- our_env,
- context->environment,
- files_env,
- pam_env,
- NULL))) {
- err = -ENOMEM;
- r = EXIT_MEMORY;
- goto fail_child;
- }
-
- if (!(final_argv = replace_env_argv(argv, final_env))) {
- err = -ENOMEM;
- r = EXIT_MEMORY;
- goto fail_child;
- }
-
- final_env = strv_env_clean(final_env);
-
- execve(command->path, final_argv, final_env);
- err = -errno;
- r = EXIT_EXEC;
-
- fail_child:
- if (r != 0) {
- log_open();
- log_struct(LOG_ERR, MESSAGE_ID(SD_MESSAGE_SPAWN_FAILED),
- "EXECUTABLE=%s", command->path,
- "MESSAGE=Failed at step %s spawning %s: %s",
- exit_status_to_string(r, EXIT_STATUS_SYSTEMD),
- command->path, strerror(-err),
- "ERRNO=%d", -err,
- NULL);
- log_close();
- }
-
- _exit(r);
- }
-
- log_struct(LOG_DEBUG,
- "UNIT=%s", unit_id,
- "MESSAGE=Forked %s as %lu",
- command->path, (unsigned long) pid,
- NULL);
-
- /* 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 (cgroup_bondings)
- cgroup_bonding_install_list(cgroup_bondings, pid, cgroup_suffix);
-
- 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->control_group_persistent = -1;
- c->ignore_sigpipe = true;
- c->timer_slack_nsec = (nsec_t) -1;
-}
-
-void exec_context_done(ExecContext *c) {
- unsigned l;
-
- assert(c);
-
- strv_free(c->environment);
- c->environment = NULL;
-
- strv_free(c->environment_files);
- c->environment_files = NULL;
-
- for (l = 0; l < ELEMENTSOF(c->rlimit); l++) {
- free(c->rlimit[l]);
- c->rlimit[l] = NULL;
- }
-
- free(c->working_directory);
- c->working_directory = NULL;
- free(c->root_directory);
- c->root_directory = NULL;
-
- free(c->tty_path);
- c->tty_path = NULL;
-
- free(c->tcpwrap_name);
- c->tcpwrap_name = NULL;
-
- free(c->syslog_identifier);
- c->syslog_identifier = NULL;
-
- free(c->user);
- c->user = NULL;
-
- free(c->group);
- c->group = NULL;
-
- strv_free(c->supplementary_groups);
- c->supplementary_groups = NULL;
-
- free(c->pam_name);
- c->pam_name = NULL;
-
- if (c->capabilities) {
- cap_free(c->capabilities);
- c->capabilities = NULL;
- }
-
- strv_free(c->read_only_dirs);
- c->read_only_dirs = NULL;
-
- strv_free(c->read_write_dirs);
- c->read_write_dirs = NULL;
-
- strv_free(c->inaccessible_dirs);
- c->inaccessible_dirs = NULL;
-
- if (c->cpuset)
- CPU_FREE(c->cpuset);
-
- free(c->utmp_id);
- c->utmp_id = NULL;
-
- free(c->syscall_filter);
- c->syscall_filter = NULL;
-}
-
-void exec_command_done(ExecCommand *c) {
- assert(c);
-
- free(c->path);
- c->path = NULL;
-
- strv_free(c->argv);
- c->argv = NULL;
-}
-
-void exec_command_done_array(ExecCommand *c, unsigned n) {
- unsigned i;
-
- for (i = 0; i < n; i++)
- exec_command_done(c+i);
-}
-
-void exec_command_free_list(ExecCommand *c) {
- ExecCommand *i;
-
- while ((i = c)) {
- LIST_REMOVE(ExecCommand, command, c, i);
- exec_command_done(i);
- free(i);
- }
-}
-
-void exec_command_free_array(ExecCommand **c, unsigned n) {
- unsigned i;
-
- for (i = 0; i < n; i++) {
- exec_command_free_list(c[i]);
- c[i] = NULL;
- }
-}
-
-int exec_context_load_environment(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;
-
- fn = *i;
-
- if (fn[0] == '-') {
- ignore = true;
- fn ++;
- }
-
- if (!path_is_absolute(fn)) {
-
- if (ignore)
- continue;
-
- strv_free(r);
- return -EINVAL;
- }
-
- if ((k = load_env_file(fn, &p)) < 0) {
-
- if (ignore)
- continue;
-
- strv_free(r);
- return k;
- }
-
- 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 void strv_fprintf(FILE *f, char **l) {
- char **g;
-
- assert(f);
-
- STRV_FOREACH(g, l)
- fprintf(f, " %s", *g);
-}
-
-void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
- char ** e;
- unsigned i;
-
- assert(c);
- assert(f);
-
- if (!prefix)
- prefix = "";
-
- fprintf(f,
- "%sUMask: %04o\n"
- "%sWorkingDirectory: %s\n"
- "%sRootDirectory: %s\n"
- "%sNonBlocking: %s\n"
- "%sPrivateTmp: %s\n"
- "%sControlGroupModify: %s\n"
- "%sControlGroupPersistent: %s\n"
- "%sPrivateNetwork: %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->control_group_modify),
- prefix, yes_no(c->control_group_persistent),
- prefix, yes_no(c->private_network),
- prefix, yes_no(c->ignore_sigpipe));
-
- STRV_FOREACH(e, c->environment)
- fprintf(f, "%sEnvironment: %s\n", prefix, *e);
-
- STRV_FOREACH(e, c->environment_files)
- fprintf(f, "%sEnvironmentFile: %s\n", prefix, *e);
-
- if (c->tcpwrap_name)
- fprintf(f,
- "%sTCPWrapName: %s\n",
- prefix, c->tcpwrap_name);
-
- 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: %llu\n", prefix, rlimit_to_string(i), (unsigned long long) c->rlimit[i]->rlim_max);
-
- if (c->ioprio_set) {
- char *class_str;
- int r;
-
- r = ioprio_class_to_string_alloc(IOPRIO_PRIO_CLASS(c->ioprio), &class_str);
- if (r < 0)
- class_str = NULL;
- fprintf(f,
- "%sIOSchedulingClass: %s\n"
- "%sIOPriority: %i\n",
- prefix, strna(class_str),
- prefix, (int) IOPRIO_PRIO_DATA(c->ioprio));
- free(class_str);
- }
-
- if (c->cpu_sched_set) {
- char *policy_str;
- int r;
-
- r = sched_policy_to_string_alloc(c->cpu_sched_policy, &policy_str);
- if (r < 0)
- policy_str = NULL;
- 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));
- free(policy_str);
- }
-
- 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, " %i", i);
- fputs("\n", f);
- }
-
- if (c->timer_slack_nsec != (nsec_t) -1)
- fprintf(f, "%sTimerSlackNSec: %lu\n", prefix, (unsigned long)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) {
- char *fac_str, *lvl_str;
- int r;
-
- r = log_facility_unshifted_to_string_alloc(c->syslog_priority >> 3, &fac_str);
- if (r < 0)
- fac_str = NULL;
-
- r = log_level_to_string_alloc(LOG_PRI(c->syslog_priority), &lvl_str);
- if (r < 0)
- lvl_str = NULL;
-
- fprintf(f,
- "%sSyslogFacility: %s\n"
- "%sSyslogLevel: %s\n",
- prefix, strna(fac_str),
- prefix, strna(lvl_str));
- free(lvl_str);
- free(fac_str);
- }
-
- if (c->capabilities) {
- char *t;
- if ((t = cap_to_text(c->capabilities, NULL))) {
- fprintf(f, "%sCapabilities: %s\n",
- prefix, t);
- cap_free(t);
- }
- }
-
- if (c->secure_bits)
- fprintf(f, "%sSecure Bits:%s%s%s%s%s%s\n",
- prefix,
- (c->secure_bits & SECURE_KEEP_CAPS) ? " keep-caps" : "",
- (c->secure_bits & SECURE_KEEP_CAPS_LOCKED) ? " keep-caps-locked" : "",
- (c->secure_bits & SECURE_NO_SETUID_FIXUP) ? " no-setuid-fixup" : "",
- (c->secure_bits & SECURE_NO_SETUID_FIXUP_LOCKED) ? " no-setuid-fixup-locked" : "",
- (c->secure_bits & SECURE_NOROOT) ? " noroot" : "",
- (c->secure_bits & SECURE_NOROOT_LOCKED) ? "noroot-locked" : "");
-
- if (c->capability_bounding_set_drop) {
- unsigned long l;
- fprintf(f, "%sCapabilityBoundingSet:", prefix);
-
- for (l = 0; l <= cap_last_cap(); l++)
- if (!(c->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) l))) {
- char *t;
-
- if ((t = cap_to_name(l))) {
- fprintf(f, " %s", t);
- cap_free(t);
- }
- }
-
- 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);
-}
-
-void exec_status_start(ExecStatus *s, pid_t pid) {
- assert(s);
-
- zero(*s);
- s->pid = pid;
- dual_timestamp_get(&s->start_timestamp);
-}
-
-void exec_status_exit(ExecStatus *s, ExecContext *context, pid_t pid, int code, int status) {
- assert(s);
-
- if (s->pid && s->pid != pid)
- zero(*s);
-
- s->pid = pid;
- dual_timestamp_get(&s->exit_timestamp);
-
- s->code = code;
- s->status = status;
-
- if (context) {
- if (context->utmp_id)
- utmp_put_dead_process(context->utmp_id, pid, code, status);
-
- exec_context_tty_reset(context);
- }
-}
-
-void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix) {
- char buf[FORMAT_TIMESTAMP_MAX];
-
- assert(s);
- assert(f);
-
- if (!prefix)
- prefix = "";
-
- if (s->pid <= 0)
- return;
-
- fprintf(f,
- "%sPID: %lu\n",
- prefix, (unsigned long) 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) {
- char *p2;
- const char *prefix2;
-
- char *cmd;
-
- assert(c);
- assert(f);
-
- if (!prefix)
- prefix = "";
- p2 = strappend(prefix, "\t");
- prefix2 = p2 ? p2 : prefix;
-
- cmd = exec_command_line(c->argv);
-
- fprintf(f,
- "%sCommand Line: %s\n",
- prefix, cmd ? cmd : strerror(ENOMEM));
-
- free(cmd);
-
- exec_status_dump(&c->exec_status, f, prefix2);
-
- free(p2);
-}
-
-void exec_command_dump_list(ExecCommand *c, FILE *f, const char *prefix) {
- assert(f);
-
- if (!prefix)
- 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(ExecCommand, command, *l, end);
- LIST_INSERT_AFTER(ExecCommand, 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;
-
- if (!(p = strdup(path))) {
- strv_free(l);
- return -ENOMEM;
- }
-
- free(c->path);
- c->path = p;
-
- strv_free(c->argv);
- c->argv = l;
-
- return 0;
-}
-
-static const char* const exec_input_table[_EXEC_INPUT_MAX] = {
- [EXEC_INPUT_NULL] = "null",
- [EXEC_INPUT_TTY] = "tty",
- [EXEC_INPUT_TTY_FORCE] = "tty-force",
- [EXEC_INPUT_TTY_FAIL] = "tty-fail",
- [EXEC_INPUT_SOCKET] = "socket"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(exec_input, ExecInput);
-
-static const char* const exec_output_table[_EXEC_OUTPUT_MAX] = {
- [EXEC_OUTPUT_INHERIT] = "inherit",
- [EXEC_OUTPUT_NULL] = "null",
- [EXEC_OUTPUT_TTY] = "tty",
- [EXEC_OUTPUT_SYSLOG] = "syslog",
- [EXEC_OUTPUT_SYSLOG_AND_CONSOLE] = "syslog+console",
- [EXEC_OUTPUT_KMSG] = "kmsg",
- [EXEC_OUTPUT_KMSG_AND_CONSOLE] = "kmsg+console",
- [EXEC_OUTPUT_JOURNAL] = "journal",
- [EXEC_OUTPUT_JOURNAL_AND_CONSOLE] = "journal+console",
- [EXEC_OUTPUT_SOCKET] = "socket"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput);
diff --git a/src/core/execute.h b/src/core/execute.h
deleted file mode 100644
index 2bcd2e1e6c..0000000000
--- a/src/core/execute.h
+++ /dev/null
@@ -1,209 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct ExecStatus ExecStatus;
-typedef struct ExecCommand ExecCommand;
-typedef struct ExecContext ExecContext;
-
-#include <linux/types.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <sys/capability.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <sched.h>
-
-struct CGroupBonding;
-struct CGroupAttribute;
-
-#include "list.h"
-#include "util.h"
-
-typedef enum ExecInput {
- EXEC_INPUT_NULL,
- EXEC_INPUT_TTY,
- EXEC_INPUT_TTY_FORCE,
- EXEC_INPUT_TTY_FAIL,
- EXEC_INPUT_SOCKET,
- _EXEC_INPUT_MAX,
- _EXEC_INPUT_INVALID = -1
-} ExecInput;
-
-typedef enum ExecOutput {
- EXEC_OUTPUT_INHERIT,
- EXEC_OUTPUT_NULL,
- EXEC_OUTPUT_TTY,
- EXEC_OUTPUT_SYSLOG,
- EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
- EXEC_OUTPUT_KMSG,
- EXEC_OUTPUT_KMSG_AND_CONSOLE,
- EXEC_OUTPUT_JOURNAL,
- EXEC_OUTPUT_JOURNAL_AND_CONSOLE,
- EXEC_OUTPUT_SOCKET,
- _EXEC_OUTPUT_MAX,
- _EXEC_OUTPUT_INVALID = -1
-} ExecOutput;
-
-struct ExecStatus {
- dual_timestamp start_timestamp;
- dual_timestamp exit_timestamp;
- pid_t pid;
- int code; /* as in siginfo_t::si_code */
- int status; /* as in sigingo_t::si_status */
-};
-
-struct ExecCommand {
- char *path;
- char **argv;
- ExecStatus exec_status;
- LIST_FIELDS(ExecCommand, command); /* useful for chaining commands */
- bool ignore;
-};
-
-struct ExecContext {
- char **environment;
- char **environment_files;
-
- struct rlimit *rlimit[RLIMIT_NLIMITS];
- char *working_directory, *root_directory;
-
- mode_t umask;
- int oom_score_adjust;
- int nice;
- int ioprio;
- int cpu_sched_policy;
- int cpu_sched_priority;
-
- cpu_set_t *cpuset;
- unsigned cpuset_ncpus;
-
- ExecInput std_input;
- ExecOutput std_output;
- ExecOutput std_error;
-
- nsec_t timer_slack_nsec;
-
- char *tcpwrap_name;
-
- 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;
-
- char **read_write_dirs, **read_only_dirs, **inaccessible_dirs;
- unsigned long mount_flags;
-
- uint64_t capability_bounding_set_drop;
-
- cap_t capabilities;
- int secure_bits;
-
- int syslog_priority;
- char *syslog_identifier;
- bool syslog_level_prefix;
-
- bool cpu_sched_reset_on_fork;
- bool non_blocking;
- bool private_tmp;
- bool private_network;
-
- bool no_new_privileges;
-
- bool control_group_modify;
- int control_group_persistent;
-
- /* This is not exposed to the user but available
- * internally. We need it to make sure that whenever we spawn
- * /bin/mount it is run in the same process group as us so
- * that the autofs logic detects that it belongs to us and we
- * don't enter a trigger loop. */
- bool same_pgrp;
-
- uint32_t *syscall_filter;
-
- bool oom_score_adjust_set:1;
- bool nice_set:1;
- bool ioprio_set:1;
- bool cpu_sched_set:1;
-};
-
-int exec_spawn(ExecCommand *command,
- char **argv,
- const ExecContext *context,
- int fds[], unsigned n_fds,
- char **environment,
- bool apply_permissions,
- bool apply_chroot,
- bool apply_tty_stdin,
- bool confirm_spawn,
- struct CGroupBonding *cgroup_bondings,
- struct CGroupAttribute *cgroup_attributes,
- const char *cgroup_suffix,
- const char *unit_id,
- int pipe_fd[2],
- pid_t *ret);
-
-void exec_command_done(ExecCommand *c);
-void exec_command_done_array(ExecCommand *c, unsigned n);
-
-void 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, ...);
-
-void exec_context_init(ExecContext *c);
-void exec_context_done(ExecContext *c);
-void exec_context_dump(ExecContext *c, FILE* f, const char *prefix);
-void exec_context_tty_reset(const ExecContext *context);
-
-int exec_context_load_environment(const ExecContext *c, char ***l);
-
-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);
-
-const char* exec_output_to_string(ExecOutput i);
-ExecOutput exec_output_from_string(const char *s);
-
-const char* exec_input_to_string(ExecInput i);
-ExecInput exec_input_from_string(const char *s);
diff --git a/src/core/fdset.c b/src/core/fdset.c
deleted file mode 100644
index fe918cd8cc..0000000000
--- a/src/core/fdset.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#include "set.h"
-#include "util.h"
-#include "macro.h"
-#include "fdset.h"
-
-#define MAKE_SET(s) ((Set*) s)
-#define MAKE_FDSET(s) ((FDSet*) s)
-
-/* Make sure we can distuingish fd 0 and NULL */
-#define FD_TO_PTR(fd) INT_TO_PTR((fd)+1)
-#define PTR_TO_FD(p) (PTR_TO_INT(p)-1)
-
-FDSet *fdset_new(void) {
- return MAKE_FDSET(set_new(trivial_hash_func, trivial_compare_func));
-}
-
-void fdset_free(FDSet *s) {
- void *p;
-
- while ((p = set_steal_first(MAKE_SET(s)))) {
- /* Valgrind's fd might have ended up in this set here,
- * due to fdset_new_fill(). We'll ignore all failures
- * here, so that the EBADFD that valgrind will return
- * us on close() doesn't influence us */
-
- /* When reloading duplicates of the private bus
- * connection fds and suchlike are closed here, which
- * has no effect at all, since they are only
- * duplicates. So don't be surprised about these log
- * messages. */
-
- log_debug("Closing left-over fd %i", PTR_TO_FD(p));
- close_nointr(PTR_TO_FD(p));
- }
-
- set_free(MAKE_SET(s));
-}
-
-int fdset_put(FDSet *s, int fd) {
- assert(s);
- assert(fd >= 0);
-
- return set_put(MAKE_SET(s), FD_TO_PTR(fd));
-}
-
-int fdset_put_dup(FDSet *s, int fd) {
- int copy, r;
-
- assert(s);
- assert(fd >= 0);
-
- if ((copy = fcntl(fd, F_DUPFD_CLOEXEC, 3)) < 0)
- return -errno;
-
- if ((r = fdset_put(s, copy)) < 0) {
- close_nointr_nofail(copy);
- return r;
- }
-
- return copy;
-}
-
-bool fdset_contains(FDSet *s, int fd) {
- assert(s);
- assert(fd >= 0);
-
- return !!set_get(MAKE_SET(s), FD_TO_PTR(fd));
-}
-
-int fdset_remove(FDSet *s, int fd) {
- assert(s);
- assert(fd >= 0);
-
- return set_remove(MAKE_SET(s), FD_TO_PTR(fd)) ? fd : -ENOENT;
-}
-
-int fdset_new_fill(FDSet **_s) {
- DIR *d;
- struct dirent *de;
- int r = 0;
- FDSet *s;
-
- assert(_s);
-
- /* Creates an fdsets and fills in all currently open file
- * descriptors. */
-
- if (!(d = opendir("/proc/self/fd")))
- return -errno;
-
- if (!(s = fdset_new())) {
- r = -ENOMEM;
- goto finish;
- }
-
- while ((de = readdir(d))) {
- int fd = -1;
-
- if (ignore_file(de->d_name))
- continue;
-
- if ((r = safe_atoi(de->d_name, &fd)) < 0)
- goto finish;
-
- if (fd < 3)
- continue;
-
- if (fd == dirfd(d))
- continue;
-
- if ((r = fdset_put(s, fd)) < 0)
- goto finish;
- }
-
- r = 0;
- *_s = s;
- s = NULL;
-
-finish:
- closedir(d);
-
- /* We won't close the fds here! */
- if (s)
- set_free(MAKE_SET(s));
-
- return r;
-}
-
-int fdset_cloexec(FDSet *fds, bool b) {
- Iterator i;
- void *p;
- int r;
-
- assert(fds);
-
- SET_FOREACH(p, MAKE_SET(fds), i)
- if ((r = fd_cloexec(PTR_TO_FD(p), b)) < 0)
- return r;
-
- return 0;
-}
diff --git a/src/core/fdset.h b/src/core/fdset.h
deleted file mode 100644
index c3e408c8ad..0000000000
--- a/src/core/fdset.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct FDSet FDSet;
-
-FDSet* fdset_new(void);
-void fdset_free(FDSet *s);
-
-int fdset_put(FDSet *s, int fd);
-int fdset_put_dup(FDSet *s, int fd);
-
-bool fdset_contains(FDSet *s, int fd);
-int fdset_remove(FDSet *s, int fd);
-
-int fdset_new_fill(FDSet **_s);
-
-int fdset_cloexec(FDSet *fds, bool b);
diff --git a/src/core/hostname-setup.c b/src/core/hostname-setup.c
deleted file mode 100644
index dbd2227e21..0000000000
--- a/src/core/hostname-setup.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include "hostname-setup.h"
-#include "macro.h"
-#include "util.h"
-#include "log.h"
-
-#if defined(TARGET_ALTLINUX) || defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA)
-#define FILENAME "/etc/sysconfig/network"
-#elif defined(TARGET_SUSE) || defined(TARGET_SLACKWARE)
-#define FILENAME "/etc/HOSTNAME"
-#elif defined(TARGET_GENTOO)
-#define FILENAME "/etc/conf.d/hostname"
-#endif
-
-static int read_and_strip_hostname(const char *path, char **hn) {
- char *s;
- int r;
-
- assert(path);
- assert(hn);
-
- r = read_one_line_file(path, &s);
- if (r < 0)
- return r;
-
- hostname_cleanup(s);
-
- if (isempty(s)) {
- free(s);
- return -ENOENT;
- }
-
- *hn = s;
-
- return 0;
-}
-
-static int read_distro_hostname(char **hn) {
-
-#if defined(TARGET_GENTOO) || defined(TARGET_ALTLINUX) || defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA)
- int r;
- _cleanup_fclose_ FILE *f = NULL;
-
- assert(hn);
-
- f = fopen(FILENAME, "re");
- if (!f)
- return -errno;
-
- for (;;) {
- char line[LINE_MAX];
- char *s, *k;
-
- if (!fgets(line, sizeof(line), f)) {
- if (feof(f))
- break;
-
- r = -errno;
- goto finish;
- }
-
- s = strstrip(line);
-
- if (!startswith_no_case(s, "HOSTNAME="))
- continue;
-
- k = strdup(s+9);
- if (!k) {
- r = -ENOMEM;
- goto finish;
- }
-
- hostname_cleanup(k);
-
- if (isempty(k)) {
- free(k);
- r = -ENOENT;
- goto finish;
- }
-
- *hn = k;
- r = 0;
- goto finish;
- }
-
- r = -ENOENT;
-
-finish:
- return r;
-
-#elif defined(TARGET_SUSE) || defined(TARGET_SLACKWARE)
- return read_and_strip_hostname(FILENAME, hn);
-#else
- return -ENOENT;
-#endif
-}
-
-static int read_hostname(char **hn) {
- int r;
-
- assert(hn);
-
- /* First, try to load the generic hostname configuration file,
- * that we support on all distributions */
-
- r = read_and_strip_hostname("/etc/hostname", hn);
- if (r < 0) {
- if (r == -ENOENT)
- return read_distro_hostname(hn);
-
- return r;
- }
-
- return 0;
-}
-
-int hostname_setup(void) {
- int r;
- char *b = NULL;
- const char *hn = NULL;
- bool enoent = false;
-
- r = read_hostname(&b);
- if (r < 0) {
- hn = NULL;
-
- if (r == -ENOENT)
- enoent = true;
- else
- log_warning("Failed to read configured hostname: %s", strerror(-r));
- } else
- hn = b;
-
- if (isempty(hn)) {
- /* Don't override the hostname if it is already set
- * and not explicitly configured */
- if (hostname_is_set())
- goto finish;
-
- if (enoent)
- log_info("No hostname configured.");
-
- hn = "localhost";
- }
-
- if (sethostname(hn, strlen(hn)) < 0) {
- log_warning("Failed to set hostname to <%s>: %m", hn);
- r = -errno;
- } else
- log_info("Set hostname to <%s>.", hn);
-
-finish:
- free(b);
-
- return r;
-}
diff --git a/src/core/hostname-setup.h b/src/core/hostname-setup.h
deleted file mode 100644
index 8dc3a9e1d8..0000000000
--- a/src/core/hostname-setup.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-int hostname_setup(void);
diff --git a/src/core/ima-setup.c b/src/core/ima-setup.c
deleted file mode 100644
index e8cc1ba8b6..0000000000
--- a/src/core/ima-setup.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
- Copyright (C) 2012 Roberto Sassu - Politecnico di Torino, Italy
- TORSEC group -- http://security.polito.it
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-
-#include "ima-setup.h"
-#include "mount-setup.h"
-#include "macro.h"
-#include "util.h"
-#include "log.h"
-#include "label.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
- struct stat st;
- ssize_t policy_size = 0, written = 0;
- char *policy;
- int policyfd = -1, imafd = -1;
- int result = 0;
-
-#ifndef HAVE_SELINUX
- /* Mount the securityfs filesystem */
- mount_setup_early();
-#endif
-
- if (stat(IMA_POLICY_PATH, &st) < 0)
- return 0;
-
- policy_size = st.st_size;
- if (stat(IMA_SECFS_DIR, &st) < 0) {
- log_debug("IMA support is disabled in the kernel, ignoring.");
- return 0;
- }
-
- if (stat(IMA_SECFS_POLICY, &st) < 0) {
- log_error("Another IMA custom policy has already been loaded, "
- "ignoring.");
- return 0;
- }
-
- policyfd = open(IMA_POLICY_PATH, O_RDONLY|O_CLOEXEC);
- if (policyfd < 0) {
- log_error("Failed to open the IMA custom policy file %s (%m), "
- "ignoring.", IMA_POLICY_PATH);
- return 0;
- }
-
- imafd = open(IMA_SECFS_POLICY, O_WRONLY|O_CLOEXEC);
- if (imafd < 0) {
- log_error("Failed to open the IMA kernel interface %s (%m), "
- "ignoring.", IMA_SECFS_POLICY);
- goto out;
- }
-
- policy = mmap(NULL, policy_size, PROT_READ, MAP_PRIVATE, policyfd, 0);
- if (policy == MAP_FAILED) {
- log_error("mmap() failed (%m), freezing");
- result = -errno;
- goto out;
- }
-
- written = loop_write(imafd, policy, (size_t)policy_size, false);
- if (written != policy_size) {
- log_error("Failed to load the IMA custom policy file %s (%m), "
- "ignoring.", IMA_POLICY_PATH);
- goto out_mmap;
- }
-
- log_info("Successfully loaded the IMA custom policy %s.",
- IMA_POLICY_PATH);
-out_mmap:
- munmap(policy, policy_size);
-out:
- if (policyfd >= 0)
- close_nointr_nofail(policyfd);
- if (imafd >= 0)
- close_nointr_nofail(imafd);
- if (result)
- return result;
-#endif /* HAVE_IMA */
-
- return 0;
-}
diff --git a/src/core/ima-setup.h b/src/core/ima-setup.h
deleted file mode 100644
index 14b56d1fc2..0000000000
--- a/src/core/ima-setup.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
- Copyright (C) 2012 Roberto Sassu - Politecnico di Torino, Italy
- TORSEC group -- http://security.polito.it
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-int ima_setup(void);
diff --git a/src/core/initreq.h b/src/core/initreq.h
deleted file mode 100644
index 859042ce42..0000000000
--- a/src/core/initreq.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * initreq.h Interface to talk to init through /dev/initctl.
- *
- * Copyright (C) 1995-2004 Miquel van Smoorenburg
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * Version: @(#)initreq.h 1.28 31-Mar-2004 MvS
- *
- */
-#ifndef _INITREQ_H
-#define _INITREQ_H
-
-#include <sys/param.h>
-
-#if defined(__FreeBSD_kernel__)
-# define INIT_FIFO "/etc/.initctl"
-#else
-# define INIT_FIFO "/dev/initctl"
-#endif
-
-#define INIT_MAGIC 0x03091969
-#define INIT_CMD_START 0
-#define INIT_CMD_RUNLVL 1
-#define INIT_CMD_POWERFAIL 2
-#define INIT_CMD_POWERFAILNOW 3
-#define INIT_CMD_POWEROK 4
-#define INIT_CMD_BSD 5
-#define INIT_CMD_SETENV 6
-#define INIT_CMD_UNSETENV 7
-
-#define INIT_CMD_CHANGECONS 12345
-
-#ifdef MAXHOSTNAMELEN
-# define INITRQ_HLEN MAXHOSTNAMELEN
-#else
-# define INITRQ_HLEN 64
-#endif
-
-/*
- * This is what BSD 4.4 uses when talking to init.
- * Linux doesn't use this right now.
- */
-struct init_request_bsd {
- char gen_id[8]; /* Beats me.. telnetd uses "fe" */
- char tty_id[16]; /* Tty name minus /dev/tty */
- char host[INITRQ_HLEN]; /* Hostname */
- char term_type[16]; /* Terminal type */
- int signal; /* Signal to send */
- int pid; /* Process to send to */
- char exec_name[128]; /* Program to execute */
- char reserved[128]; /* For future expansion. */
-};
-
-
-/*
- * Because of legacy interfaces, "runlevel" and "sleeptime"
- * aren't in a separate struct in the union.
- *
- * The weird sizes are because init expects the whole
- * struct to be 384 bytes.
- */
-struct init_request {
- int magic; /* Magic number */
- int cmd; /* What kind of request */
- int runlevel; /* Runlevel to change to */
- int sleeptime; /* Time between TERM and KILL */
- union {
- struct init_request_bsd bsd;
- char data[368];
- } i;
-};
-
-#endif
diff --git a/src/core/job.c b/src/core/job.c
deleted file mode 100644
index f08b8cbc7d..0000000000
--- a/src/core/job.c
+++ /dev/null
@@ -1,1086 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <assert.h>
-#include <errno.h>
-#include <sys/timerfd.h>
-#include <sys/epoll.h>
-
-#include "systemd/sd-id128.h"
-#include "systemd/sd-messages.h"
-#include "set.h"
-#include "unit.h"
-#include "macro.h"
-#include "strv.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
-#include "log.h"
-#include "dbus-job.h"
-
-JobBusClient* job_bus_client_new(DBusConnection *connection, const char *name) {
- JobBusClient *cl;
- size_t name_len;
-
- name_len = strlen(name);
- cl = malloc0(sizeof(JobBusClient) + name_len + 1);
- if (!cl)
- return NULL;
-
- cl->bus = connection;
- memcpy(cl->name, name, name_len + 1);
- return cl;
-}
-
-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;
- j->timer_watch.type = WATCH_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) {
- JobBusClient *cl;
-
- 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(Job, run_queue, j->manager->run_queue, j);
-
- if (j->in_dbus_queue)
- LIST_REMOVE(Job, dbus_queue, j->manager->dbus_job_queue, j);
-
- if (j->timer_watch.type != WATCH_INVALID) {
- assert(j->timer_watch.type == WATCH_JOB_TIMER);
- assert(j->timer_watch.data.job == j);
- assert(j->timer_watch.fd >= 0);
-
- assert_se(epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_DEL, j->timer_watch.fd, NULL) >= 0);
- close_nointr_nofail(j->timer_watch.fd);
- }
-
- while ((cl = j->bus_client_list)) {
- LIST_REMOVE(JobBusClient, client, j->bus_client_list, cl);
- free(cl);
- }
- free(j);
-}
-
-void job_uninstall(Job *j) {
- Job **pj;
-
- assert(j->installed);
-
- pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
- assert(*pj == j);
-
- /* Detach from next 'bigger' objects */
-
- /* daemon-reload should be transparent to job observers */
- if (j->manager->n_reloading <= 0)
- bus_job_send_removed_signal(j);
-
- *pj = NULL;
-
- unit_add_to_gc_queue(j->unit);
-
- hashmap_remove(j->manager->jobs, UINT32_TO_PTR(j->id));
- j->installed = false;
-}
-
-static bool job_type_allows_late_merge(JobType t) {
- /* Tells whether it is OK to merge a job of type 't' with an already
- * running job.
- * Reloads cannot be merged this way. Think of the sequence:
- * 1. Reload of a daemon is in progress; the daemon has already loaded
- * its config file, but hasn't completed the reload operation yet.
- * 2. Edit foo's config file.
- * 3. Trigger another reload to have the daemon use the new config.
- * Should the second reload job be merged into the first one, the daemon
- * would not know about the new config.
- * JOB_RESTART jobs on the other hand can be merged, because they get
- * patched into JOB_START after stopping the unit. So if we see a
- * JOB_RESTART running, it means the unit hasn't stopped yet and at
- * this time the merge is still allowed. */
- return t != JOB_RELOAD;
-}
-
-static void job_merge_into_installed(Job *j, Job *other) {
- assert(j->installed);
- assert(j->unit == other->unit);
-
- if (j->type != JOB_NOP)
- job_type_merge_and_collapse(&j->type, other->type, j->unit);
- else
- assert(other->type == JOB_NOP);
-
- j->override = j->override || other->override;
-}
-
-Job* job_install(Job *j) {
- Job **pj;
- Job *uj;
-
- assert(!j->installed);
- assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
-
- pj = (j->type == JOB_NOP) ? &j->unit->nop_job : &j->unit->job;
- uj = *pj;
-
- if (uj) {
- if (j->type != JOB_NOP && job_type_is_conflicting(uj->type, j->type))
- job_finish_and_invalidate(uj, JOB_CANCELED, false);
- else {
- /* not conflicting, i.e. mergeable */
-
- if (j->type == JOB_NOP || 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_debug("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_debug("Merged into running job, re-running: %s/%s as %u",
- uj->unit->id, job_type_to_string(uj->type), (unsigned) uj->id);
- uj->state = JOB_WAITING;
- return uj;
- }
- }
- }
-
- /* Install the job */
- *pj = j;
- j->installed = true;
- j->manager->n_installed_jobs ++;
- log_debug("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_debug("Unit %s already has a job installed. Not installing deserialized job.", j->unit->id);
- return -EEXIST;
- }
- *pj = j;
- j->installed = true;
- log_debug("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(JobDependency, subject, subject->subject_list, l);
-
- LIST_PREPEND(JobDependency, object, object->object_list, l);
-
- return l;
-}
-
-void job_dependency_free(JobDependency *l) {
- assert(l);
-
- if (l->subject)
- LIST_REMOVE(JobDependency, subject, l->subject->subject_list, l);
-
- LIST_REMOVE(JobDependency, object, l->object->object_list, l);
-
- free(l);
-}
-
-void job_dump(Job *j, FILE*f, const char *prefix) {
- assert(j);
- assert(f);
-
- if (!prefix)
- prefix = "";
-
- fprintf(f,
- "%s-> Job %u:\n"
- "%s\tAction: %s -> %s\n"
- "%s\tState: %s\n"
- "%s\tForced: %s\n",
- prefix, j->id,
- prefix, j->unit->id, job_type_to_string(j->type),
- prefix, job_state_to_string(j->state),
- prefix, yes_no(j->override));
-}
-
-/*
- * 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 merged with C is the same as
- * A merged with C merged with B.
- *
- * 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;
-
- default:
- assert_not_reached("Invalid job type");
- }
-}
-
-void job_type_collapse(JobType *t, Unit *u) {
- UnitActiveState s;
-
- switch (*t) {
-
- case JOB_TRY_RESTART:
- s = unit_active_state(u);
- if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
- *t = JOB_NOP;
- else
- *t = JOB_RESTART;
- break;
-
- case JOB_RELOAD_OR_START:
- s = unit_active_state(u);
- if (UNIT_IS_INACTIVE_OR_DEACTIVATING(s))
- *t = JOB_START;
- else
- *t = JOB_RELOAD;
- break;
-
- default:
- ;
- }
-}
-
-int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u) {
- JobType t = job_type_lookup_merge(*a, b);
- if (t < 0)
- return -EEXIST;
- *a = t;
- job_type_collapse(a, u);
- return 0;
-}
-
-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. */
-
- /* First check if there is an override */
- if (j->ignore_order)
- return true;
-
- if (j->type == JOB_NOP)
- return true;
-
- if (j->type == JOB_START ||
- j->type == JOB_VERIFY_ACTIVE ||
- j->type == JOB_RELOAD) {
-
- /* Immediate result is that the job is or might be
- * started. In this case lets wait for the
- * dependencies, regardless whether they are
- * starting or stopping something. */
-
- SET_FOREACH(other, j->unit->dependencies[UNIT_AFTER], i)
- if (other->job)
- return false;
- }
-
- /* Also, if something else is being stopped and we should
- * change state after it, then lets wait. */
-
- SET_FOREACH(other, j->unit->dependencies[UNIT_BEFORE], i)
- if (other->job &&
- (other->job->type == JOB_STOP ||
- other->job->type == JOB_RESTART))
- return false;
-
- /* This means that for a service a and a service b where b
- * shall be started after a:
- *
- * start a + start b → 1st step start a, 2nd step start b
- * start a + stop b → 1st step stop b, 2nd step start a
- * stop a + start b → 1st step stop a, 2nd step start b
- * stop a + stop b → 1st step stop b, 2nd step stop a
- *
- * This has the side effect that restarts are properly
- * synchronized too. */
-
- return true;
-}
-
-static void job_change_type(Job *j, JobType newtype) {
- log_debug("Converting job %s/%s -> %s/%s",
- j->unit->id, job_type_to_string(j->type),
- j->unit->id, job_type_to_string(newtype));
-
- j->type = newtype;
-}
-
-int job_run_and_invalidate(Job *j) {
- int r;
- uint32_t id;
- Manager *m;
-
- assert(j);
- assert(j->installed);
- assert(j->type < _JOB_TYPE_MAX_IN_TRANSACTION);
- assert(j->in_run_queue);
-
- LIST_REMOVE(Job, 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;
-
- j->state = JOB_RUNNING;
- job_add_to_dbus_queue(j);
-
- /* While we execute this operation the job might go away (for
- * example: because it is replaced by a new, conflicting
- * job.) To make sure we don't access a freed job later on we
- * store the id here, so that we can verify the job is still
- * valid. */
- id = j->id;
- m = j->manager;
-
- switch (j->type) {
-
- case JOB_START:
- r = unit_start(j->unit);
-
- /* If this unit cannot be started, then simply wait */
- if (r == -EBADR)
- r = 0;
- break;
-
- case JOB_VERIFY_ACTIVE: {
- UnitActiveState t = unit_active_state(j->unit);
- if (UNIT_IS_ACTIVE_OR_RELOADING(t))
- r = -EALREADY;
- else if (t == UNIT_ACTIVATING)
- r = -EAGAIN;
- else
- r = -ENOEXEC;
- break;
- }
-
- case JOB_STOP:
- case JOB_RESTART:
- r = unit_stop(j->unit);
-
- /* If this unit cannot stopped, then simply wait. */
- if (r == -EBADR)
- r = 0;
- break;
-
- case JOB_RELOAD:
- r = unit_reload(j->unit);
- break;
-
- case JOB_NOP:
- r = -EALREADY;
- break;
-
- default:
- assert_not_reached("Unknown job type");
- }
-
- j = manager_get_job(m, id);
- if (j) {
- if (r == -EALREADY)
- r = job_finish_and_invalidate(j, JOB_DONE, true);
- else if (r == -ENOEXEC)
- r = job_finish_and_invalidate(j, JOB_SKIPPED, true);
- else if (r == -EAGAIN)
- j->state = JOB_WAITING;
- else if (r < 0)
- r = job_finish_and_invalidate(j, JOB_FAILED, true);
- }
-
- return r;
-}
-
-static const char *job_get_status_message_format(Unit *u, JobType t, JobResult result) {
- const UnitStatusMessageFormats *format_table;
-
- assert(u);
- assert(t >= 0);
- assert(t < _JOB_TYPE_MAX);
-
- format_table = &UNIT_VTABLE(u)->status_message_formats;
- if (!format_table)
- return NULL;
-
- if (t == JOB_START)
- return format_table->finished_start_job[result];
- else if (t == JOB_STOP || t == JOB_RESTART)
- return format_table->finished_stop_job[result];
-
- return NULL;
-}
-
-static const char *job_get_status_message_format_try_harder(Unit *u, JobType t, JobResult result) {
- const char *format;
-
- assert(u);
- assert(t >= 0);
- assert(t < _JOB_TYPE_MAX);
-
- format = job_get_status_message_format(u, t, result);
- if (format)
- return format;
-
- /* Return generic strings */
- if (t == JOB_START) {
- if (result == JOB_DONE)
- return "Started %s.";
- else if (result == JOB_FAILED)
- return "Failed to start %s.";
- else if (result == JOB_DEPENDENCY)
- return "Dependency failed for %s.";
- else if (result == JOB_TIMEOUT)
- return "Timed out starting %s.";
- } else if (t == JOB_STOP || t == JOB_RESTART) {
- if (result == JOB_DONE)
- return "Stopped %s.";
- else if (result == JOB_FAILED)
- return "Stopped (with error) %s.";
- else if (result == JOB_TIMEOUT)
- return "Timed out stoppping %s.";
- } else if (t == JOB_RELOAD) {
- if (result == JOB_DONE)
- return "Reloaded %s.";
- else if (result == JOB_FAILED)
- return "Reload failed for %s.";
- else if (result == JOB_TIMEOUT)
- return "Timed out reloading %s.";
- }
-
- return NULL;
-}
-
-static void job_print_status_message(Unit *u, JobType t, JobResult result) {
- const char *format;
-
- assert(u);
- assert(t >= 0);
- assert(t < _JOB_TYPE_MAX);
-
- if (t == JOB_START) {
- format = job_get_status_message_format(u, t, result);
- if (!format)
- return;
-
- switch (result) {
-
- case JOB_DONE:
- if (u->condition_result)
- unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, format, unit_description(u));
- break;
-
- case JOB_FAILED:
- unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON "FAILED" ANSI_HIGHLIGHT_OFF, format, unit_description(u));
- unit_status_printf(u, NULL, "See 'systemctl status %s' for details.", u->id);
- break;
-
- case JOB_DEPENDENCY:
- unit_status_printf(u, ANSI_HIGHLIGHT_YELLOW_ON "DEPEND" ANSI_HIGHLIGHT_OFF, format, unit_description(u));
- break;
-
- case JOB_TIMEOUT:
- unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format, unit_description(u));
- break;
-
- default:
- ;
- }
-
- } else if (t == JOB_STOP || t == JOB_RESTART) {
-
- format = job_get_status_message_format(u, t, result);
- if (!format)
- return;
-
- switch (result) {
-
- case JOB_TIMEOUT:
- unit_status_printf(u, ANSI_HIGHLIGHT_RED_ON " TIME " ANSI_HIGHLIGHT_OFF, format, unit_description(u));
- break;
-
- case JOB_DONE:
- case JOB_FAILED:
- unit_status_printf(u, ANSI_HIGHLIGHT_GREEN_ON " OK " ANSI_HIGHLIGHT_OFF, format, unit_description(u));
- break;
-
- default:
- ;
- }
-
- } else if (t == JOB_VERIFY_ACTIVE) {
-
- /* When verify-active detects the unit is inactive, report it.
- * Most likely a DEPEND warning from a requisiting unit will
- * occur next and it's nice to see what was requisited. */
- if (result == JOB_SKIPPED)
- unit_status_printf(u, ANSI_HIGHLIGHT_ON " INFO " ANSI_HIGHLIGHT_OFF, "%s is not active.", unit_description(u));
- }
-}
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wformat-nonliteral"
-static void job_log_status_message(Unit *u, JobType t, JobResult result) {
- const char *format;
- char buf[LINE_MAX];
-
- assert(u);
- assert(t >= 0);
- assert(t < _JOB_TYPE_MAX);
-
- /* Skip this if it goes to the console. since we already print
- * to the console anyway... */
-
- if (log_on_console())
- return;
-
- format = job_get_status_message_format_try_harder(u, t, result);
- if (!format)
- return;
-
- snprintf(buf, sizeof(buf), format, unit_description(u));
- char_array_0(buf);
-
- if (t == JOB_START) {
- sd_id128_t mid;
-
- mid = result == JOB_DONE ? SD_MESSAGE_UNIT_STARTED : SD_MESSAGE_UNIT_FAILED;
- log_struct(result == JOB_DONE ? LOG_INFO : LOG_ERR,
- MESSAGE_ID(mid),
- "UNIT=%s", u->id,
- "RESULT=%s", job_result_to_string(result),
- "MESSAGE=%s", buf,
- NULL);
-
- } else if (t == JOB_STOP)
- log_struct(result == JOB_DONE ? LOG_INFO : LOG_ERR,
- MESSAGE_ID(SD_MESSAGE_UNIT_STOPPED),
- "UNIT=%s", u->id,
- "RESULT=%s", job_result_to_string(result),
- "MESSAGE=%s", buf,
- NULL);
-
- else if (t == JOB_RELOAD)
- log_struct(result == JOB_DONE ? LOG_INFO : LOG_ERR,
- MESSAGE_ID(SD_MESSAGE_UNIT_RELOADED),
- "UNIT=%s", u->id,
- "RESULT=%s", job_result_to_string(result),
- "MESSAGE=%s", buf,
- NULL);
-}
-#pragma GCC diagnostic pop
-
-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_debug("Job %s/%s finished, result=%s", u->id, job_type_to_string(t), job_result_to_string(result));
-
- job_print_status_message(u, t, result);
- job_log_status_message(u, t, result);
-
- job_add_to_dbus_queue(j);
-
- /* Patch restart jobs so that they become normal start jobs */
- if (result == JOB_DONE && t == JOB_RESTART) {
-
- job_change_type(j, JOB_START);
- j->state = JOB_WAITING;
-
- job_add_to_run_queue(j);
-
- goto finish;
- }
-
- if (result == JOB_FAILED)
- j->manager->n_failed_jobs ++;
-
- job_uninstall(j);
- job_free(j);
-
- /* Fail depending jobs on failure */
- if (result != JOB_DONE && recursive) {
-
- if (t == JOB_START ||
- t == JOB_VERIFY_ACTIVE) {
-
- SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i)
- if (other->job &&
- (other->job->type == JOB_START ||
- other->job->type == JOB_VERIFY_ACTIVE))
- job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true);
-
- SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
- if (other->job &&
- (other->job->type == JOB_START ||
- other->job->type == JOB_VERIFY_ACTIVE))
- job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true);
-
- SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
- if (other->job &&
- !other->job->override &&
- (other->job->type == JOB_START ||
- other->job->type == JOB_VERIFY_ACTIVE))
- job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true);
-
- } else if (t == JOB_STOP) {
-
- SET_FOREACH(other, u->dependencies[UNIT_CONFLICTED_BY], i)
- if (other->job &&
- (other->job->type == JOB_START ||
- other->job->type == JOB_VERIFY_ACTIVE))
- job_finish_and_invalidate(other->job, JOB_DEPENDENCY, true);
- }
- }
-
- /* Trigger OnFailure dependencies that are not generated by
- * the unit itself. We don't tread 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_notice("Job %s/%s failed with result '%s'.",
- u->id,
- job_type_to_string(t),
- job_result_to_string(result));
-
- unit_trigger_on_failure(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;
-}
-
-int job_start_timer(Job *j) {
- struct itimerspec its;
- struct epoll_event ev;
- int fd, r;
- assert(j);
-
- if (j->unit->job_timeout <= 0 ||
- j->timer_watch.type == WATCH_JOB_TIMER)
- return 0;
-
- assert(j->timer_watch.type == WATCH_INVALID);
-
- if ((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0) {
- r = -errno;
- goto fail;
- }
-
- zero(its);
- timespec_store(&its.it_value, j->unit->job_timeout);
-
- if (timerfd_settime(fd, 0, &its, NULL) < 0) {
- r = -errno;
- goto fail;
- }
-
- zero(ev);
- ev.data.ptr = &j->timer_watch;
- ev.events = EPOLLIN;
-
- if (epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0) {
- r = -errno;
- goto fail;
- }
-
- j->timer_watch.type = WATCH_JOB_TIMER;
- j->timer_watch.fd = fd;
- j->timer_watch.data.job = j;
-
- return 0;
-
-fail:
- if (fd >= 0)
- close_nointr_nofail(fd);
-
- return r;
-}
-
-void job_add_to_run_queue(Job *j) {
- assert(j);
- assert(j->installed);
-
- if (j->in_run_queue)
- return;
-
- LIST_PREPEND(Job, 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(Job, 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/%lu", (unsigned long) j->id) < 0)
- return NULL;
-
- return p;
-}
-
-void job_timer_event(Job *j, uint64_t n_elapsed, Watch *w) {
- assert(j);
- assert(w == &j->timer_watch);
-
- log_warning("Job %s/%s timed out.", j->unit->id, job_type_to_string(j->type));
- job_finish_and_invalidate(j, JOB_TIMEOUT, true);
-}
-
-int job_serialize(Job *j, FILE *f, FDSet *fds) {
- fprintf(f, "job-id=%u\n", j->id);
- fprintf(f, "job-type=%s\n", job_type_to_string(j->type));
- fprintf(f, "job-state=%s\n", job_state_to_string(j->state));
- fprintf(f, "job-override=%s\n", yes_no(j->override));
- fprintf(f, "job-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));
- /* Cannot save bus clients. Just note the fact that we're losing
- * them. job_send_message() will fallback to broadcasting. */
- fprintf(f, "job-forgot-bus-clients=%s\n",
- yes_no(j->forgot_bus_clients || j->bus_client_list));
- if (j->timer_watch.type == WATCH_JOB_TIMER) {
- int copy = fdset_put_dup(fds, j->timer_watch.fd);
- if (copy < 0)
- return copy;
- fprintf(f, "job-timer-watch-fd=%d\n", copy);
- }
-
- /* End marker */
- fputc('\n', f);
- return 0;
-}
-
-int job_deserialize(Job *j, FILE *f, FDSet *fds) {
- 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 = 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 = job_state_from_string(v);
- if (s < 0)
- log_debug("Failed to parse job state %s", v);
- else
- j->state = s;
- } else if (streq(l, "job-override")) {
- int b = parse_boolean(v);
- if (b < 0)
- log_debug("Failed to parse job override flag %s", v);
- else
- j->override = j->override || b;
- } else if (streq(l, "job-sent-dbus-new-signal")) {
- int 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 = 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-forgot-bus-clients")) {
- int b = parse_boolean(v);
- if (b < 0)
- log_debug("Failed to parse job forgot_bus_clients flag %s", v);
- else
- j->forgot_bus_clients = j->forgot_bus_clients || b;
- } else if (streq(l, "job-timer-watch-fd")) {
- int fd;
- if (safe_atoi(v, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
- log_debug("Failed to parse job-timer-watch-fd value %s", v);
- else {
- if (j->timer_watch.type == WATCH_JOB_TIMER)
- close_nointr_nofail(j->timer_watch.fd);
-
- j->timer_watch.type = WATCH_JOB_TIMER;
- j->timer_watch.fd = fdset_remove(fds, fd);
- j->timer_watch.data.job = j;
- }
- }
- }
-}
-
-int job_coldplug(Job *j) {
- struct epoll_event ev;
-
- if (j->timer_watch.type != WATCH_JOB_TIMER)
- return 0;
-
- zero(ev);
- ev.data.ptr = &j->timer_watch;
- ev.events = EPOLLIN;
-
- if (epoll_ctl(j->manager->epoll_fd, EPOLL_CTL_ADD, j->timer_watch.fd, &ev) < 0)
- return -errno;
-
- return 0;
-}
-
-static const char* const job_state_table[_JOB_STATE_MAX] = {
- [JOB_WAITING] = "waiting",
- [JOB_RUNNING] = "running"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(job_state, JobState);
-
-static const char* const job_type_table[_JOB_TYPE_MAX] = {
- [JOB_START] = "start",
- [JOB_VERIFY_ACTIVE] = "verify-active",
- [JOB_STOP] = "stop",
- [JOB_RELOAD] = "reload",
- [JOB_RELOAD_OR_START] = "reload-or-start",
- [JOB_RESTART] = "restart",
- [JOB_TRY_RESTART] = "try-restart",
- [JOB_NOP] = "nop",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(job_type, JobType);
-
-static const char* const job_mode_table[_JOB_MODE_MAX] = {
- [JOB_FAIL] = "fail",
- [JOB_REPLACE] = "replace",
- [JOB_ISOLATE] = "isolate",
- [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"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(job_result, JobResult);
diff --git a/src/core/job.h b/src/core/job.h
deleted file mode 100644
index 3aa49d4b46..0000000000
--- a/src/core/job.h
+++ /dev/null
@@ -1,230 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-#include <inttypes.h>
-#include <errno.h>
-
-typedef struct Job Job;
-typedef struct JobDependency JobDependency;
-typedef struct JobBusClient JobBusClient;
-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, it won't have to merge with anything.
- * job_install() avoids the problem of merging JOB_NOP too (it's
- * special-cased, only merges with other JOB_NOPs). */
- JOB_NOP = _JOB_TYPE_MAX_MERGING, /* do nothing */
-
- _JOB_TYPE_MAX_IN_TRANSACTION,
-
- /* JOB_TRY_RESTART can never appear in a transaction, because
- * it always collapses into JOB_RESTART or JOB_NOP before entering.
- * Thus we never need to merge it with anything. */
- JOB_TRY_RESTART = _JOB_TYPE_MAX_IN_TRANSACTION, /* if running, stop and then start */
-
- /* JOB_RELOAD_OR_START won't enter into a transaction and cannot result
- * from transaction merging (there's no way for JOB_RELOAD and
- * JOB_START to meet in one transaction). It can result from a merge
- * during job installation, but then it will immediately collapse into
- * one of the two simpler types. */
- JOB_RELOAD_OR_START, /* if running, reload, otherwise start */
-
- _JOB_TYPE_MAX,
- _JOB_TYPE_INVALID = -1
-};
-
-enum JobState {
- JOB_WAITING,
- JOB_RUNNING,
- _JOB_STATE_MAX,
- _JOB_STATE_INVALID = -1
-};
-
-enum JobMode {
- JOB_FAIL, /* Fail if a conflicting job is already queued */
- JOB_REPLACE, /* Replace an existing conflicting job */
- JOB_ISOLATE, /* Start a unit, and stop all others */
- 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, /* JobTimeout elapsed */
- JOB_FAILED, /* Job failed */
- JOB_DEPENDENCY, /* A required dependency job did not result in JOB_DONE */
- JOB_SKIPPED, /* JOB_RELOAD of inactive unit; negative result of JOB_VERIFY_ACTIVE */
- _JOB_RESULT_MAX,
- _JOB_RESULT_INVALID = -1
-};
-
-#include "manager.h"
-#include "unit.h"
-#include "hashmap.h"
-#include "list.h"
-
-struct JobDependency {
- /* Encodes that the 'subject' job needs the 'object' job in
- * some way. This structure is used only while building a transaction. */
- Job *subject;
- Job *object;
-
- LIST_FIELDS(JobDependency, subject);
- LIST_FIELDS(JobDependency, object);
-
- bool matters;
- bool conflicts;
-};
-
-struct JobBusClient {
- LIST_FIELDS(JobBusClient, client);
- /* Note that this bus object is not ref counted here. */
- DBusConnection *bus;
- char name[0];
-};
-
-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;
-
- Watch timer_watch;
-
- /* There can be more than one client, because of job merging. */
- LIST_HEAD(JobBusClient, bus_client_list);
-
- JobResult result;
-
- bool installed:1;
- bool in_run_queue:1;
- bool matters_to_anchor:1;
- bool override:1;
- bool in_dbus_queue:1;
- bool sent_dbus_new_signal:1;
- bool ignore_order:1;
- bool forgot_bus_clients:1;
-};
-
-JobBusClient* job_bus_client_new(DBusConnection *connection, const char *name);
-
-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);
-
-static inline bool job_type_is_mergeable(JobType a, JobType b) {
- return job_type_lookup_merge(a, b) >= 0;
-}
-
-static inline bool job_type_is_conflicting(JobType a, JobType b) {
- return !job_type_is_mergeable(a, b);
-}
-
-static inline bool job_type_is_superset(JobType a, JobType b) {
- /* Checks whether operation a is a "superset" of b in its actions */
- return a == job_type_lookup_merge(a, b);
-}
-
-bool job_type_is_redundant(JobType a, UnitActiveState b);
-
-/* Collapses a state-dependent job type into a simpler type by observing
- * the state of the unit which it is going to be applied to. */
-void job_type_collapse(JobType *t, Unit *u);
-
-int job_type_merge_and_collapse(JobType *a, JobType b, Unit *u);
-
-bool job_is_runnable(Job *j);
-
-void job_add_to_run_queue(Job *j);
-void job_add_to_dbus_queue(Job *j);
-
-int job_start_timer(Job *j);
-void job_timer_event(Job *j, uint64_t n_elapsed, Watch *w);
-
-int job_run_and_invalidate(Job *j);
-int job_finish_and_invalidate(Job *j, JobResult result, bool recursive);
-
-char *job_dbus_path(Job *j);
-
-const char* job_type_to_string(JobType t);
-JobType job_type_from_string(const char *s);
-
-const char* job_state_to_string(JobState t);
-JobState job_state_from_string(const char *s);
-
-const char* job_mode_to_string(JobMode t);
-JobMode job_mode_from_string(const char *s);
-
-const char* job_result_to_string(JobResult t);
-JobResult job_result_from_string(const char *s);
diff --git a/src/core/kill.c b/src/core/kill.c
deleted file mode 100644
index 0775653f73..0000000000
--- a/src/core/kill.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2012 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <string.h>
-
-#include "kill.h"
-#include "util.h"
-
-void kill_context_init(KillContext *c) {
- assert(c);
-
- c->kill_signal = SIGTERM;
- c->send_sigkill = true;
-}
-
-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",
- prefix, kill_mode_to_string(c->kill_mode),
- prefix, signal_to_string(c->kill_signal),
- prefix, yes_no(c->send_sigkill));
-}
-
-static const char* const kill_mode_table[_KILL_MODE_MAX] = {
- [KILL_CONTROL_GROUP] = "control-group",
- [KILL_PROCESS] = "process",
- [KILL_NONE] = "none"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(kill_mode, KillMode);
-
-static const char* const kill_who_table[_KILL_WHO_MAX] = {
- [KILL_MAIN] = "main",
- [KILL_CONTROL] = "control",
- [KILL_ALL] = "all"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(kill_who, KillWho);
diff --git a/src/core/kill.h b/src/core/kill.h
deleted file mode 100644
index 3c9b0ab8db..0000000000
--- a/src/core/kill.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2012 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct KillContext KillContext;
-
-#include <stdbool.h>
-#include <stdio.h>
-
-typedef enum KillMode {
- /* The kill mode is a property of a unit. */
- KILL_CONTROL_GROUP = 0,
- KILL_PROCESS,
- KILL_NONE,
- _KILL_MODE_MAX,
- _KILL_MODE_INVALID = -1
-} KillMode;
-
-struct KillContext {
- KillMode kill_mode;
- int kill_signal;
- bool send_sigkill;
-};
-
-typedef enum KillWho {
- /* Kill who is a property of an operation */
- KILL_MAIN,
- KILL_CONTROL,
- KILL_ALL,
- _KILL_WHO_MAX,
- _KILL_WHO_INVALID = -1
-} KillWho;
-
-void kill_context_init(KillContext *c);
-void kill_context_dump(KillContext *c, FILE *f, const char *prefix);
-
-const char *kill_mode_to_string(KillMode k);
-KillMode kill_mode_from_string(const char *s);
-
-const char *kill_who_to_string(KillWho k);
-KillWho kill_who_from_string(const char *s);
diff --git a/src/core/killall.c b/src/core/killall.c
deleted file mode 100644
index 55200ffa48..0000000000
--- a/src/core/killall.c
+++ /dev/null
@@ -1,177 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 ProFUSION embedded systems
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/wait.h>
-#include <signal.h>
-#include <errno.h>
-
-#include "util.h"
-#include "def.h"
-#include "killall.h"
-
-#define TIMEOUT_USEC (5 * USEC_PER_SEC)
-
-static bool ignore_proc(pid_t pid) {
- char buf[PATH_MAX];
- FILE *f;
- char c;
- 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;
-
- snprintf(buf, sizeof(buf), "/proc/%lu/cmdline", (unsigned long) pid);
- char_array_0(buf);
-
- f = fopen(buf, "re");
- if (!f)
- return true; /* not really, but has the desired effect */
-
- count = fread(&c, 1, 1, f);
- fclose(f);
-
- /* Kernel threads have an empty cmdline */
- if (count <= 0)
- return true;
-
- /* Processes with argv[0][0] = '@' we ignore from the killing
- * spree.
- *
- * http://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons */
- if (count == 1 && c == '@')
- return true;
-
- return false;
-}
-
-static void wait_for_children(int n_processes, sigset_t *mask) {
- usec_t until;
-
- assert(mask);
-
- until = now(CLOCK_MONOTONIC) + TIMEOUT_USEC;
- for (;;) {
- struct timespec ts;
- int k;
- usec_t n;
-
- for (;;) {
- pid_t pid = waitpid(-1, NULL, WNOHANG);
-
- if (pid == 0)
- break;
-
- if (pid < 0 && errno == ECHILD)
- return;
-
- if (n_processes > 0)
- if (--n_processes == 0)
- return;
- }
-
- n = now(CLOCK_MONOTONIC);
- if (n >= until)
- return;
-
- timespec_store(&ts, until - n);
-
- if ((k = sigtimedwait(mask, NULL, &ts)) != SIGCHLD) {
-
- if (k < 0 && errno != EAGAIN) {
- log_error("sigtimedwait() failed: %m");
- return;
- }
-
- if (k >= 0)
- log_warning("sigtimedwait() returned unexpected signal.");
- }
- }
-}
-
-static int killall(int sig) {
- DIR *dir;
- struct dirent *d;
- unsigned int n_processes = 0;
-
- dir = opendir("/proc");
- if (!dir)
- return -errno;
-
- while ((d = readdir(dir))) {
- pid_t pid;
-
- if (d->d_type != DT_DIR &&
- d->d_type != DT_UNKNOWN)
- continue;
-
- if (parse_pid(d->d_name, &pid) < 0)
- continue;
-
- if (ignore_proc(pid))
- continue;
-
- if (kill(pid, sig) >= 0)
- n_processes++;
- else if (errno != ENOENT)
- log_warning("Could not kill %d: %m", pid);
- }
-
- closedir(dir);
-
- return n_processes;
-}
-
-void broadcast_signal(int sig, bool wait_for_exit) {
- sigset_t mask, oldmask;
- int n_processes;
-
- 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("kill(-1, SIGSTOP) failed: %m");
-
- n_processes = killall(sig);
-
- if (kill(-1, SIGCONT) < 0 && errno != ESRCH)
- log_warning("kill(-1, SIGCONT) failed: %m");
-
- if (n_processes <= 0)
- goto finish;
-
- if (wait_for_exit)
- wait_for_children(n_processes, &mask);
-
-finish:
- sigprocmask(SIG_SETMASK, &oldmask, NULL);
-}
diff --git a/src/core/killall.h b/src/core/killall.h
deleted file mode 100644
index d08ac142f0..0000000000
--- a/src/core/killall.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef fookillallhfoo
-#define fookillallhfoo
-
-/***
- 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);
-
-#endif
diff --git a/src/core/kmod-setup.c b/src/core/kmod-setup.c
deleted file mode 100644
index 20ab232374..0000000000
--- a/src/core/kmod-setup.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/wait.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <libkmod.h>
-
-#include "macro.h"
-#include "execute.h"
-
-#include "kmod-setup.h"
-
-typedef struct Kmodule {
- const char *name;
- const char *directory;
- bool (*condition_fn)(void);
-} KModule;
-
-static const KModule kmod_table[] = {
- { "autofs4", "/sys/class/misc/autofs", NULL } ,
- { "ipv6", "/sys/module/ipv6", NULL },
- { "unix", "/proc/net/unix", NULL } ,
-};
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wformat-nonliteral"
-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 */
- log_metav(LOG_DEBUG, file, line, fn, format, args);
-}
-#pragma GCC diagnostic pop
-
-int kmod_setup(void) {
- unsigned i;
- struct kmod_ctx *ctx = NULL;
- struct kmod_module *mod;
- int err;
-
- for (i = 0; i < ELEMENTSOF(kmod_table); i += 2) {
- if (kmod_table[i].condition_fn && !kmod_table[i].condition_fn())
- continue;
-
- if (access(kmod_table[i].directory, F_OK) >= 0)
- continue;
-
- 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].name);
-
- if (!ctx) {
- ctx = kmod_new(NULL, NULL);
- if (!ctx) {
- log_error("Failed to allocate memory for kmod");
- return -ENOMEM;
- }
-
- kmod_set_log_fn(ctx, systemd_kmod_log, NULL);
- kmod_load_resources(ctx);
- }
-
- err = kmod_module_new_from_name(ctx, kmod_table[i].name, &mod);
- if (err < 0) {
- log_error("Failed to lookup module '%s'", kmod_table[i].name);
- continue;
- }
-
- err = kmod_module_probe_insert_module(mod, KMOD_PROBE_APPLY_BLACKLIST, NULL, NULL, NULL, NULL);
- if (err == 0)
- log_info("Inserted module '%s'", kmod_module_get_name(mod));
- else if (err == KMOD_PROBE_APPLY_BLACKLIST)
- log_info("Module '%s' is blacklisted", kmod_module_get_name(mod));
- else
- log_error("Failed to insert module '%s'", kmod_module_get_name(mod));
-
- kmod_module_unref(mod);
- }
-
- if (ctx)
- kmod_unref(ctx);
-
- return 0;
-}
diff --git a/src/core/kmod-setup.h b/src/core/kmod-setup.h
deleted file mode 100644
index 24dcdddfa4..0000000000
--- a/src/core/kmod-setup.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-int kmod_setup(void);
diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c
deleted file mode 100644
index 86f81c7484..0000000000
--- a/src/core/load-dropin.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dirent.h>
-#include <errno.h>
-
-#include "unit.h"
-#include "load-dropin.h"
-#include "log.h"
-#include "strv.h"
-#include "unit-name.h"
-
-static int iterate_dir(Unit *u, const char *path, UnitDependency dependency) {
- DIR *d;
- struct dirent *de;
- int r;
-
- assert(u);
- assert(path);
-
- d = opendir(path);
- if (!d) {
-
- if (errno == ENOENT)
- return 0;
-
- return -errno;
- }
-
- while ((de = readdir(d))) {
- char *f;
-
- if (ignore_file(de->d_name))
- continue;
-
- f = strjoin(path, "/", de->d_name, NULL);
- if (!f) {
- r = -ENOMEM;
- goto finish;
- }
-
- r = unit_add_dependency_by_name(u, dependency, de->d_name, f, true);
- free(f);
-
- if (r < 0)
- log_error("Cannot add dependency %s to %s, ignoring: %s", de->d_name, u->id, strerror(-r));
- }
-
- r = 0;
-
-finish:
- closedir(d);
- return r;
-}
-
-static int process_dir(Unit *u, const char *unit_path, const char *name, const char *suffix, UnitDependency dependency) {
- int r;
- char *path;
-
- assert(u);
- assert(unit_path);
- assert(name);
- assert(suffix);
-
- path = strjoin(unit_path, "/", name, suffix, NULL);
- if (!path)
- return -ENOMEM;
-
- if (u->manager->unit_path_cache &&
- !set_get(u->manager->unit_path_cache, path))
- r = 0;
- else
- r = iterate_dir(u, path, dependency);
- free(path);
-
- if (r < 0)
- return r;
-
- if (u->instance) {
- char *template;
- /* Also try the template dir */
-
- template = unit_name_template(name);
- if (!template)
- return -ENOMEM;
-
- path = strjoin(unit_path, "/", template, suffix, NULL);
- free(template);
-
- if (!path)
- return -ENOMEM;
-
- if (u->manager->unit_path_cache &&
- !set_get(u->manager->unit_path_cache, path))
- r = 0;
- else
- r = iterate_dir(u, path, dependency);
- free(path);
-
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-int unit_load_dropin(Unit *u) {
- Iterator i;
- char *t;
-
- 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) {
- int r;
-
- r = process_dir(u, *p, t, ".wants", UNIT_WANTS);
- if (r < 0)
- return r;
-
- r = process_dir(u, *p, t, ".requires", UNIT_REQUIRES);
- if (r < 0)
- return r;
- }
- }
-
- return 0;
-}
diff --git a/src/core/load-dropin.h b/src/core/load-dropin.h
deleted file mode 100644
index 1d2fafeee6..0000000000
--- a/src/core/load-dropin.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "unit.h"
-
-/* Read service data supplementary drop-in directories */
-
-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 0c5ccebd73..0000000000
--- a/src/core/load-fragment-gperf.gperf.m4
+++ /dev/null
@@ -1,255 +0,0 @@
-%{
-#include <stddef.h>
-#include "conf-parser.h"
-#include "load-fragment.h"
-#include "missing.h"
-%}
-struct ConfigPerfItem;
-%null_strings
-%language=ANSI-C
-%define slot-name section_and_lvalue
-%define hash-function-name load_fragment_gperf_hash
-%define lookup-function-name load_fragment_gperf_lookup
-%readonly-tables
-%omit-struct-type
-%struct-type
-%includes
-%%
-m4_dnl Define the context options only once
-m4_define(`EXEC_CONTEXT_CONFIG_ITEMS',
-`$1.WorkingDirectory, config_parse_unit_path_printf, 0, offsetof($1, exec_context.working_directory)
-$1.RootDirectory, config_parse_unit_path_printf, 0, offsetof($1, exec_context.root_directory)
-$1.User, config_parse_unit_string_printf, 0, offsetof($1, exec_context.user)
-$1.Group, config_parse_unit_string_printf, 0, offsetof($1, exec_context.group)
-$1.SupplementaryGroups, config_parse_strv, 0, offsetof($1, exec_context.supplementary_groups)
-$1.Nice, config_parse_exec_nice, 0, offsetof($1, exec_context)
-$1.OOMScoreAdjust, config_parse_exec_oom_score_adjust, 0, offsetof($1, exec_context)
-$1.IOSchedulingClass, config_parse_exec_io_class, 0, offsetof($1, exec_context)
-$1.IOSchedulingPriority, config_parse_exec_io_priority, 0, offsetof($1, exec_context)
-$1.CPUSchedulingPolicy, config_parse_exec_cpu_sched_policy, 0, offsetof($1, exec_context)
-$1.CPUSchedulingPriority, config_parse_exec_cpu_sched_prio, 0, offsetof($1, exec_context)
-$1.CPUSchedulingResetOnFork, config_parse_bool, 0, offsetof($1, exec_context.cpu_sched_reset_on_fork)
-$1.CPUAffinity, config_parse_exec_cpu_affinity, 0, offsetof($1, exec_context)
-$1.UMask, config_parse_mode, 0, offsetof($1, exec_context.umask)
-$1.Environment, config_parse_unit_strv_printf, 0, offsetof($1, exec_context.environment)
-$1.EnvironmentFile, config_parse_unit_env_file, 0, offsetof($1, exec_context.environment_files)
-$1.StandardInput, config_parse_input, 0, offsetof($1, exec_context.std_input)
-$1.StandardOutput, config_parse_output, 0, offsetof($1, exec_context.std_output)
-$1.StandardError, config_parse_output, 0, offsetof($1, exec_context.std_error)
-$1.TTYPath, config_parse_unit_path_printf, 0, offsetof($1, exec_context.tty_path)
-$1.TTYReset, config_parse_bool, 0, offsetof($1, exec_context.tty_reset)
-$1.TTYVHangup, config_parse_bool, 0, offsetof($1, exec_context.tty_vhangup)
-$1.TTYVTDisallocate, config_parse_bool, 0, offsetof($1, exec_context.tty_vt_disallocate)
-$1.SyslogIdentifier, config_parse_unit_string_printf, 0, offsetof($1, exec_context.syslog_identifier)
-$1.SyslogFacility, config_parse_facility, 0, offsetof($1, exec_context.syslog_priority)
-$1.SyslogLevel, config_parse_level, 0, offsetof($1, exec_context.syslog_priority)
-$1.SyslogLevelPrefix, config_parse_bool, 0, offsetof($1, exec_context.syslog_level_prefix)
-$1.Capabilities, config_parse_exec_capabilities, 0, offsetof($1, exec_context)
-$1.SecureBits, config_parse_exec_secure_bits, 0, offsetof($1, exec_context)
-$1.CapabilityBoundingSet, config_parse_bounding_set, 0, offsetof($1, exec_context.capability_bounding_set_drop)
-$1.TimerSlackNSec, config_parse_nsec, 0, offsetof($1, exec_context.timer_slack_nsec)
-$1.NoNewPrivileges config_parse_bool, 0, offsetof($1, exec_context.no_new_privileges)
-$1.SystemCallFilter, config_parse_syscall_filter, 0, offsetof($1, exec_context)
-$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.ControlGroup, config_parse_unit_cgroup, 0, 0
-$1.ControlGroupAttribute, config_parse_unit_cgroup_attr, 0, 0
-$1.CPUShares, config_parse_unit_cpu_shares, 0, 0
-$1.MemoryLimit, config_parse_unit_memory_limit, 0, 0
-$1.MemorySoftLimit, config_parse_unit_memory_limit, 0, 0
-$1.DeviceAllow, config_parse_unit_device_allow, 0, 0
-$1.DeviceDeny, config_parse_unit_device_allow, 0, 0
-$1.BlockIOWeight, config_parse_unit_blkio_weight, 0, 0
-$1.BlockIOReadBandwidth, config_parse_unit_blkio_bandwidth, 0, 0
-$1.BlockIOWriteBandwidth, config_parse_unit_blkio_bandwidth, 0, 0
-$1.ReadWriteDirectories, config_parse_path_strv, 0, offsetof($1, exec_context.read_write_dirs)
-$1.ReadOnlyDirectories, config_parse_path_strv, 0, offsetof($1, exec_context.read_only_dirs)
-$1.InaccessibleDirectories, config_parse_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.MountFlags, config_parse_exec_mount_flags, 0, offsetof($1, exec_context)
-$1.TCPWrapName, config_parse_unit_string_printf, 0, offsetof($1, exec_context.tcpwrap_name)
-$1.PAMName, config_parse_unit_string_printf, 0, offsetof($1, exec_context.pam_name)
-$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.ControlGroupModify, config_parse_bool, 0, offsetof($1, exec_context.control_group_modify)
-$1.ControlGroupPersistent, config_parse_tristate, 0, offsetof($1, exec_context.control_group_persistent)'
-)m4_dnl
-m4_define(`KILL_CONTEXT_CONFIG_ITEMS',
-`$1.SendSIGKILL, config_parse_bool, 0, offsetof($1, kill_context.send_sigkill)
-$1.KillMode, config_parse_kill_mode, 0, offsetof($1, kill_context.kill_mode)
-$1.KillSignal, config_parse_kill_signal, 0, offsetof($1, kill_context.kill_signal)'
-)m4_dnl
-Unit.Description, config_parse_unit_string_printf, 0, offsetof(Unit, description)
-Unit.Documentation, config_parse_documentation, 0, offsetof(Unit, documentation)
-Unit.SourcePath, config_parse_path, 0, offsetof(Unit, source_path)
-Unit.Requires, config_parse_unit_deps, UNIT_REQUIRES, 0
-Unit.RequiresOverridable, config_parse_unit_deps, UNIT_REQUIRES_OVERRIDABLE, 0
-Unit.Requisite, config_parse_unit_deps, UNIT_REQUISITE, 0
-Unit.RequisiteOverridable, config_parse_unit_deps, UNIT_REQUISITE_OVERRIDABLE, 0
-Unit.Wants, config_parse_unit_deps, UNIT_WANTS, 0
-Unit.BindsTo, config_parse_unit_deps, UNIT_BINDS_TO, 0
-Unit.BindTo, config_parse_unit_deps, UNIT_BINDS_TO, 0
-Unit.Conflicts, config_parse_unit_deps, UNIT_CONFLICTS, 0
-Unit.Before, config_parse_unit_deps, UNIT_BEFORE, 0
-Unit.After, config_parse_unit_deps, UNIT_AFTER, 0
-Unit.OnFailure, config_parse_unit_deps, UNIT_ON_FAILURE, 0
-Unit.PropagatesReloadTo, config_parse_unit_deps, UNIT_PROPAGATES_RELOAD_TO, 0
-Unit.PropagateReloadTo, config_parse_unit_deps, UNIT_PROPAGATES_RELOAD_TO, 0
-Unit.ReloadPropagatedFrom, config_parse_unit_deps, UNIT_RELOAD_PROPAGATED_FROM, 0
-Unit.PropagateReloadFrom, config_parse_unit_deps, UNIT_RELOAD_PROPAGATED_FROM, 0
-Unit.PartOf, config_parse_unit_deps, UNIT_PART_OF, 0
-Unit.RequiresMountsFor, config_parse_unit_requires_mounts_for, 0, offsetof(Unit, requires_mounts_for)
-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.OnFailureIsolate, config_parse_bool, 0, offsetof(Unit, on_failure_isolate)
-Unit.IgnoreOnIsolate, config_parse_bool, 0, offsetof(Unit, ignore_on_isolate)
-Unit.IgnoreOnSnapshot, config_parse_bool, 0, offsetof(Unit, ignore_on_snapshot)
-Unit.JobTimeoutSec, config_parse_usec, 0, offsetof(Unit, job_timeout)
-Unit.ConditionPathExists, config_parse_unit_condition_path, CONDITION_PATH_EXISTS, 0
-Unit.ConditionPathExistsGlob, config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB, 0
-Unit.ConditionPathIsDirectory, config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY, 0
-Unit.ConditionPathIsSymbolicLink,config_parse_unit_condition_path, CONDITION_PATH_IS_SYMBOLIC_LINK,0
-Unit.ConditionPathIsMountPoint, config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT, 0
-Unit.ConditionPathIsReadWrite, config_parse_unit_condition_path, CONDITION_PATH_IS_READ_WRITE, 0
-Unit.ConditionDirectoryNotEmpty, config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, 0
-Unit.ConditionFileIsExecutable, config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE, 0
-Unit.ConditionKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, 0
-Unit.ConditionVirtualization, config_parse_unit_condition_string, CONDITION_VIRTUALIZATION, 0
-Unit.ConditionSecurity, config_parse_unit_condition_string, CONDITION_SECURITY, 0
-Unit.ConditionCapability, config_parse_unit_condition_string, CONDITION_CAPABILITY, 0
-Unit.ConditionHost, config_parse_unit_condition_string, CONDITION_HOST, 0
-Unit.ConditionNull, config_parse_unit_condition_null, 0, 0
-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_usec, 0, offsetof(Service, restart_usec)
-Service.TimeoutSec, config_parse_service_timeout, 0, offsetof(Service, timeout_start_usec)
-Service.TimeoutStartSec, config_parse_service_timeout, 0, offsetof(Service, timeout_start_usec)
-Service.TimeoutStopSec, config_parse_service_timeout, 0, offsetof(Service, timeout_stop_usec)
-Service.WatchdogSec, config_parse_usec, 0, offsetof(Service, watchdog_usec)
-Service.StartLimitInterval, config_parse_usec, 0, offsetof(Service, start_limit.interval)
-Service.StartLimitBurst, config_parse_unsigned, 0, offsetof(Service, start_limit.burst)
-Service.StartLimitAction, config_parse_start_limit_action, 0, offsetof(Service, start_limit_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_ignore_status)
-Service.SuccessExitStatus, config_parse_set_status, 0, offsetof(Service, success_status)
-m4_ifdef(`HAVE_SYSV_COMPAT',
-`Service.SysVStartPriority, config_parse_sysv_priority, 0, offsetof(Service, sysv_start_priority)',
-`Service.SysVStartPriority, config_parse_warn_compat, 0, 0')
-Service.NonBlocking, config_parse_bool, 0, offsetof(Service, exec_context.non_blocking)
-Service.BusName, config_parse_unit_string_printf, 0, offsetof(Service, bus_name)
-Service.NotifyAccess, config_parse_notify_access, 0, offsetof(Service, notify_access)
-Service.Sockets, config_parse_service_sockets, 0, 0
-Service.FsckPassNo, config_parse_fsck_passno, 0, offsetof(Service, fsck_passno)
-EXEC_CONTEXT_CONFIG_ITEMS(Service)m4_dnl
-KILL_CONTEXT_CONFIG_ITEMS(Service)m4_dnl
-m4_dnl
-Socket.ListenStream, config_parse_socket_listen, 0, 0
-Socket.ListenDatagram, config_parse_socket_listen, 0, 0
-Socket.ListenSequentialPacket, config_parse_socket_listen, 0, 0
-Socket.ListenFIFO, config_parse_socket_listen, 0, 0
-Socket.ListenNetlink, config_parse_socket_listen, 0, 0
-Socket.ListenSpecial, config_parse_socket_listen, 0, 0
-Socket.ListenMessageQueue, config_parse_socket_listen, 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_usec, 0, offsetof(Socket, timeout_usec)
-Socket.DirectoryMode, config_parse_mode, 0, offsetof(Socket, directory_mode)
-Socket.SocketMode, config_parse_mode, 0, offsetof(Socket, socket_mode)
-Socket.Accept, config_parse_bool, 0, offsetof(Socket, accept)
-Socket.MaxConnections, config_parse_unsigned, 0, offsetof(Socket, max_connections)
-Socket.KeepAlive, config_parse_bool, 0, offsetof(Socket, keep_alive)
-Socket.Priority, config_parse_int, 0, offsetof(Socket, priority)
-Socket.ReceiveBuffer, config_parse_bytes_size, 0, offsetof(Socket, receive_buffer)
-Socket.SendBuffer, config_parse_bytes_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_bytes_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.MessageQueueMaxMessages, config_parse_long, 0, offsetof(Socket, mq_maxmsg)
-Socket.MessageQueueMessageSize, config_parse_long, 0, offsetof(Socket, mq_msgsize)
-Socket.Service, config_parse_socket_service, 0, 0
-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)
-EXEC_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl
-KILL_CONTEXT_CONFIG_ITEMS(Socket)m4_dnl
-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.FsckPassNo, config_parse_fsck_passno, 0, offsetof(Mount, parameters_fragment.passno)
-Mount.TimeoutSec, config_parse_usec, 0, offsetof(Mount, timeout_usec)
-Mount.DirectoryMode, config_parse_mode, 0, offsetof(Mount, directory_mode)
-EXEC_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
-KILL_CONTEXT_CONFIG_ITEMS(Mount)m4_dnl
-m4_dnl
-Automount.Where, config_parse_path, 0, offsetof(Automount, where)
-Automount.DirectoryMode, config_parse_mode, 0, offsetof(Automount, directory_mode)
-m4_dnl
-Swap.What, config_parse_path, 0, offsetof(Swap, parameters_fragment.what)
-Swap.Priority, config_parse_int, 0, offsetof(Swap, parameters_fragment.priority)
-Swap.TimeoutSec, config_parse_usec, 0, offsetof(Swap, timeout_usec)
-EXEC_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl
-KILL_CONTEXT_CONFIG_ITEMS(Swap)m4_dnl
-m4_dnl
-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.Unit, config_parse_timer_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_path_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 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
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
deleted file mode 100644
index 5803044178..0000000000
--- a/src/core/load-fragment.c
+++ /dev/null
@@ -1,2541 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <linux/oom.h>
-#include <assert.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sched.h>
-#include <sys/prctl.h>
-#include <sys/mount.h>
-#include <linux/fs.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-
-#include "unit.h"
-#include "strv.h"
-#include "conf-parser.h"
-#include "load-fragment.h"
-#include "log.h"
-#include "ioprio.h"
-#include "securebits.h"
-#include "missing.h"
-#include "unit-name.h"
-#include "unit-printf.h"
-#include "bus-errors.h"
-#include "utf8.h"
-#include "path-util.h"
-#include "syscall-list.h"
-
-#ifndef HAVE_SYSV_COMPAT
-int config_parse_warn_compat(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- log_debug("[%s:%u] Support for option %s= has been disabled at compile time and is ignored", filename, line, lvalue);
- return 0;
-}
-#endif
-
-int config_parse_unit_deps(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- UnitDependency d = ltype;
- Unit *u = userdata;
- char *w;
- size_t l;
- char *state;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- FOREACH_WORD_QUOTED(w, l, rvalue, state) {
- char *t, *k;
- int r;
-
- t = strndup(w, l);
- if (!t)
- return -ENOMEM;
-
- k = unit_name_printf(u, t);
- free(t);
- if (!k)
- return -ENOMEM;
-
- r = unit_add_dependency_by_name(u, d, k, NULL, true);
- if (r < 0)
- log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
-
- free(k);
- }
-
- return 0;
-}
-
-int config_parse_unit_string_printf(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Unit *u = userdata;
- char *k;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(u);
-
- k = unit_full_printf(u, rvalue);
- if (!k)
- return -ENOMEM;
-
- r = config_parse_string(filename, line, section, lvalue, ltype, k, data, userdata);
- free (k);
-
- return r;
-}
-
-int config_parse_unit_strv_printf(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Unit *u = userdata;
- char *k;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(u);
-
- k = unit_full_printf(u, rvalue);
- if (!k)
- return -ENOMEM;
-
- r = config_parse_strv(filename, line, section, lvalue, ltype, k, data, userdata);
- free(k);
-
- return r;
-}
-
-int config_parse_unit_path_printf(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Unit *u = userdata;
- char *k;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(u);
-
- k = unit_full_printf(u, rvalue);
- if (!k)
- return log_oom();
-
- r = config_parse_path(filename, line, section, lvalue, ltype, k, data, userdata);
- free(k);
-
- return r;
-}
-
-int config_parse_socket_listen(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- SocketPort *p, *tail;
- Socket *s;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- s = SOCKET(data);
-
- p = new0(SocketPort, 1);
- if (!p)
- return -ENOMEM;
-
- if (streq(lvalue, "ListenFIFO")) {
- p->type = SOCKET_FIFO;
-
- if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
- free(p);
- return -ENOMEM;
- }
-
- path_kill_slashes(p->path);
-
- } else if (streq(lvalue, "ListenSpecial")) {
- p->type = SOCKET_SPECIAL;
-
- if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
- free(p);
- return -ENOMEM;
- }
-
- path_kill_slashes(p->path);
-
- } else if (streq(lvalue, "ListenMessageQueue")) {
-
- p->type = SOCKET_MQUEUE;
-
- if (!(p->path = unit_full_printf(UNIT(s), rvalue))) {
- free(p);
- return -ENOMEM;
- }
-
- path_kill_slashes(p->path);
-
- } else if (streq(lvalue, "ListenNetlink")) {
- char *k;
- int r;
-
- p->type = SOCKET_SOCKET;
- k = unit_full_printf(UNIT(s), rvalue);
- r = socket_address_parse_netlink(&p->address, k);
- free(k);
-
- if (r < 0) {
- log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
- free(p);
- return 0;
- }
-
- } else {
- char *k;
- int r;
-
- p->type = SOCKET_SOCKET;
- k = unit_full_printf(UNIT(s), rvalue);
- r = socket_address_parse(&p->address, k);
- free(k);
-
- if (r < 0) {
- log_error("[%s:%u] Failed to parse address value, ignoring: %s", filename, line, rvalue);
- free(p);
- 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_error("[%s:%u] Address family not supported, ignoring: %s", filename, line, rvalue);
- free(p);
- return 0;
- }
- }
-
- p->fd = -1;
-
- if (s->ports) {
- LIST_FIND_TAIL(SocketPort, port, s->ports, tail);
- LIST_INSERT_AFTER(SocketPort, port, s->ports, tail, p);
- } else
- LIST_PREPEND(SocketPort, port, s->ports, p);
-
- return 0;
-}
-
-int config_parse_socket_bind(
- const char *filename,
- unsigned line,
- const char *section,
- 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_error("[%s:%u] Failed to parse bind IPv6 only value, ignoring: %s", filename, line, 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 *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- ExecContext *c = data;
- int priority;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (safe_atoi(rvalue, &priority) < 0) {
- log_error("[%s:%u] Failed to parse nice priority, ignoring: %s. ", filename, line, rvalue);
- return 0;
- }
-
- if (priority < PRIO_MIN || priority >= PRIO_MAX) {
- log_error("[%s:%u] Nice priority out of range, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- c->nice = priority;
- c->nice_set = true;
-
- return 0;
-}
-
-int config_parse_exec_oom_score_adjust(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- ExecContext *c = data;
- int oa;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (safe_atoi(rvalue, &oa) < 0) {
- log_error("[%s:%u] Failed to parse the OOM score adjust value, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- if (oa < OOM_SCORE_ADJ_MIN || oa > OOM_SCORE_ADJ_MAX) {
- log_error("[%s:%u] OOM score adjust value out of range, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- c->oom_score_adjust = oa;
- c->oom_score_adjust_set = true;
-
- return 0;
-}
-
-int config_parse_exec(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- ExecCommand **e = data, *nce;
- char *path, **n;
- unsigned k;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(e);
-
- /* We accept an absolute path as first argument, or
- * alternatively an absolute prefixed with @ to allow
- * overriding of argv[0]. */
-
- e += ltype;
-
- for (;;) {
- char *w;
- size_t l;
- char *state;
- bool honour_argv0 = false, ignore = false;
-
- path = NULL;
- nce = NULL;
- n = NULL;
-
- rvalue += strspn(rvalue, WHITESPACE);
-
- if (rvalue[0] == 0)
- break;
-
- if (rvalue[0] == '-') {
- ignore = true;
- rvalue ++;
- }
-
- if (rvalue[0] == '@') {
- honour_argv0 = true;
- rvalue ++;
- }
-
- if (*rvalue != '/') {
- log_error("[%s:%u] Invalid executable path in command line, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- k = 0;
- FOREACH_WORD_QUOTED(w, l, rvalue, state) {
- if (strncmp(w, ";", MAX(l, 1U)) == 0)
- break;
-
- k++;
- }
-
- n = new(char*, k + !honour_argv0);
- if (!n)
- return -ENOMEM;
-
- k = 0;
- FOREACH_WORD_QUOTED(w, l, rvalue, state) {
- if (strncmp(w, ";", MAX(l, 1U)) == 0)
- break;
-
- if (honour_argv0 && w == rvalue) {
- assert(!path);
-
- path = strndup(w, l);
- if (!path) {
- r = -ENOMEM;
- goto fail;
- }
-
- if (!utf8_is_valid(path)) {
- log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
- r = 0;
- goto fail;
- }
-
- } else {
- char *c;
-
- c = n[k++] = cunescape_length(w, l);
- if (!c) {
- r = -ENOMEM;
- goto fail;
- }
-
- if (!utf8_is_valid(c)) {
- log_error("[%s:%u] Path is not UTF-8 clean, ignoring assignment: %s", filename, line, rvalue);
- r = 0;
- goto fail;
- }
- }
- }
-
- n[k] = NULL;
-
- if (!n[0]) {
- log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue);
- r = 0;
- goto fail;
- }
-
- if (!path) {
- path = strdup(n[0]);
- if (!path) {
- r = -ENOMEM;
- goto fail;
- }
- }
-
- assert(path_is_absolute(path));
-
- nce = new0(ExecCommand, 1);
- if (!nce) {
- r = -ENOMEM;
- goto fail;
- }
-
- nce->argv = n;
- nce->path = path;
- nce->ignore = ignore;
-
- path_kill_slashes(nce->path);
-
- exec_command_append_list(e, nce);
-
- rvalue = state;
- }
-
- return 0;
-
-fail:
- n[k] = NULL;
- strv_free(n);
- free(path);
- free(nce);
-
- return r;
-}
-
-DEFINE_CONFIG_PARSE_ENUM(config_parse_service_type, service_type, ServiceType, "Failed to parse service type");
-DEFINE_CONFIG_PARSE_ENUM(config_parse_service_restart, service_restart, ServiceRestart, "Failed to parse service restart specifier");
-
-int config_parse_socket_bindtodevice(
- const char *filename,
- unsigned line,
- const char *section,
- 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, "*")) {
- if (!(n = strdup(rvalue)))
- return -ENOMEM;
- } 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 *filename,
- unsigned line,
- const char *section,
- 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_error("[%s:%u] Failed to parse IO scheduling class, ignoring: %s", filename, line, 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 *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- ExecContext *c = data;
- int i;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (safe_atoi(rvalue, &i) < 0 || i < 0 || i >= IOPRIO_BE_NR) {
- log_error("[%s:%u] Failed to parse io priority, ignoring: %s", filename, line, 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 *filename,
- unsigned line,
- const char *section,
- 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_error("[%s:%u] Failed to parse CPU scheduling policy, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- c->cpu_sched_policy = x;
- c->cpu_sched_set = true;
-
- return 0;
-}
-
-int config_parse_exec_cpu_sched_prio(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- ExecContext *c = data;
- int i;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- /* On Linux RR/FIFO have the same range */
- if (safe_atoi(rvalue, &i) < 0 || i < sched_get_priority_min(SCHED_RR) || i > sched_get_priority_max(SCHED_RR)) {
- log_error("[%s:%u] Failed to parse CPU scheduling priority, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- c->cpu_sched_priority = i;
- c->cpu_sched_set = true;
-
- return 0;
-}
-
-int config_parse_exec_cpu_affinity(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- ExecContext *c = data;
- char *w;
- size_t l;
- char *state;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- FOREACH_WORD_QUOTED(w, l, rvalue, state) {
- char *t;
- int r;
- unsigned cpu;
-
- if (!(t = strndup(w, l)))
- return -ENOMEM;
-
- r = safe_atou(t, &cpu);
- free(t);
-
- if (!(c->cpuset))
- if (!(c->cpuset = cpu_set_malloc(&c->cpuset_ncpus)))
- return -ENOMEM;
-
- if (r < 0 || cpu >= c->cpuset_ncpus) {
- log_error("[%s:%u] Failed to parse CPU affinity, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- CPU_SET_S(cpu, CPU_ALLOC_SIZE(c->cpuset_ncpus), c->cpuset);
- }
-
- return 0;
-}
-
-int config_parse_exec_capabilities(
- const char *filename,
- unsigned line,
- const char *section,
- 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);
-
- if (!(cap = cap_from_text(rvalue))) {
- if (errno == ENOMEM)
- return -ENOMEM;
-
- log_error("[%s:%u] Failed to parse capabilities, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- if (c->capabilities)
- cap_free(c->capabilities);
- c->capabilities = cap;
-
- return 0;
-}
-
-int config_parse_exec_secure_bits(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- ExecContext *c = data;
- char *w;
- size_t l;
- char *state;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- FOREACH_WORD_QUOTED(w, l, rvalue, state) {
- if (first_word(w, "keep-caps"))
- c->secure_bits |= SECURE_KEEP_CAPS;
- else if (first_word(w, "keep-caps-locked"))
- c->secure_bits |= SECURE_KEEP_CAPS_LOCKED;
- else if (first_word(w, "no-setuid-fixup"))
- c->secure_bits |= SECURE_NO_SETUID_FIXUP;
- else if (first_word(w, "no-setuid-fixup-locked"))
- c->secure_bits |= SECURE_NO_SETUID_FIXUP_LOCKED;
- else if (first_word(w, "noroot"))
- c->secure_bits |= SECURE_NOROOT;
- else if (first_word(w, "noroot-locked"))
- c->secure_bits |= SECURE_NOROOT_LOCKED;
- else {
- log_error("[%s:%u] Failed to parse secure bits, ignoring: %s", filename, line, rvalue);
- return 0;
- }
- }
-
- return 0;
-}
-
-int config_parse_bounding_set(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- uint64_t *capability_bounding_set_drop = data;
- char *w;
- size_t l;
- char *state;
- bool invert = false;
- uint64_t sum = 0;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (rvalue[0] == '~') {
- invert = true;
- rvalue++;
- }
-
- /* Note that we store this inverted internally, since the
- * kernel wants it like this. But we actually expose it
- * non-inverted everywhere to have a fully normalized
- * interface. */
-
- FOREACH_WORD_QUOTED(w, l, rvalue, state) {
- char *t;
- int r;
- cap_value_t cap;
-
- t = strndup(w, l);
- if (!t)
- return -ENOMEM;
-
- r = cap_from_name(t, &cap);
- free(t);
-
- if (r < 0) {
- log_error("[%s:%u] Failed to parse capability bounding set, ignoring: %s", filename, line, rvalue);
- continue;
- }
-
- sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
- }
-
- if (invert)
- *capability_bounding_set_drop |= sum;
- else
- *capability_bounding_set_drop |= ~sum;
-
- return 0;
-}
-
-int config_parse_limit(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- struct rlimit **rl = data;
- unsigned long long u;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- rl += ltype;
-
- if (streq(rvalue, "infinity"))
- u = (unsigned long long) RLIM_INFINITY;
- else if (safe_atollu(rvalue, &u) < 0) {
- log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- if (!*rl)
- if (!(*rl = new(struct rlimit, 1)))
- return -ENOMEM;
-
- (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
- return 0;
-}
-
-int config_parse_unit_cgroup(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Unit *u = userdata;
- char *w;
- size_t l;
- char *state;
-
- FOREACH_WORD_QUOTED(w, l, rvalue, state) {
- char *t, *k;
- int r;
-
- t = strndup(w, l);
- if (!t)
- return -ENOMEM;
-
- k = unit_full_printf(u, t);
- free(t);
-
- if (!k)
- return -ENOMEM;
-
- t = cunescape(k);
- free(k);
-
- if (!t)
- return -ENOMEM;
-
- r = unit_add_cgroup_from_text(u, t);
- free(t);
-
- if (r < 0) {
- log_error("[%s:%u] Failed to parse cgroup value, ignoring: %s", filename, line, rvalue);
- return 0;
- }
- }
-
- return 0;
-}
-
-#ifdef HAVE_SYSV_COMPAT
-int config_parse_sysv_priority(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- int *priority = data;
- int i;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (safe_atoi(rvalue, &i) < 0 || i < 0) {
- log_error("[%s:%u] Failed to parse SysV start priority, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- *priority = (int) i;
- return 0;
-}
-#endif
-
-int config_parse_fsck_passno(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- int *passno = data;
- int i;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (safe_atoi(rvalue, &i) || i < 0) {
- log_error("[%s:%u] Failed to parse fsck pass number, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- *passno = (int) i;
- return 0;
-}
-
-DEFINE_CONFIG_PARSE_ENUM(config_parse_kill_mode, kill_mode, KillMode, "Failed to parse kill mode");
-
-int config_parse_kill_signal(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- int *sig = data;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(sig);
-
- if ((r = signal_from_string_try_harder(rvalue)) <= 0) {
- log_error("[%s:%u] Failed to parse kill signal, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- *sig = r;
- return 0;
-}
-
-int config_parse_exec_mount_flags(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- ExecContext *c = data;
- char *w;
- size_t l;
- char *state;
- unsigned long flags = 0;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- FOREACH_WORD_QUOTED(w, l, rvalue, state) {
- if (strncmp(w, "shared", MAX(l, 6U)) == 0)
- flags |= MS_SHARED;
- else if (strncmp(w, "slave", MAX(l, 5U)) == 0)
- flags |= MS_SLAVE;
- else if (strncmp(w, "private", MAX(l, 7U)) == 0)
- flags |= MS_PRIVATE;
- else {
- log_error("[%s:%u] Failed to parse mount flags, ignoring: %s", filename, line, rvalue);
- return 0;
- }
- }
-
- c->mount_flags = flags;
- return 0;
-}
-
-int config_parse_timer(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Timer *t = data;
- usec_t u;
- TimerValue *v;
- TimerBase b;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if ((b = timer_base_from_string(lvalue)) < 0) {
- log_error("[%s:%u] Failed to parse timer base, ignoring: %s", filename, line, lvalue);
- return 0;
- }
-
- if (parse_usec(rvalue, &u) < 0) {
- log_error("[%s:%u] Failed to parse timer value, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- if (!(v = new0(TimerValue, 1)))
- return -ENOMEM;
-
- v->base = b;
- v->value = u;
-
- LIST_PREPEND(TimerValue, value, t->values, v);
-
- return 0;
-}
-
-int config_parse_timer_unit(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Timer *t = data;
- int r;
- DBusError error;
- Unit *u;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- dbus_error_init(&error);
-
- if (endswith(rvalue, ".timer")) {
- log_error("[%s:%u] Unit cannot be of type timer, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, NULL, &u);
- if (r < 0) {
- log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
- dbus_error_free(&error);
- return 0;
- }
-
- unit_ref_set(&t->unit, u);
-
- return 0;
-}
-
-int config_parse_path_spec(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Path *p = data;
- PathSpec *s;
- PathType b;
- char *k;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- b = path_type_from_string(lvalue);
- if (b < 0) {
- log_error("[%s:%u] Failed to parse path type, ignoring: %s", filename, line, lvalue);
- return 0;
- }
-
- k = unit_full_printf(UNIT(p), rvalue);
- if (!k)
- return log_oom();
-
- if (!path_is_absolute(k)) {
- log_error("[%s:%u] Path is not absolute, ignoring: %s", filename, line, k);
- free(k);
- return 0;
- }
-
- s = new0(PathSpec, 1);
- if (!s) {
- free(k);
- return log_oom();
- }
-
- s->path = path_kill_slashes(k);
- s->type = b;
- s->inotify_fd = -1;
-
- LIST_PREPEND(PathSpec, spec, p->specs, s);
-
- return 0;
-}
-
-int config_parse_path_unit(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Path *t = data;
- int r;
- DBusError error;
- Unit *u;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- dbus_error_init(&error);
-
- if (endswith(rvalue, ".path")) {
- log_error("[%s:%u] Unit cannot be of type path, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- if ((r = manager_load_unit(UNIT(t)->manager, rvalue, NULL, &error, &u)) < 0) {
- log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
- dbus_error_free(&error);
- return 0;
- }
-
- unit_ref_set(&t->unit, u);
-
- return 0;
-}
-
-int config_parse_socket_service(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Socket *s = data;
- int r;
- DBusError error;
- Unit *x;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- dbus_error_init(&error);
-
- if (!endswith(rvalue, ".service")) {
- log_error("[%s:%u] Unit must be of type service, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- r = manager_load_unit(UNIT(s)->manager, rvalue, NULL, &error, &x);
- if (r < 0) {
- log_error("[%s:%u] Failed to load unit %s, ignoring: %s", filename, line, rvalue, bus_error(&error, r));
- dbus_error_free(&error);
- return 0;
- }
-
- unit_ref_set(&s->service, x);
-
- return 0;
-}
-
-int config_parse_service_sockets(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Service *s = data;
- int r;
- char *state, *w;
- size_t l;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- FOREACH_WORD_QUOTED(w, l, rvalue, state) {
- char *t, *k;
-
- t = strndup(w, l);
- if (!t)
- return -ENOMEM;
-
- k = unit_name_printf(UNIT(s), t);
- free(t);
-
- if (!k)
- return -ENOMEM;
-
- if (!endswith(k, ".socket")) {
- log_error("[%s:%u] Unit must be of type socket, ignoring: %s", filename, line, rvalue);
- free(k);
- continue;
- }
-
- r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_WANTS, UNIT_AFTER, k, NULL, true);
- if (r < 0)
- log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", filename, line, k, strerror(-r));
-
- r = unit_add_dependency_by_name(UNIT(s), UNIT_TRIGGERED_BY, k, NULL, true);
- if (r < 0)
- return r;
-
- free(k);
- }
-
- return 0;
-}
-
-int config_parse_service_timeout(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Service *s = userdata;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(s);
-
- r = config_parse_usec(filename, line, section, lvalue, ltype, rvalue, data, userdata);
-
- if (r)
- return r;
-
- if (streq(lvalue, "TimeoutSec")) {
- s->start_timeout_defined = true;
- s->timeout_stop_usec = s->timeout_start_usec;
- } else if (streq(lvalue, "TimeoutStartSec"))
- s->start_timeout_defined = true;
-
- return 0;
-}
-
-int config_parse_unit_env_file(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- char ***env = data, **k;
- Unit *u = userdata;
- char *s;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- s = unit_full_printf(u, rvalue);
- if (!s)
- return -ENOMEM;
-
- if (!path_is_absolute(s[0] == '-' ? s + 1 : s)) {
- log_error("[%s:%u] Path '%s' is not absolute, ignoring.", filename, line, s);
- free(s);
- return 0;
- }
-
- k = strv_append(*env, s);
- free(s);
- if (!k)
- return -ENOMEM;
-
- strv_free(*env);
- *env = k;
-
- return 0;
-}
-
-int config_parse_ip_tos(
- const char *filename,
- unsigned line,
- const char *section,
- 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_error("[%s:%u] Failed to parse IP TOS value, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- *ip_tos = x;
- return 0;
-}
-
-int config_parse_unit_condition_path(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- ConditionType cond = ltype;
- Unit *u = data;
- bool trigger, negate;
- Condition *c;
- _cleanup_free_ char *p = NULL;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- trigger = rvalue[0] == '|';
- if (trigger)
- rvalue++;
-
- negate = rvalue[0] == '!';
- if (negate)
- rvalue++;
-
- p = unit_full_printf(u, rvalue);
- if (!p)
- return -ENOMEM;
-
- if (!path_is_absolute(p)) {
- log_error("[%s:%u] Path in condition not absolute, ignoring: %s", filename, line, p);
- return 0;
- }
-
- c = condition_new(cond, p, trigger, negate);
- if (!c)
- return -ENOMEM;
-
- LIST_PREPEND(Condition, conditions, u->conditions, c);
- return 0;
-}
-
-int config_parse_unit_condition_string(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- ConditionType cond = ltype;
- Unit *u = data;
- bool trigger, negate;
- Condition *c;
- _cleanup_free_ char *s = NULL;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- trigger = rvalue[0] == '|';
- if (trigger)
- rvalue++;
-
- negate = rvalue[0] == '!';
- if (negate)
- rvalue++;
-
- s = unit_full_printf(u, rvalue);
- if (!s)
- return -ENOMEM;
-
- c = condition_new(cond, s, trigger, negate);
- if (!c)
- return log_oom();
-
- LIST_PREPEND(Condition, conditions, u->conditions, c);
- return 0;
-}
-
-int config_parse_unit_condition_null(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Unit *u = data;
- Condition *c;
- bool trigger, negate;
- int b;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if ((trigger = rvalue[0] == '|'))
- rvalue++;
-
- if ((negate = rvalue[0] == '!'))
- rvalue++;
-
- if ((b = parse_boolean(rvalue)) < 0) {
- log_error("[%s:%u] Failed to parse boolean value in condition, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- if (!b)
- negate = !negate;
-
- if (!(c = condition_new(CONDITION_NULL, NULL, trigger, negate)))
- return -ENOMEM;
-
- LIST_PREPEND(Condition, conditions, u->conditions, 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_start_limit_action, start_limit_action, StartLimitAction, "Failed to parse start limit action specifier");
-
-int config_parse_unit_cgroup_attr(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Unit *u = data;
- char **l;
- int r;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- l = strv_split_quoted(rvalue);
- if (!l)
- return -ENOMEM;
-
- if (strv_length(l) != 2) {
- log_error("[%s:%u] Failed to parse cgroup attribute value, ignoring: %s", filename, line, rvalue);
- strv_free(l);
- return 0;
- }
-
- r = unit_add_cgroup_attribute(u, NULL, l[0], l[1], NULL);
- strv_free(l);
-
- if (r < 0) {
- log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- return 0;
-}
-
-int config_parse_unit_cpu_shares(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) {
- Unit *u = data;
- int r;
- unsigned long ul;
- char *t;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (safe_atolu(rvalue, &ul) < 0 || ul < 1) {
- log_error("[%s:%u] Failed to parse CPU shares value, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- if (asprintf(&t, "%lu", ul) < 0)
- return -ENOMEM;
-
- r = unit_add_cgroup_attribute(u, "cpu", "cpu.shares", t, NULL);
- free(t);
-
- if (r < 0) {
- log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- return 0;
-}
-
-int config_parse_unit_memory_limit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) {
- Unit *u = data;
- int r;
- off_t sz;
- char *t;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if (parse_bytes(rvalue, &sz) < 0 || sz <= 0) {
- log_error("[%s:%u] Failed to parse memory limit value, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- if (asprintf(&t, "%llu", (unsigned long long) sz) < 0)
- return -ENOMEM;
-
- r = unit_add_cgroup_attribute(u,
- "memory",
- streq(lvalue, "MemorySoftLimit") ? "memory.soft_limit_in_bytes" : "memory.limit_in_bytes",
- t, NULL);
- free(t);
-
- if (r < 0) {
- log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- return 0;
-}
-
-static int device_map(const char *controller, const char *name, const char *value, char **ret) {
- char **l;
-
- assert(controller);
- assert(name);
- assert(value);
- assert(ret);
-
- l = strv_split_quoted(value);
- if (!l)
- return -ENOMEM;
-
- assert(strv_length(l) >= 1);
-
- if (streq(l[0], "*")) {
-
- if (asprintf(ret, "a *:*%s%s",
- isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
- strv_free(l);
- return -ENOMEM;
- }
-
- } else {
- struct stat st;
-
- if (stat(l[0], &st) < 0) {
- log_warning("Couldn't stat device %s", l[0]);
- strv_free(l);
- return -errno;
- }
-
- if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
- log_warning("%s is not a device.", l[0]);
- strv_free(l);
- return -ENODEV;
- }
-
- if (asprintf(ret, "%c %u:%u%s%s",
- S_ISCHR(st.st_mode) ? 'c' : 'b',
- major(st.st_rdev), minor(st.st_rdev),
- isempty(l[1]) ? "" : " ", strempty(l[1])) < 0) {
-
- strv_free(l);
- return -ENOMEM;
- }
- }
-
- strv_free(l);
- return 0;
-}
-
-int config_parse_unit_device_allow(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) {
- Unit *u = data;
- char **l;
- int r;
- unsigned k;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- l = strv_split_quoted(rvalue);
- if (!l)
- return -ENOMEM;
-
- k = strv_length(l);
- if (k < 1 || k > 2) {
- log_error("[%s:%u] Failed to parse device value, ignoring: %s", filename, line, rvalue);
- strv_free(l);
- return 0;
- }
-
- if (!streq(l[0], "*") && !path_startswith(l[0], "/dev")) {
- log_error("[%s:%u] Device node path not absolute, ignoring: %s", filename, line, rvalue);
- strv_free(l);
- return 0;
- }
-
- if (!isempty(l[1]) && !in_charset(l[1], "rwm")) {
- log_error("[%s:%u] Device access string invalid, ignoring: %s", filename, line, rvalue);
- strv_free(l);
- return 0;
- }
- strv_free(l);
-
- r = unit_add_cgroup_attribute(u, "devices",
- streq(lvalue, "DeviceAllow") ? "devices.allow" : "devices.deny",
- rvalue, device_map);
-
- if (r < 0) {
- log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- return 0;
-}
-
-static int blkio_map(const char *controller, const char *name, const char *value, char **ret) {
- struct stat st;
- char **l;
- dev_t d;
-
- assert(controller);
- assert(name);
- assert(value);
- assert(ret);
-
- l = strv_split_quoted(value);
- if (!l)
- return -ENOMEM;
-
- assert(strv_length(l) == 2);
-
- if (stat(l[0], &st) < 0) {
- log_warning("Couldn't stat device %s", l[0]);
- strv_free(l);
- return -errno;
- }
-
- if (S_ISBLK(st.st_mode))
- d = 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 */
- d = st.st_dev;
-
- /* If this is a partition, try to get the originating
- * block device */
- block_get_whole_disk(d, &d);
- } else {
- log_warning("%s is not a block device and file system block device cannot be determined or is not local.", l[0]);
- strv_free(l);
- return -ENODEV;
- }
-
- if (asprintf(ret, "%u:%u %s", major(d), minor(d), l[1]) < 0) {
- strv_free(l);
- return -ENOMEM;
- }
-
- strv_free(l);
- return 0;
-}
-
-int config_parse_unit_blkio_weight(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) {
- Unit *u = data;
- int r;
- unsigned long ul;
- const char *device = NULL, *weight;
- unsigned k;
- char *t, **l;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- l = strv_split_quoted(rvalue);
- if (!l)
- return -ENOMEM;
-
- k = strv_length(l);
- if (k < 1 || k > 2) {
- log_error("[%s:%u] Failed to parse weight value, ignoring: %s", filename, line, rvalue);
- strv_free(l);
- return 0;
- }
-
- if (k == 1)
- weight = l[0];
- else {
- device = l[0];
- weight = l[1];
- }
-
- if (device && !path_is_absolute(device)) {
- log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
- strv_free(l);
- return 0;
- }
-
- if (safe_atolu(weight, &ul) < 0 || ul < 10 || ul > 1000) {
- log_error("[%s:%u] Failed to parse block IO weight value, ignoring: %s", filename, line, rvalue);
- strv_free(l);
- return 0;
- }
-
- if (device)
- r = asprintf(&t, "%s %lu", device, ul);
- else
- r = asprintf(&t, "%lu", ul);
- strv_free(l);
-
- if (r < 0)
- return -ENOMEM;
-
- if (device)
- r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight_device", t, blkio_map);
- else
- r = unit_add_cgroup_attribute(u, "blkio", "blkio.weight", t, NULL);
- free(t);
-
- if (r < 0) {
- log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- return 0;
-}
-
-int config_parse_unit_blkio_bandwidth(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata) {
- Unit *u = data;
- int r;
- off_t bytes;
- unsigned k;
- char *t, **l;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- l = strv_split_quoted(rvalue);
- if (!l)
- return -ENOMEM;
-
- k = strv_length(l);
- if (k != 2) {
- log_error("[%s:%u] Failed to parse bandwidth value, ignoring: %s", filename, line, rvalue);
- strv_free(l);
- return 0;
- }
-
- if (!path_is_absolute(l[0])) {
- log_error("[%s:%u] Failed to parse block device node value, ignoring: %s", filename, line, rvalue);
- strv_free(l);
- return 0;
- }
-
- if (parse_bytes(l[1], &bytes) < 0 || bytes <= 0) {
- log_error("[%s:%u] Failed to parse block IO bandwidth value, ignoring: %s", filename, line, rvalue);
- strv_free(l);
- return 0;
- }
-
- r = asprintf(&t, "%s %llu", l[0], (unsigned long long) bytes);
- strv_free(l);
-
- if (r < 0)
- return -ENOMEM;
-
- r = unit_add_cgroup_attribute(u, "blkio",
- streq(lvalue, "BlockIOReadBandwidth") ? "blkio.read_bps_device" : "blkio.write_bps_device",
- t, blkio_map);
- free(t);
-
- if (r < 0) {
- log_error("[%s:%u] Failed to add cgroup attribute value, ignoring: %s", filename, line, rvalue);
- return 0;
- }
-
- return 0;
-}
-
-int config_parse_unit_requires_mounts_for(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- Unit *u = userdata;
- int r;
- bool empty_before;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- empty_before = !u->requires_mounts_for;
-
- r = config_parse_path_strv(filename, line, section, lvalue, ltype, rvalue, data, userdata);
-
- /* Make it easy to find units with requires_mounts set */
- if (empty_before && u->requires_mounts_for)
- LIST_PREPEND(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
-
- return r;
-}
-
-int config_parse_documentation(
- const char *filename,
- unsigned line,
- const char *section,
- 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);
-
- r = config_parse_unit_strv_printf(filename, line, section, lvalue, ltype, rvalue, data, userdata);
- if (r < 0)
- return r;
-
- for (a = b = u->documentation; a && *a; a++) {
-
- if (is_valid_documentation_url(*a))
- *(b++) = *a;
- else {
- log_error("[%s:%u] Invalid URL, ignoring: %s", filename, line, *a);
- free(*a);
- }
- }
- *b = NULL;
-
- return r;
-}
-
-static void syscall_set(uint32_t *p, int nr) {
- p[nr >> 4] |= 1 << (nr & 31);
-}
-
-static void syscall_unset(uint32_t *p, int nr) {
- p[nr >> 4] &= ~(1 << (nr & 31));
-}
-
-int config_parse_syscall_filter(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- ExecContext *c = data;
- Unit *u = userdata;
- bool invert = false;
- char *w;
- size_t l;
- char *state;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(u);
-
- if (rvalue[0] == '~') {
- invert = true;
- rvalue++;
- }
-
- if (!c->syscall_filter) {
- size_t n;
-
- n = (syscall_max() + 31) >> 4;
- c->syscall_filter = new(uint32_t, n);
- if (!c->syscall_filter)
- return -ENOMEM;
-
- memset(c->syscall_filter, invert ? 0xFF : 0, n * sizeof(uint32_t));
-
- /* Add these by default */
- syscall_set(c->syscall_filter, __NR_execve);
- syscall_set(c->syscall_filter, __NR_rt_sigreturn);
-#ifdef __NR_sigreturn
- syscall_set(c->syscall_filter, __NR_sigreturn);
-#endif
- syscall_set(c->syscall_filter, __NR_exit_group);
- syscall_set(c->syscall_filter, __NR_exit);
- }
-
- FOREACH_WORD_QUOTED(w, l, rvalue, state) {
- int id;
- char *t;
-
- t = strndup(w, l);
- if (!t)
- return -ENOMEM;
-
- id = syscall_from_name(t);
- free(t);
-
- if (id < 0) {
- log_error("[%s:%u] Failed to parse syscall, ignoring: %s", filename, line, rvalue);
- continue;
- }
-
- if (invert)
- syscall_unset(c->syscall_filter, id);
- else
- syscall_set(c->syscall_filter, id);
- }
-
- c->no_new_privileges = true;
-
- 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 = path_get_file_name(*filename);
-
- if (unit_name_is_valid(name, true)) {
-
- id = set_get(names, name);
- if (!id) {
- id = strdup(name);
- if (!id)
- return -ENOMEM;
-
- r = set_put(names, id);
- if (r < 0) {
- free(id);
- 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) {
- r = -errno;
- close_nointr_nofail(fd);
- return r;
- }
-
- *_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;
- Set *symlink_names;
- FILE *f = NULL;
- char *filename = NULL, *id = NULL;
- Unit *merged;
- struct stat st;
-
- assert(u);
- assert(path);
-
- symlink_names = set_new(string_hash_func, string_compare_func);
- if (!symlink_names)
- return -ENOMEM;
-
- if (path_is_absolute(path)) {
-
- filename = strdup(path);
- if (!filename) {
- r = -ENOMEM;
- goto finish;
- }
-
- r = open_follow(&filename, &f, symlink_names, &id);
- if (r < 0) {
- free(filename);
- filename = NULL;
-
- if (r != -ENOENT)
- goto finish;
- }
-
- } 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) {
- r = -ENOMEM;
- goto finish;
- }
-
- if (u->manager->unit_path_cache &&
- !set_get(u->manager->unit_path_cache, filename))
- r = -ENOENT;
- else
- r = open_follow(&filename, &f, symlink_names, &id);
-
- if (r < 0) {
- free(filename);
- filename = NULL;
-
- if (r != -ENOENT)
- goto finish;
-
- /* Empty the symlink names for the next run */
- set_clear_free(symlink_names);
- continue;
- }
-
- break;
- }
- }
-
- if (!filename) {
- /* Hmm, no suitable file found? */
- r = 0;
- goto finish;
- }
-
- merged = u;
- r = merge_by_names(&merged, symlink_names, id);
- if (r < 0)
- goto finish;
-
- if (merged != u) {
- u->load_state = UNIT_MERGED;
- r = 0;
- goto finish;
- }
-
- if (fstat(fileno(f), &st) < 0) {
- r = -errno;
- goto finish;
- }
-
- if (null_or_empty(&st))
- u->load_state = UNIT_MASKED;
- else {
- /* Now, parse the file contents */
- r = config_parse(filename, f, UNIT_VTABLE(u)->sections, config_item_perf_lookup, (void*) load_fragment_gperf_lookup, false, u);
- if (r < 0)
- goto finish;
-
- u->load_state = UNIT_LOADED;
- }
-
- 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;
- }
-
- r = 0;
-
-finish:
- set_free_free(symlink_names);
- free(filename);
-
- if (f)
- fclose(f);
-
- return r;
-}
-
-int unit_load_fragment(Unit *u) {
- int r;
- Iterator i;
- const char *t;
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
- assert(u->id);
-
- /* First, try to find the unit under its id. We always look
- * for unit files in the default directories, to make it easy
- * to override things by placing things in /etc/systemd/system */
- r = load_from_path(u, u->id);
- if (r < 0)
- return r;
-
- /* Try to find an alias we can load this with */
- if (u->load_state == UNIT_STUB)
- SET_FOREACH(t, u->names, i) {
-
- if (t == u->id)
- continue;
-
- r = load_from_path(u, t);
- if (r < 0)
- return r;
-
- if (u->load_state != UNIT_STUB)
- break;
- }
-
- /* And now, try looking for it under the suggested (originally linked) path */
- if (u->load_state == UNIT_STUB && u->fragment_path) {
-
- r = load_from_path(u, u->fragment_path);
- if (r < 0)
- return r;
-
- if (u->load_state == UNIT_STUB) {
- /* Hmm, this didn't work? Then let's get rid
- * of the fragment path stored for us, so that
- * we don't point to an invalid location. */
- free(u->fragment_path);
- u->fragment_path = NULL;
- }
- }
-
- /* Look for a template */
- if (u->load_state == UNIT_STUB && u->instance) {
- char *k;
-
- k = unit_name_template(u->id);
- if (!k)
- return -ENOMEM;
-
- r = load_from_path(u, k);
- free(k);
-
- if (r < 0)
- return r;
-
- if (u->load_state == UNIT_STUB)
- SET_FOREACH(t, u->names, i) {
-
- if (t == u->id)
- continue;
-
- k = unit_name_template(t);
- if (!k)
- return -ENOMEM;
-
- r = load_from_path(u, k);
- free(k);
-
- if (r < 0)
- return r;
-
- if (u->load_state != UNIT_STUB)
- break;
- }
- }
-
- return 0;
-}
-
-void unit_dump_config_items(FILE *f) {
- static const struct {
- const ConfigParserCallback callback;
- const char *rvalue;
- } table[] = {
- { config_parse_int, "INTEGER" },
- { config_parse_unsigned, "UNSIGNED" },
- { config_parse_bytes_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_facility, "FACILITY" },
- { config_parse_level, "LEVEL" },
- { config_parse_exec_capabilities, "CAPABILITIES" },
- { config_parse_exec_secure_bits, "SECUREBITS" },
- { config_parse_bounding_set, "BOUNDINGSET" },
- { config_parse_limit, "LIMIT" },
- { config_parse_unit_cgroup, "CGROUP [...]" },
- { 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" },
-#else
- { config_parse_warn_compat, "NOTSUPPORTED" },
-#endif
- { config_parse_kill_mode, "KILLMODE" },
- { config_parse_kill_signal, "SIGNAL" },
- { config_parse_socket_listen, "SOCKET [...]" },
- { config_parse_socket_bind, "SOCKETBIND" },
- { config_parse_socket_bindtodevice, "NETWORKINTERFACE" },
- { config_parse_usec, "SECONDS" },
- { config_parse_nsec, "NANOSECONDS" },
- { config_parse_path_strv, "PATH [...]" },
- { config_parse_unit_requires_mounts_for, "PATH [...]" },
- { config_parse_exec_mount_flags, "MOUNTFLAG [...]" },
- { config_parse_unit_string_printf, "STRING" },
- { config_parse_timer, "TIMER" },
- { config_parse_timer_unit, "NAME" },
- { config_parse_path_spec, "PATH" },
- { config_parse_path_unit, "UNIT" },
- { 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" },
- };
-
- 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 || strncmp(prev, i, prefix_len+1) != 0) {
- 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 24f738464c..0000000000
--- a/src/core/load-fragment.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "unit.h"
-
-/* Read service data from .desktop file style configuration fragments */
-
-int unit_load_fragment(Unit *u);
-
-void unit_dump_config_items(FILE *f);
-
-int config_parse_warn_compat(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_deps(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_string_printf(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_strv_printf(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_path_printf(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_documentation(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_socket_listen(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_socket_bind(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_nice(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_oom_score_adjust(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_service_timeout(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_service_type(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_service_restart(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_socket_bindtodevice(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_output(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_input(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_io_class(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_io_priority(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_cpu_sched_policy(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_cpu_sched_prio(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_cpu_affinity(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_capabilities(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_secure_bits(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_bounding_set(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_limit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_cgroup(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_sysv_priority(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_fsck_passno(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_kill_signal(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_exec_mount_flags(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_timer(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_timer_unit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_path_spec(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_path_unit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_socket_service(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_service_sockets(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_env_file(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_ip_tos(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_condition_path(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_condition_string(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_condition_null(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_kill_mode(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_notify_access(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_start_limit_action(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_cgroup_attr(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_cpu_shares(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_memory_limit(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_device_allow(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_blkio_weight(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_blkio_bandwidth(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_unit_requires_mounts_for(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
-int config_parse_syscall_filter(const char *filename, unsigned line, const char *section, 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[];
diff --git a/src/core/locale-setup.c b/src/core/locale-setup.c
deleted file mode 100644
index b9bd3a0748..0000000000
--- a/src/core/locale-setup.c
+++ /dev/null
@@ -1,241 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <string.h>
-#include <stdlib.h>
-#include <errno.h>
-
-#include "locale-setup.h"
-#include "util.h"
-#include "macro.h"
-#include "virt.h"
-
-enum {
- /* We don't list LC_ALL here on purpose. People should be
- * using LANG instead. */
-
- VARIABLE_LANG,
- VARIABLE_LANGUAGE,
- VARIABLE_LC_CTYPE,
- VARIABLE_LC_NUMERIC,
- VARIABLE_LC_TIME,
- VARIABLE_LC_COLLATE,
- VARIABLE_LC_MONETARY,
- VARIABLE_LC_MESSAGES,
- VARIABLE_LC_PAPER,
- VARIABLE_LC_NAME,
- VARIABLE_LC_ADDRESS,
- VARIABLE_LC_TELEPHONE,
- VARIABLE_LC_MEASUREMENT,
- VARIABLE_LC_IDENTIFICATION,
- _VARIABLE_MAX
-};
-
-static const char * const variable_names[_VARIABLE_MAX] = {
- [VARIABLE_LANG] = "LANG",
- [VARIABLE_LANGUAGE] = "LANGUAGE",
- [VARIABLE_LC_CTYPE] = "LC_CTYPE",
- [VARIABLE_LC_NUMERIC] = "LC_NUMERIC",
- [VARIABLE_LC_TIME] = "LC_TIME",
- [VARIABLE_LC_COLLATE] = "LC_COLLATE",
- [VARIABLE_LC_MONETARY] = "LC_MONETARY",
- [VARIABLE_LC_MESSAGES] = "LC_MESSAGES",
- [VARIABLE_LC_PAPER] = "LC_PAPER",
- [VARIABLE_LC_NAME] = "LC_NAME",
- [VARIABLE_LC_ADDRESS] = "LC_ADDRESS",
- [VARIABLE_LC_TELEPHONE] = "LC_TELEPHONE",
- [VARIABLE_LC_MEASUREMENT] = "LC_MEASUREMENT",
- [VARIABLE_LC_IDENTIFICATION] = "LC_IDENTIFICATION"
-};
-
-int locale_setup(void) {
- char *variables[_VARIABLE_MAX];
- int r = 0, i;
-
- zero(variables);
-
- if (detect_container(NULL) <= 0)
- if ((r = parse_env_file("/proc/cmdline", WHITESPACE,
-#if defined(TARGET_FEDORA)
- "LANG", &variables[VARIABLE_LANG],
-#endif
- "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)) < 0) {
-
- if (r != -ENOENT)
- log_warning("Failed to read /proc/cmdline: %s", strerror(-r));
- }
-
- /* 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)) < 0) {
-
- if (r != -ENOENT)
- log_warning("Failed to read /etc/locale.conf: %s", strerror(-r));
- }
-
-#if defined(TARGET_ALTLINUX)
- if (r <= 0 &&
- (r = parse_env_file("/etc/sysconfig/i18n", NEWLINE,
- "LANG", &variables[VARIABLE_LANG],
- NULL)) < 0) {
-
- if (r != -ENOENT)
- log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
- }
-
-#elif defined(TARGET_SUSE)
- if (r <= 0 &&
- (r = parse_env_file("/etc/sysconfig/language", NEWLINE,
- "RC_LANG", &variables[VARIABLE_LANG],
- NULL)) < 0) {
-
- if (r != -ENOENT)
- log_warning("Failed to read /etc/sysconfig/language: %s", strerror(-r));
- }
-
-#elif defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM)
- if (r <= 0 &&
- (r = parse_env_file("/etc/default/locale", NEWLINE,
- "LANG", &variables[VARIABLE_LANG],
- "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)) < 0) {
-
- if (r != -ENOENT)
- log_warning("Failed to read /etc/default/locale: %s", strerror(-r));
- }
-
-#elif defined(TARGET_GENTOO)
- /* Gentoo's openrc expects locale variables in /etc/env.d/
- * These files are later compiled by env-update into shell
- * export commands at /etc/profile.env, with variables being
- * exported by openrc's runscript (so /etc/init.d/)
- */
- if (r <= 0 &&
- (r = parse_env_file("/etc/profile.env", NEWLINE,
- "export LANG", &variables[VARIABLE_LANG],
- "export LC_CTYPE", &variables[VARIABLE_LC_CTYPE],
- "export LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC],
- "export LC_TIME", &variables[VARIABLE_LC_TIME],
- "export LC_COLLATE", &variables[VARIABLE_LC_COLLATE],
- "export LC_MONETARY", &variables[VARIABLE_LC_MONETARY],
- "export LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES],
- "export LC_PAPER", &variables[VARIABLE_LC_PAPER],
- "export LC_NAME", &variables[VARIABLE_LC_NAME],
- "export LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS],
- "export LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE],
- "export LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT],
- "export LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION],
- NULL)) < 0) {
-
- if (r != -ENOENT)
- log_warning("Failed to read /etc/profile.env: %s", strerror(-r));
- }
-#elif defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA )
- if (r <= 0 &&
- (r = parse_env_file("/etc/sysconfig/i18n", NEWLINE,
- "LANG", &variables[VARIABLE_LANG],
- "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)) < 0) {
-
- if (r != -ENOENT)
- log_warning("Failed to read /etc/sysconfig/i18n: %s", strerror(-r));
- }
-
-#endif
-
- if (!variables[VARIABLE_LANG]) {
- if (!(variables[VARIABLE_LANG] = strdup("C"))) {
- r = -ENOMEM;
- goto finish;
- }
- }
-
- for (i = 0; i < _VARIABLE_MAX; i++) {
-
- if (variables[i]) {
- if (setenv(variable_names[i], variables[i], 1) < 0) {
- r = -errno;
- goto finish;
- }
- } else
- unsetenv(variable_names[i]);
- }
-
- r = 0;
-
-finish:
- for (i = 0; i < _VARIABLE_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 5a0f2f7888..0000000000
--- a/src/core/locale-setup.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-int locale_setup(void);
diff --git a/src/core/loopback-setup.c b/src/core/loopback-setup.c
deleted file mode 100644
index 065b75a6e3..0000000000
--- a/src/core/loopback-setup.c
+++ /dev/null
@@ -1,317 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <sys/socket.h>
-#include <net/if.h>
-#include <asm/types.h>
-#include <netinet/in.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
-
-#include "util.h"
-#include "macro.h"
-#include "loopback-setup.h"
-#include "socket-util.h"
-
-#define NLMSG_TAIL(nmsg) \
- ((struct rtattr *) (((uint8_t*) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
-
-static int add_rtattr(struct nlmsghdr *n, size_t max_length, int type, const void *data, size_t data_length) {
- size_t length;
- struct rtattr *rta;
-
- length = RTA_LENGTH(data_length);
-
- if (NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(length) > max_length)
- return -E2BIG;
-
- rta = NLMSG_TAIL(n);
- rta->rta_type = type;
- rta->rta_len = length;
- memcpy(RTA_DATA(rta), data, data_length);
- n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(length);
-
- return 0;
-}
-
-static ssize_t sendto_loop(int fd, const void *buf, size_t buf_len, int flags, const struct sockaddr *sa, socklen_t sa_len) {
-
- for (;;) {
- ssize_t l;
-
- l = sendto(fd, buf, buf_len, flags, sa, sa_len);
- if (l >= 0)
- return l;
-
- if (errno != EINTR)
- return -errno;
- }
-}
-
-static ssize_t recvfrom_loop(int fd, void *buf, size_t buf_len, int flags, struct sockaddr *sa, socklen_t *sa_len) {
-
- for (;;) {
- ssize_t l;
-
- l = recvfrom(fd, buf, buf_len, flags, sa, sa_len);
- if (l >= 0)
- return l;
-
- if (errno != EINTR)
- return -errno;
- }
-}
-
-static int add_adresses(int fd, int if_loopback, unsigned *requests) {
- union {
- struct sockaddr sa;
- struct sockaddr_nl nl;
- } sa;
- union {
- struct nlmsghdr header;
- uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
- NLMSG_ALIGN(sizeof(struct ifaddrmsg)) +
- RTA_LENGTH(sizeof(struct in6_addr))];
- } request;
-
- struct ifaddrmsg *ifaddrmsg;
- uint32_t ipv4_address = htonl(INADDR_LOOPBACK);
- int r;
-
- zero(request);
-
- request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
- request.header.nlmsg_type = RTM_NEWADDR;
- request.header.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_ACK;
- request.header.nlmsg_seq = *requests + 1;
-
- ifaddrmsg = NLMSG_DATA(&request.header);
- ifaddrmsg->ifa_family = AF_INET;
- ifaddrmsg->ifa_prefixlen = 8;
- ifaddrmsg->ifa_flags = IFA_F_PERMANENT;
- ifaddrmsg->ifa_scope = RT_SCOPE_HOST;
- ifaddrmsg->ifa_index = if_loopback;
-
- r = add_rtattr(&request.header, sizeof(request), IFA_LOCAL, &ipv4_address, sizeof(ipv4_address));
- if (r < 0)
- return r;
-
- zero(sa);
- sa.nl.nl_family = AF_NETLINK;
-
- if (sendto_loop(fd, &request, request.header.nlmsg_len, 0, &sa.sa, sizeof(sa)) < 0)
- return -errno;
- (*requests)++;
-
- if (!socket_ipv6_is_supported())
- return 0;
-
- request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
- request.header.nlmsg_seq = *requests + 1;
-
- ifaddrmsg->ifa_family = AF_INET6;
- ifaddrmsg->ifa_prefixlen = 128;
-
- r = add_rtattr(&request.header, sizeof(request), IFA_LOCAL, &in6addr_loopback, sizeof(in6addr_loopback));
- if (r < 0)
- return r;
-
- if (sendto_loop(fd, &request, request.header.nlmsg_len, 0, &sa.sa, sizeof(sa)) < 0)
- return -errno;
- (*requests)++;
-
- return 0;
-}
-
-static int start_interface(int fd, int if_loopback, unsigned *requests) {
- union {
- struct sockaddr sa;
- struct sockaddr_nl nl;
- } sa;
- union {
- struct nlmsghdr header;
- uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
- NLMSG_ALIGN(sizeof(struct ifinfomsg))];
- } request;
-
- struct ifinfomsg *ifinfomsg;
-
- zero(request);
-
- request.header.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
- request.header.nlmsg_type = RTM_NEWLINK;
- request.header.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
- request.header.nlmsg_seq = *requests + 1;
-
- ifinfomsg = NLMSG_DATA(&request.header);
- ifinfomsg->ifi_family = AF_UNSPEC;
- ifinfomsg->ifi_index = if_loopback;
- ifinfomsg->ifi_flags = IFF_UP;
- ifinfomsg->ifi_change = IFF_UP;
-
- zero(sa);
- sa.nl.nl_family = AF_NETLINK;
-
- if (sendto_loop(fd, &request, request.header.nlmsg_len, 0, &sa.sa, sizeof(sa)) < 0)
- return -errno;
-
- (*requests)++;
-
- return 0;
-}
-
-static int read_response(int fd, unsigned requests_max) {
- union {
- struct sockaddr sa;
- struct sockaddr_nl nl;
- } sa;
- union {
- struct nlmsghdr header;
- uint8_t buf[NLMSG_ALIGN(sizeof(struct nlmsghdr)) +
- NLMSG_ALIGN(sizeof(struct nlmsgerr))];
- } response;
-
- ssize_t l;
- socklen_t sa_len = sizeof(sa);
- struct nlmsgerr *nlmsgerr;
-
- l = recvfrom_loop(fd, &response, sizeof(response), 0, &sa.sa, &sa_len);
- if (l < 0)
- return -errno;
-
- if (sa_len != sizeof(sa.nl) ||
- sa.nl.nl_family != AF_NETLINK)
- return -EIO;
-
- if (sa.nl.nl_pid != 0)
- return 0;
-
- if ((size_t) l < sizeof(struct nlmsghdr))
- return -EIO;
-
- if (response.header.nlmsg_type != NLMSG_ERROR ||
- (pid_t) response.header.nlmsg_pid != getpid() ||
- response.header.nlmsg_seq >= requests_max)
- return 0;
-
- if ((size_t) l < NLMSG_LENGTH(sizeof(struct nlmsgerr)) ||
- response.header.nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
- return -EIO;
-
- nlmsgerr = NLMSG_DATA(&response.header);
-
- if (nlmsgerr->error < 0 && nlmsgerr->error != -EEXIST)
- return nlmsgerr->error;
-
- return response.header.nlmsg_seq;
-}
-
-static int check_loopback(void) {
- int r, fd;
- union {
- struct sockaddr sa;
- struct sockaddr_in in;
- } sa;
-
- /* If we failed to set up the loop back device, check whether
- * it might already be set up */
-
- fd = socket(AF_INET, SOCK_DGRAM|SOCK_NONBLOCK|SOCK_CLOEXEC, 0);
- if (fd < 0)
- return -errno;
-
- zero(sa);
- sa.in.sin_family = AF_INET;
- sa.in.sin_addr.s_addr = INADDR_LOOPBACK;
-
- if (bind(fd, &sa.sa, sizeof(sa.in)) >= 0)
- r = 1;
- else
- r = errno == EADDRNOTAVAIL ? 0 : -errno;
-
- close_nointr_nofail(fd);
-
- return r;
-}
-
-int loopback_setup(void) {
- int r, if_loopback;
- union {
- struct sockaddr sa;
- struct sockaddr_nl nl;
- } sa;
- unsigned requests = 0, i;
- int fd;
- bool eperm = false;
-
- errno = 0;
- if_loopback = (int) if_nametoindex("lo");
- if (if_loopback <= 0)
- return errno ? -errno : -ENODEV;
-
- fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
- if (fd < 0)
- return -errno;
-
- zero(sa);
- sa.nl.nl_family = AF_NETLINK;
- if (bind(fd, &sa.sa, sizeof(sa)) < 0) {
- r = -errno;
- goto finish;
- }
-
- r = add_adresses(fd, if_loopback, &requests);
- if (r < 0)
- goto finish;
-
- r = start_interface(fd, if_loopback, &requests);
- if (r < 0)
- goto finish;
-
- for (i = 0; i < requests; i++) {
- r = read_response(fd, requests);
-
- if (r == -EPERM)
- eperm = true;
- else if (r < 0)
- goto finish;
- }
-
- if (eperm && check_loopback() < 0) {
- r = -EPERM;
- goto finish;
- }
-
- r = 0;
-
-finish:
- if (r < 0)
- log_warning("Failed to configure loopback device: %s", strerror(-r));
-
- if (fd >= 0)
- close_nointr_nofail(fd);
-
- return r;
-}
diff --git a/src/core/loopback-setup.h b/src/core/loopback-setup.h
deleted file mode 100644
index dd83cf13a7..0000000000
--- a/src/core/loopback-setup.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-int loopback_setup(void);
diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c
deleted file mode 100644
index 7f4c23b130..0000000000
--- a/src/core/machine-id-setup.c
+++ /dev/null
@@ -1,246 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <sys/mount.h>
-
-#include <systemd/sd-id128.h>
-
-#include "machine-id-setup.h"
-#include "macro.h"
-#include "util.h"
-#include "mkdir.h"
-#include "log.h"
-#include "virt.h"
-
-static int shorten_uuid(char destination[36], const char *source) {
- unsigned i, j;
-
- 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) {
- destination[32] = '\n';
- destination[33] = 0;
- return 0;
- }
-
- return -EINVAL;
-}
-
-static int generate(char id[34]) {
- int fd, r;
- unsigned char *p;
- sd_id128_t buf;
- char *q;
- ssize_t k;
- const char *vm_id;
-
- assert(id);
-
- /* First, try reading the D-Bus machine id, unless it is a symlink */
- fd = open("/var/lib/dbus/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
- if (fd >= 0) {
-
- k = loop_read(fd, id, 32, false);
- close_nointr_nofail(fd);
-
- if (k >= 32) {
- id[32] = '\n';
- id[33] = 0;
-
- log_info("Initializing machine ID from D-Bus machine ID.");
- return 0;
- }
- }
-
- /* If that didn't work, see if we are running in qemu/kvm and a
- * machine ID was passed in via -uuid on the qemu/kvm command
- * line */
-
- r = detect_vm(&vm_id);
- if (r > 0 && streq(vm_id, "kvm")) {
- char uuid[37];
-
- fd = open("/sys/class/dmi/id/product_uuid", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
- if (fd >= 0) {
- k = loop_read(fd, uuid, 36, false);
- close_nointr_nofail(fd);
-
- if (k >= 36) {
- r = shorten_uuid(id, uuid);
- if (r >= 0) {
- log_info("Initializing machine ID from KVM UUID.");
- return 0;
- }
- }
- }
- }
-
- /* If that didn't work either, see if we are running in a
- * container, and a machine ID was passed in via
- * $container_uuid the way libvirt/LXC does it */
- r = detect_container(NULL);
- if (r > 0) {
- char *e;
-
- r = getenv_for_pid(1, "container_uuid", &e);
- if (r > 0) {
- if (strlen(e) >= 36) {
- r = shorten_uuid(id, e);
- if (r >= 0) {
- log_info("Initializing machine ID from container UUID.");
- free(e);
- return 0;
- }
- }
-
- free(e);
- }
- }
-
- /* If that didn't work, generate a random machine id */
- r = sd_id128_randomize(&buf);
- if (r < 0) {
- log_error("Failed to open /dev/urandom: %s", strerror(-r));
- return r;
- }
-
- 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(void) {
- int fd, r;
- bool writable;
- struct stat st;
- char id[34]; /* 32 + \n + \0 */
- mode_t m;
-
- m = 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. */
-
- fd = open("/etc/machine-id", O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444);
- if (fd >= 0)
- writable = true;
- else {
- fd = open("/etc/machine-id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
- if (fd < 0) {
- umask(m);
- log_error("Cannot open /etc/machine-id: %m");
- return -errno;
- }
-
- writable = false;
- }
-
- umask(m);
-
- if (fstat(fd, &st) < 0) {
- log_error("fstat() failed: %m");
- r = -errno;
- goto finish;
- }
-
- if (S_ISREG(st.st_mode)) {
- if (loop_read(fd, id, 32, false) >= 32) {
- r = 0;
- goto finish;
- }
- }
-
- /* Hmm, so, the id currently stored is not useful, then let's
- * generate one */
-
- r = generate(id);
- if (r < 0)
- goto finish;
-
- if (S_ISREG(st.st_mode) && writable) {
- lseek(fd, 0, SEEK_SET);
-
- if (loop_write(fd, id, 33, false) == 33) {
- r = 0;
- goto finish;
- }
- }
-
- close_nointr_nofail(fd);
- fd = -1;
-
- /* Hmm, we couldn't write it? So let's write it to
- * /run/machine-id as a replacement */
-
- m = umask(0022);
- r = write_one_line_file("/run/machine-id", id);
- umask(m);
-
- if (r < 0) {
- log_error("Cannot write /run/machine-id: %s", strerror(-r));
-
- unlink("/run/machine-id");
- goto finish;
- }
-
- /* And now, let's mount it over */
- r = mount("/run/machine-id", "/etc/machine-id", NULL, MS_BIND, NULL) < 0 ? -errno : 0;
- if (r < 0) {
- unlink("/run/machine-id");
- log_error("Failed to mount /etc/machine-id: %s", strerror(-r));
- } else {
- log_info("Installed transient /etc/machine-id file.");
-
- /* Mark the mount read-only */
- mount(NULL, "/etc/machine-id", NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, NULL);
- }
-
-finish:
-
- if (fd >= 0)
- close_nointr_nofail(fd);
-
- return r;
-}
diff --git a/src/core/machine-id-setup.h b/src/core/machine-id-setup.h
deleted file mode 100644
index b9e6b4d674..0000000000
--- a/src/core/machine-id-setup.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-int machine_id_setup(void);
diff --git a/src/core/macros.systemd.in b/src/core/macros.systemd.in
deleted file mode 100644
index e521df337d..0000000000
--- a/src/core/macros.systemd.in
+++ /dev/null
@@ -1,56 +0,0 @@
-# -*- Mode: makefile; indent-tabs-mode: t -*- */
-#
-# This file is part of systemd.
-#
-# Copyright 2012 Lennart Poettering
-#
-# systemd is free software; you can redistribute it and/or modify it
-# under the terms of the GNU Lesser General Public License as published by
-# the Free Software Foundation; either version 2.1 of the License, or
-# (at your option) any later version.
-#
-# systemd is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public License
-# along with systemd; If not, see <http://www.gnu.org/licenses/>.
-
-# RPM macros for packages installing systemd unit files
-
-%_unitdir @systemunitdir@
-%_presetdir @systempresetdir@
-
-%systemd_requires \
-Requires(post): systemd \
-Requires(preun): systemd \
-Requires(postun): systemd \
-%{nil}
-
-%systemd_post() \
-if [ $1 -eq 1 ] ; then \
- # Initial installation \
- @rootbindir@/systemctl preset %{?*} >/dev/null 2>&1 || : \
-fi \
-%{nil}
-
-%systemd_preun() \
-if [ $1 -eq 0 ] ; then \
- # Package removal, not upgrade \
- @rootbindir@/systemctl --no-reload disable %{?*} > /dev/null 2>&1 || : \
- @rootbindir@/systemctl stop %{?*} > /dev/null 2>&1 || : \
-fi \
-%{nil}
-
-%systemd_postun() \
-@rootbindir@/systemctl daemon-reload >/dev/null 2>&1 || : \
-%{nil}
-
-%systemd_postun_with_restart() \
-@rootbindir@/systemctl daemon-reload >/dev/null 2>&1 || : \
-if [ $1 -ge 1 ] ; then \
- # Package upgrade, not uninstall \
- @rootbindir@/systemctl try-restart %{?*} >/dev/null 2>&1 || : \
-fi \
-%{nil}
diff --git a/src/core/main.c b/src/core/main.c
deleted file mode 100644
index 4da8ecb864..0000000000
--- a/src/core/main.c
+++ /dev/null
@@ -1,1950 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus/dbus.h>
-
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <getopt.h>
-#include <signal.h>
-#include <sys/wait.h>
-#include <fcntl.h>
-#include <sys/prctl.h>
-#include <sys/mount.h>
-
-#include "manager.h"
-#include "log.h"
-#include "load-fragment.h"
-#include "fdset.h"
-#include "special.h"
-#include "conf-parser.h"
-#include "bus-errors.h"
-#include "missing.h"
-#include "label.h"
-#include "build.h"
-#include "strv.h"
-#include "def.h"
-#include "virt.h"
-#include "watchdog.h"
-#include "path-util.h"
-#include "switch-root.h"
-#include "capability.h"
-#include "killall.h"
-
-#include "mount-setup.h"
-#include "loopback-setup.h"
-#include "kmod-setup.h"
-#include "hostname-setup.h"
-#include "machine-id-setup.h"
-#include "locale-setup.h"
-#include "hwclock.h"
-#include "selinux-setup.h"
-#include "ima-setup.h"
-#include "sd-daemon.h"
-
-static enum {
- ACTION_RUN,
- ACTION_HELP,
- ACTION_VERSION,
- ACTION_TEST,
- ACTION_DUMP_CONFIGURATION_ITEMS,
- ACTION_DONE
-} arg_action = ACTION_RUN;
-
-static char *arg_default_unit = NULL;
-static SystemdRunningAs arg_running_as = _SYSTEMD_RUNNING_AS_INVALID;
-
-static bool arg_dump_core = true;
-static bool arg_crash_shell = false;
-static int arg_crash_chvt = -1;
-static bool arg_confirm_spawn = false;
-static bool arg_show_status = true;
-static bool arg_switched_root = false;
-static char **arg_default_controllers = NULL;
-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_runtime_watchdog = 0;
-static usec_t arg_shutdown_watchdog = 10 * USEC_PER_MINUTE;
-static struct rlimit *arg_default_rlimit[RLIMIT_NLIMITS] = {};
-static uint64_t arg_capability_bounding_set_drop = 0;
-static nsec_t arg_timer_slack_nsec = (nsec_t) -1;
-
-static FILE* serialization = NULL;
-
-static void nop_handler(int sig) {
-}
-
-_noreturn_ static void crash(int sig) {
-
- if (!arg_dump_core)
- log_error("Caught <%s>, not dumping core.", signal_to_string(sig));
- else {
- struct sigaction sa;
- pid_t pid;
-
- /* We want to wait for the core process, hence let's enable SIGCHLD */
- zero(sa);
- sa.sa_handler = nop_handler;
- sa.sa_flags = SA_NOCLDSTOP|SA_RESTART;
- assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
-
- if ((pid = fork()) < 0)
- log_error("Caught <%s>, cannot fork for core dump: %s", signal_to_string(sig), strerror(errno));
-
- else if (pid == 0) {
- struct rlimit rl;
-
- /* Enable default signal handler for core dump */
- zero(sa);
- sa.sa_handler = SIG_DFL;
- assert_se(sigaction(sig, &sa, NULL) == 0);
-
- /* Don't limit the core dump size */
- zero(rl);
- rl.rlim_cur = RLIM_INFINITY;
- rl.rlim_max = RLIM_INFINITY;
- setrlimit(RLIMIT_CORE, &rl);
-
- /* Just to be sure... */
- assert_se(chdir("/") == 0);
-
- /* Raise the signal again */
- raise(sig);
-
- assert_not_reached("We shouldn't be here...");
- _exit(1);
-
- } else {
- siginfo_t status;
- int r;
-
- /* Order things nicely. */
- if ((r = wait_for_terminate(pid, &status)) < 0)
- log_error("Caught <%s>, waitpid() failed: %s", signal_to_string(sig), strerror(-r));
- else if (status.si_code != CLD_DUMPED)
- log_error("Caught <%s>, core dump failed.", signal_to_string(sig));
- else
- log_error("Caught <%s>, dumped core as pid %lu.", signal_to_string(sig), (unsigned long) pid);
- }
- }
-
- if (arg_crash_chvt)
- chvt(arg_crash_chvt);
-
- if (arg_crash_shell) {
- struct sigaction sa;
- pid_t pid;
-
- log_info("Executing crash shell in 10s...");
- sleep(10);
-
- /* Let the kernel reap children for us */
- zero(sa);
- sa.sa_handler = SIG_IGN;
- sa.sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART;
- assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
-
- pid = fork();
- if (pid < 0)
- log_error("Failed to fork off crash shell: %m");
- else if (pid == 0) {
- make_console_stdio();
- execl("/bin/sh", "/bin/sh", NULL);
-
- log_error("execl() failed: %m");
- _exit(1);
- }
-
- log_info("Successfully spawned crash shell as pid %lu.", (unsigned long) pid);
- }
-
- log_info("Freezing execution.");
- freeze();
-}
-
-static void install_crash_handler(void) {
- struct sigaction sa;
-
- zero(sa);
-
- sa.sa_handler = crash;
- sa.sa_flags = SA_NODEFER;
-
- sigaction_many(&sa, SIGNALS_CRASH_HANDLER, -1);
-}
-
-static int console_setup(bool do_reset) {
- int tty_fd, r;
-
- /* 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 (!do_reset)
- return 0;
-
- tty_fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
- if (tty_fd < 0) {
- log_error("Failed to open /dev/console: %s", strerror(-tty_fd));
- return -tty_fd;
- }
-
- /* 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)
- log_error("Failed to reset /dev/console: %s", strerror(-r));
-
- close_nointr_nofail(tty_fd);
- return r;
-}
-
-static int set_default_unit(const char *u) {
- char *c;
-
- assert(u);
-
- c = strdup(u);
- if (!c)
- return -ENOMEM;
-
- free(arg_default_unit);
- arg_default_unit = c;
-
- return 0;
-}
-
-static int parse_proc_cmdline_word(const char *word) {
-
- static const char * const rlmap[] = {
- "emergency", SPECIAL_EMERGENCY_TARGET,
- "-b", SPECIAL_EMERGENCY_TARGET,
- "single", SPECIAL_RESCUE_TARGET,
- "-s", SPECIAL_RESCUE_TARGET,
- "s", SPECIAL_RESCUE_TARGET,
- "S", SPECIAL_RESCUE_TARGET,
- "1", SPECIAL_RESCUE_TARGET,
- "2", SPECIAL_RUNLEVEL2_TARGET,
- "3", SPECIAL_RUNLEVEL3_TARGET,
- "4", SPECIAL_RUNLEVEL4_TARGET,
- "5", SPECIAL_RUNLEVEL5_TARGET,
- };
-
- assert(word);
-
- if (startswith(word, "systemd.unit=")) {
-
- if (!in_initrd())
- return set_default_unit(word + 13);
-
- } else if (startswith(word, "rd.systemd.unit=")) {
-
- if (in_initrd())
- return set_default_unit(word + 16);
-
- } else if (startswith(word, "systemd.log_target=")) {
-
- if (log_set_target_from_string(word + 19) < 0)
- log_warning("Failed to parse log target %s. Ignoring.", word + 19);
-
- } else if (startswith(word, "systemd.log_level=")) {
-
- if (log_set_max_level_from_string(word + 18) < 0)
- log_warning("Failed to parse log level %s. Ignoring.", word + 18);
-
- } else if (startswith(word, "systemd.log_color=")) {
-
- if (log_show_color_from_string(word + 18) < 0)
- log_warning("Failed to parse log color setting %s. Ignoring.", word + 18);
-
- } else if (startswith(word, "systemd.log_location=")) {
-
- if (log_show_location_from_string(word + 21) < 0)
- log_warning("Failed to parse log location setting %s. Ignoring.", word + 21);
-
- } else if (startswith(word, "systemd.dump_core=")) {
- int r;
-
- if ((r = parse_boolean(word + 18)) < 0)
- log_warning("Failed to parse dump core switch %s. Ignoring.", word + 18);
- else
- arg_dump_core = r;
-
- } else if (startswith(word, "systemd.crash_shell=")) {
- int r;
-
- if ((r = parse_boolean(word + 20)) < 0)
- log_warning("Failed to parse crash shell switch %s. Ignoring.", word + 20);
- else
- arg_crash_shell = r;
-
- } else if (startswith(word, "systemd.confirm_spawn=")) {
- int r;
-
- if ((r = parse_boolean(word + 22)) < 0)
- log_warning("Failed to parse confirm spawn switch %s. Ignoring.", word + 22);
- else
- arg_confirm_spawn = r;
-
- } else if (startswith(word, "systemd.crash_chvt=")) {
- int k;
-
- if (safe_atoi(word + 19, &k) < 0)
- log_warning("Failed to parse crash chvt switch %s. Ignoring.", word + 19);
- else
- arg_crash_chvt = k;
-
- } else if (startswith(word, "systemd.show_status=")) {
- int r;
-
- if ((r = parse_boolean(word + 20)) < 0)
- log_warning("Failed to parse show status switch %s. Ignoring.", word + 20);
- else
- arg_show_status = r;
- } else if (startswith(word, "systemd.default_standard_output=")) {
- int r;
-
- if ((r = exec_output_from_string(word + 32)) < 0)
- log_warning("Failed to parse default standard output switch %s. Ignoring.", word + 32);
- else
- arg_default_std_output = r;
- } else if (startswith(word, "systemd.default_standard_error=")) {
- int r;
-
- if ((r = exec_output_from_string(word + 31)) < 0)
- log_warning("Failed to parse default standard error switch %s. Ignoring.", word + 31);
- else
- arg_default_std_error = r;
- } else if (startswith(word, "systemd.setenv=")) {
- char *cenv, *eq;
- int r;
-
- cenv = strdup(word + 15);
- if (!cenv)
- return -ENOMEM;
-
- eq = strchr(cenv, '=');
- if (!eq) {
- r = unsetenv(cenv);
- if (r < 0)
- log_warning("unsetenv failed %m. Ignoring.");
- } else {
- *eq = 0;
- r = setenv(cenv, eq + 1, 1);
- if (r < 0)
- log_warning("setenv failed %m. Ignoring.");
- }
- free(cenv);
-
- } else if (startswith(word, "systemd.") ||
- (in_initrd() && startswith(word, "rd.systemd."))) {
-
- log_warning("Unknown kernel switch %s. Ignoring.", word);
-
- log_info("Supported kernel switches:\n"
- "systemd.unit=UNIT Default unit to start\n"
- "rd.systemd.unit=UNIT Default unit to start when run in initrd\n"
- "systemd.dump_core=0|1 Dump core on crash\n"
- "systemd.crash_shell=0|1 Run shell on crash\n"
- "systemd.crash_chvt=N Change to VT #N on crash\n"
- "systemd.confirm_spawn=0|1 Confirm every process spawn\n"
- "systemd.show_status=0|1 Show status updates on the console during bootup\n"
- "systemd.log_target=console|kmsg|journal|journal-or-kmsg|syslog|syslog-or-kmsg|null\n"
- " Log target\n"
- "systemd.log_level=LEVEL Log level\n"
- "systemd.log_color=0|1 Highlight important log messages\n"
- "systemd.log_location=0|1 Include code location in log messages\n"
- "systemd.default_standard_output=null|tty|syslog|syslog+console|kmsg|kmsg+console|journal|journal+console\n"
- " Set default log output for services\n"
- "systemd.default_standard_error=null|tty|syslog|syslog+console|kmsg|kmsg+console|journal|journal+console\n"
- " Set default log error output for services\n"
- "systemd.setenv=ASSIGNMENT Set an environment variable for all spawned processes\n");
-
- } else if (streq(word, "quiet"))
- arg_show_status = false;
- else if (!in_initrd()) {
- unsigned i;
-
- /* SysV compatibility */
- for (i = 0; i < ELEMENTSOF(rlmap); i += 2)
- if (streq(word, rlmap[i]))
- return set_default_unit(rlmap[i+1]);
- }
-
- return 0;
-}
-
-static int config_parse_level2(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- log_set_max_level_from_string(rvalue);
- return 0;
-}
-
-static int config_parse_target(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- log_set_target_from_string(rvalue);
- return 0;
-}
-
-static int config_parse_color(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- log_show_color_from_string(rvalue);
- return 0;
-}
-
-static int config_parse_location(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- log_show_location_from_string(rvalue);
- return 0;
-}
-
-static int config_parse_cpu_affinity2(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- char *w;
- size_t l;
- char *state;
- cpu_set_t *c = NULL;
- unsigned ncpus = 0;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- FOREACH_WORD_QUOTED(w, l, rvalue, state) {
- char *t;
- int r;
- unsigned cpu;
-
- if (!(t = strndup(w, l)))
- return log_oom();
-
- r = safe_atou(t, &cpu);
- free(t);
-
- if (!c)
- if (!(c = cpu_set_malloc(&ncpus)))
- return log_oom();
-
- if (r < 0 || cpu >= ncpus) {
- log_error("[%s:%u] Failed to parse CPU affinity: %s", filename, line, rvalue);
- CPU_FREE(c);
- return -EBADMSG;
- }
-
- CPU_SET_S(cpu, CPU_ALLOC_SIZE(ncpus), c);
- }
-
- if (c) {
- if (sched_setaffinity(0, CPU_ALLOC_SIZE(ncpus), c) < 0)
- log_warning("Failed to set CPU affinity: %m");
-
- CPU_FREE(c);
- }
-
- return 0;
-}
-
-static void strv_free_free(char ***l) {
- char ***i;
-
- if (!l)
- return;
-
- for (i = l; *i; i++)
- strv_free(*i);
-
- free(l);
-}
-
-static void free_join_controllers(void) {
- if (!arg_join_controllers)
- return;
-
- strv_free_free(arg_join_controllers);
- arg_join_controllers = NULL;
-}
-
-static int config_parse_join_controllers(
- const char *filename,
- unsigned line,
- const char *section,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
-
- unsigned n = 0;
- char *state, *w;
- size_t length;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
-
- free_join_controllers();
-
- FOREACH_WORD_QUOTED(w, length, rvalue, state) {
- char *s, **l;
-
- s = strndup(w, length);
- if (!s)
- return log_oom();
-
- l = strv_split(s, ",");
- free(s);
-
- strv_uniq(l);
-
- if (strv_length(l) <= 1) {
- strv_free(l);
- continue;
- }
-
- if (!arg_join_controllers) {
- arg_join_controllers = new(char**, 2);
- if (!arg_join_controllers) {
- strv_free(l);
- return log_oom();
- }
-
- arg_join_controllers[0] = l;
- arg_join_controllers[1] = NULL;
-
- n = 1;
- } else {
- char ***a;
- char ***t;
-
- t = new0(char**, n+2);
- if (!t) {
- strv_free(l);
- return log_oom();
- }
-
- n = 0;
-
- for (a = arg_join_controllers; *a; a++) {
-
- if (strv_overlap(*a, l)) {
- char **c;
-
- c = strv_merge(*a, l);
- if (!c) {
- strv_free(l);
- strv_free_free(t);
- return log_oom();
- }
-
- strv_free(l);
- l = c;
- } 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;
- }
- }
-
- return 0;
-}
-
-static int parse_config_file(void) {
-
- const ConfigTableItem items[] = {
- { "Manager", "LogLevel", config_parse_level2, 0, NULL },
- { "Manager", "LogTarget", config_parse_target, 0, NULL },
- { "Manager", "LogColor", config_parse_color, 0, NULL },
- { "Manager", "LogLocation", config_parse_location, 0, NULL },
- { "Manager", "DumpCore", config_parse_bool, 0, &arg_dump_core },
- { "Manager", "CrashShell", config_parse_bool, 0, &arg_crash_shell },
- { "Manager", "ShowStatus", config_parse_bool, 0, &arg_show_status },
- { "Manager", "CrashChVT", config_parse_int, 0, &arg_crash_chvt },
- { "Manager", "CPUAffinity", config_parse_cpu_affinity2, 0, NULL },
- { "Manager", "DefaultControllers", config_parse_strv, 0, &arg_default_controllers },
- { "Manager", "DefaultStandardOutput", config_parse_output, 0, &arg_default_std_output },
- { "Manager", "DefaultStandardError", config_parse_output, 0, &arg_default_std_error },
- { "Manager", "JoinControllers", config_parse_join_controllers, 0, &arg_join_controllers },
- { "Manager", "RuntimeWatchdogSec", config_parse_usec, 0, &arg_runtime_watchdog },
- { "Manager", "ShutdownWatchdogSec", config_parse_usec, 0, &arg_shutdown_watchdog },
- { "Manager", "CapabilityBoundingSet", config_parse_bounding_set, 0, &arg_capability_bounding_set_drop },
- { "Manager", "TimerSlackNSec", config_parse_nsec, 0, &arg_timer_slack_nsec },
- { "Manager", "DefaultLimitCPU", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_CPU]},
- { "Manager", "DefaultLimitFSIZE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_FSIZE]},
- { "Manager", "DefaultLimitDATA", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_DATA]},
- { "Manager", "DefaultLimitSTACK", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_STACK]},
- { "Manager", "DefaultLimitCORE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_CORE]},
- { "Manager", "DefaultLimitRSS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RSS]},
- { "Manager", "DefaultLimitNOFILE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NOFILE]},
- { "Manager", "DefaultLimitAS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_AS]},
- { "Manager", "DefaultLimitNPROC", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NPROC]},
- { "Manager", "DefaultLimitMEMLOCK", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_MEMLOCK]},
- { "Manager", "DefaultLimitLOCKS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_LOCKS]},
- { "Manager", "DefaultLimitSIGPENDING",config_parse_limit, 0, &arg_default_rlimit[RLIMIT_SIGPENDING]},
- { "Manager", "DefaultLimitMSGQUEUE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_MSGQUEUE]},
- { "Manager", "DefaultLimitNICE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NICE]},
- { "Manager", "DefaultLimitRTPRIO", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTPRIO]},
- { "Manager", "DefaultLimitRTTIME", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTTIME]},
- { NULL, NULL, NULL, 0, NULL }
- };
-
- FILE *f;
- const char *fn;
- int r;
-
- fn = arg_running_as == SYSTEMD_SYSTEM ? SYSTEM_CONFIG_FILE : USER_CONFIG_FILE;
- f = fopen(fn, "re");
- if (!f) {
- if (errno == ENOENT)
- return 0;
-
- log_warning("Failed to open configuration file '%s': %m", fn);
- return 0;
- }
-
- r = config_parse(fn, f, "Manager\0", config_item_table_lookup, (void*) items, false, NULL);
- if (r < 0)
- log_warning("Failed to parse configuration file: %s", strerror(-r));
-
- fclose(f);
-
- return 0;
-}
-
-static int parse_proc_cmdline(void) {
- char *line, *w, *state;
- int r;
- size_t l;
-
- /* Don't read /proc/cmdline if we are in a container, since
- * that is only relevant for the host system */
- if (detect_container(NULL) > 0)
- return 0;
-
- if ((r = read_one_line_file("/proc/cmdline", &line)) < 0) {
- log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
- return 0;
- }
-
- FOREACH_WORD_QUOTED(w, l, line, state) {
- char *word;
-
- if (!(word = strndup(w, l))) {
- r = -ENOMEM;
- goto finish;
- }
-
- r = parse_proc_cmdline_word(word);
- if (r < 0) {
- log_error("Failed on cmdline argument %s: %s", word, strerror(-r));
- free(word);
- goto finish;
- }
-
- free(word);
- }
-
- r = 0;
-
-finish:
- free(line);
- return r;
-}
-
-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_VERSION,
- ARG_DUMP_CONFIGURATION_ITEMS,
- ARG_DUMP_CORE,
- ARG_CRASH_SHELL,
- ARG_CONFIRM_SPAWN,
- ARG_SHOW_STATUS,
- ARG_DESERIALIZE,
- ARG_SWITCHED_ROOT,
- ARG_INTROSPECT,
- ARG_DEFAULT_STD_OUTPUT,
- ARG_DEFAULT_STD_ERROR
- };
-
- static const struct option options[] = {
- { "log-level", required_argument, NULL, ARG_LOG_LEVEL },
- { "log-target", required_argument, NULL, ARG_LOG_TARGET },
- { "log-color", optional_argument, NULL, ARG_LOG_COLOR },
- { "log-location", optional_argument, NULL, ARG_LOG_LOCATION },
- { "unit", required_argument, NULL, ARG_UNIT },
- { "system", no_argument, NULL, ARG_SYSTEM },
- { "user", no_argument, NULL, ARG_USER },
- { "test", no_argument, NULL, ARG_TEST },
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, ARG_VERSION },
- { "dump-configuration-items", no_argument, NULL, ARG_DUMP_CONFIGURATION_ITEMS },
- { "dump-core", optional_argument, NULL, ARG_DUMP_CORE },
- { "crash-shell", optional_argument, NULL, ARG_CRASH_SHELL },
- { "confirm-spawn", optional_argument, NULL, ARG_CONFIRM_SPAWN },
- { "show-status", optional_argument, NULL, ARG_SHOW_STATUS },
- { "deserialize", required_argument, NULL, ARG_DESERIALIZE },
- { "switched-root", no_argument, NULL, ARG_SWITCHED_ROOT },
- { "introspect", optional_argument, NULL, ARG_INTROSPECT },
- { "default-standard-output", required_argument, NULL, ARG_DEFAULT_STD_OUTPUT, },
- { "default-standard-error", required_argument, NULL, ARG_DEFAULT_STD_ERROR, },
- { NULL, 0, NULL, 0 }
- };
-
- 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:
- if ((r = log_set_max_level_from_string(optarg)) < 0) {
- log_error("Failed to parse log level %s.", optarg);
- return r;
- }
-
- break;
-
- case ARG_LOG_TARGET:
-
- if ((r = log_set_target_from_string(optarg)) < 0) {
- log_error("Failed to parse log target %s.", optarg);
- return r;
- }
-
- break;
-
- case ARG_LOG_COLOR:
-
- if (optarg) {
- if ((r = log_show_color_from_string(optarg)) < 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) {
- if ((r = log_show_location_from_string(optarg)) < 0) {
- log_error("Failed to parse log location setting %s.", optarg);
- return r;
- }
- } else
- log_show_location(true);
-
- break;
-
- case ARG_DEFAULT_STD_OUTPUT:
-
- if ((r = exec_output_from_string(optarg)) < 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:
-
- if ((r = exec_output_from_string(optarg)) < 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:
-
- if ((r = set_default_unit(optarg)) < 0) {
- log_error("Failed to set default unit %s: %s", optarg, strerror(-r));
- return r;
- }
-
- break;
-
- case ARG_SYSTEM:
- arg_running_as = SYSTEMD_SYSTEM;
- break;
-
- case ARG_USER:
- arg_running_as = SYSTEMD_USER;
- break;
-
- case ARG_TEST:
- arg_action = ACTION_TEST;
- break;
-
- case ARG_VERSION:
- arg_action = ACTION_VERSION;
- break;
-
- case ARG_DUMP_CONFIGURATION_ITEMS:
- arg_action = ACTION_DUMP_CONFIGURATION_ITEMS;
- break;
-
- case ARG_DUMP_CORE:
- r = optarg ? parse_boolean(optarg) : 1;
- if (r < 0) {
- log_error("Failed to parse dump core boolean %s.", optarg);
- return r;
- }
- arg_dump_core = r;
- break;
-
- case ARG_CRASH_SHELL:
- r = optarg ? parse_boolean(optarg) : 1;
- if (r < 0) {
- log_error("Failed to parse crash shell boolean %s.", optarg);
- return r;
- }
- arg_crash_shell = r;
- break;
-
- case ARG_CONFIRM_SPAWN:
- r = optarg ? parse_boolean(optarg) : 1;
- if (r < 0) {
- log_error("Failed to parse confirm spawn boolean %s.", optarg);
- return r;
- }
- arg_confirm_spawn = r;
- break;
-
- case ARG_SHOW_STATUS:
- r = optarg ? parse_boolean(optarg) : 1;
- if (r < 0) {
- log_error("Failed to parse show status boolean %s.", optarg);
- return r;
- }
- arg_show_status = r;
- break;
-
- case ARG_DESERIALIZE: {
- int fd;
- FILE *f;
-
- if ((r = safe_atoi(optarg, &fd)) < 0 || fd < 0) {
- log_error("Failed to parse deserialize option %s.", optarg);
- return r;
- }
-
- if (!(f = fdopen(fd, "r"))) {
- log_error("Failed to open serialization fd: %m");
- return r;
- }
-
- if (serialization)
- fclose(serialization);
-
- serialization = f;
-
- break;
- }
-
- case ARG_SWITCHED_ROOT:
- arg_switched_root = true;
- break;
-
- case ARG_INTROSPECT: {
- const char * const * i = NULL;
-
- for (i = bus_interface_table; *i; i += 2)
- if (!optarg || streq(i[0], optarg)) {
- fputs(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE
- "<node>\n", stdout);
- fputs(i[1], stdout);
- fputs("</node>\n", stdout);
-
- if (optarg)
- break;
- }
-
- if (!i[0] && optarg)
- log_error("Unknown interface %s.", optarg);
-
- arg_action = ACTION_DONE;
- break;
- }
-
- case 'h':
- arg_action = ACTION_HELP;
- 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 '?':
- default:
- if (getpid() != 1) {
- log_error("Unknown option code %c", c);
- return -EINVAL;
- }
-
- break;
- }
-
- 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;
- }
-
- if (detect_container(NULL) > 0) {
- char **a;
-
- /* All /proc/cmdline arguments the kernel didn't
- * understand it passed to us. We're not really
- * interested in that usually since /proc/cmdline is
- * more interesting and complete. With one exception:
- * if we are run in a container /proc/cmdline is not
- * relevant for the container, hence we rely on argv[]
- * instead. */
-
- for (a = argv; a < argv + argc; a++)
- if ((r = parse_proc_cmdline_word(*a)) < 0) {
- log_error("Failed on cmdline argument %s: %s", *a, strerror(-r));
- return r;
- }
- }
-
- 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"
- " --dump-configuration-items Dump understood unit configuration items\n"
- " --introspect[=INTERFACE] Extract D-Bus interface data\n"
- " --unit=UNIT Set default unit\n"
- " --system Run a system instance, even if PID != 1\n"
- " --user Run a user instance\n"
- " --dump-core[=0|1] Dump core on crash\n"
- " --crash-shell[=0|1] Run shell on crash\n"
- " --confirm-spawn[=0|1] Ask for confirmation when spawning processes\n"
- " --show-status[=0|1] Show status updates on the console during bootup\n"
- " --log-target=TARGET Set log target (console, journal, syslog, kmsg, journal-or-kmsg, syslog-or-kmsg, null)\n"
- " --log-level=LEVEL Set log level (debug, info, notice, warning, err, crit, alert, emerg)\n"
- " --log-color[=0|1] Highlight important log messages\n"
- " --log-location[=0|1] Include code location in log messages\n"
- " --default-standard-output= Set default standard output for services\n"
- " --default-standard-error= Set default standard error output for services\n",
- program_invocation_short_name);
-
- return 0;
-}
-
-static int version(void) {
- puts(PACKAGE_STRING);
- puts(DISTRIBUTION);
- puts(SYSTEMD_FEATURES);
-
- return 0;
-}
-
-static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds, bool serialize_jobs) {
- FILE *f = NULL;
- FDSet *fds = NULL;
- int r;
-
- assert(m);
- assert(_f);
- assert(_fds);
-
- /* Make sure nothing is really destructed when we shut down */
- m->n_reloading ++;
-
- r = manager_open_serialization(m, &f);
- if (r < 0) {
- log_error("Failed to create serialization file: %s", strerror(-r));
- goto fail;
- }
-
- fds = fdset_new();
- if (!fds) {
- r = -ENOMEM;
- log_error("Failed to allocate fd set: %s", strerror(-r));
- goto fail;
- }
-
- r = manager_serialize(m, f, fds, serialize_jobs);
- if (r < 0) {
- log_error("Failed to serialize state: %s", strerror(-r));
- goto fail;
- }
-
- if (fseeko(f, 0, SEEK_SET) < 0) {
- log_error("Failed to rewind serialization fd: %m");
- goto fail;
- }
-
- r = fd_cloexec(fileno(f), false);
- if (r < 0) {
- log_error("Failed to disable O_CLOEXEC for serialization: %s", strerror(-r));
- goto fail;
- }
-
- r = fdset_cloexec(fds, false);
- if (r < 0) {
- log_error("Failed to disable O_CLOEXEC for serialization fds: %s", strerror(-r));
- goto fail;
- }
-
- *_f = f;
- *_fds = fds;
-
- return 0;
-
-fail:
- fdset_free(fds);
-
- if (f)
- fclose(f);
-
- return r;
-}
-
-static int bump_rlimit_nofile(struct rlimit *saved_rlimit) {
- struct rlimit nl;
- int r;
-
- assert(saved_rlimit);
-
- /* Save the original RLIMIT_NOFILE so that we can reset it
- * later when transitioning from the initrd to the main
- * systemd or suchlike. */
- if (getrlimit(RLIMIT_NOFILE, saved_rlimit) < 0) {
- log_error("Reading RLIMIT_NOFILE failed: %m");
- return -errno;
- }
-
- /* 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) {
- log_error("Setting RLIMIT_NOFILE failed: %s", strerror(-r));
- return r;
- }
-
- return 0;
-}
-
-static struct dual_timestamp* parse_initrd_timestamp(struct dual_timestamp *t) {
- const char *e;
- unsigned long long a, b;
-
- assert(t);
-
- e = getenv("RD_TIMESTAMP");
- if (!e)
- return NULL;
-
- if (sscanf(e, "%llu %llu", &a, &b) != 2)
- return NULL;
-
- t->realtime = (usec_t) a;
- t->monotonic = (usec_t) b;
-
- return t;
-}
-
-static void test_mtab(void) {
- char *p;
-
- /* Check that /etc/mtab is a symlink */
-
- if (readlink_malloc("/etc/mtab", &p) >= 0) {
- bool b;
-
- b = streq(p, "/proc/self/mounts") || streq(p, "/proc/mounts");
- free(p);
-
- if (b)
- return;
- }
-
- log_warning("/etc/mtab is not a symlink or not pointing to /proc/self/mounts. "
- "This is not supported anymore. "
- "Please make sure to replace this file by a symlink to avoid incorrect or misleading mount(8) output.");
-}
-
-static void test_usr(void) {
-
- /* Check that /usr is not a separate fs */
-
- if (dir_is_empty("/usr") <= 0)
- return;
-
- log_warning("/usr appears to be on its own filesytem 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 void test_cgroups(void) {
-
- if (access("/proc/cgroups", F_OK) >= 0)
- return;
-
- log_warning("CONFIG_CGROUPS was not set when your kernel was compiled. "
- "Systems without control groups are not supported. "
- "We will now sleep for 10s, and then continue boot-up. "
- "Expect breakage and please do not file bugs. "
- "Instead fix your kernel and enable CONFIG_CGROUPS. "
- "Consult http://0pointer.de/blog/projects/cgroups-vs-cgroups.html for more information.");
-
- sleep(10);
-}
-
-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" does'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])
- return -ENOMEM;
-
- arg_join_controllers[1] = strv_new("net_cls", "net_prio", NULL);
- if (!arg_join_controllers[1])
- return -ENOMEM;
-
- arg_join_controllers[2] = NULL;
- return 0;
-}
-
-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 = { 0ULL, 0ULL };
- static char systemd[] = "systemd";
- bool skip_setup = false;
- int j;
- bool loaded_policy = false;
- bool arm_reboot_watchdog = false;
- bool queue_default_job = false;
- char *switch_root_dir = NULL, *switch_root_init = NULL;
- static struct rlimit saved_rlimit_nofile = { 0, 0 };
-
-#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("Failed to exec " SYSTEMCTL_BINARY_PATH ": %m");
- return 1;
- }
-#endif
-
- /* 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. */
- for (j = 1; j < argc; j++)
- if (streq(argv[j], "--deserialize")) {
- skip_setup = true;
- break;
- }
-
- /* If we have switched root, do all the special setup
- * things */
- for (j = 1; j < argc; j++)
- if (streq(argv[j], "--switched-root")) {
- skip_setup = false;
- break;
- }
-
- /* 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);
-
- if (getpid() == 1 && detect_container(NULL) <= 0) {
-
- /* Running outside of a container as PID 1 */
- arg_running_as = SYSTEMD_SYSTEM;
- make_null_stdio();
- log_set_target(LOG_TARGET_KMSG);
- log_open();
-
- if (in_initrd()) {
- char *rd_timestamp = NULL;
-
- dual_timestamp_get(&initrd_timestamp);
- asprintf(&rd_timestamp, "%llu %llu",
- (unsigned long long) initrd_timestamp.realtime,
- (unsigned long long) initrd_timestamp.monotonic);
- if (rd_timestamp) {
- setenv("RD_TIMESTAMP", rd_timestamp, 1);
- free(rd_timestamp);
- }
- }
-
- if (!skip_setup) {
- if (selinux_setup(&loaded_policy) < 0)
- goto finish;
- if (ima_setup() < 0)
- goto finish;
- }
-
- if (label_init(NULL) < 0)
- goto finish;
-
- if (!skip_setup) {
- if (hwclock_is_localtime() > 0) {
- int min;
-
- /* The first-time call to settimeofday() does a time warp in the kernel */
- r = hwclock_set_timezone(&min);
- if (r < 0)
- log_error("Failed to apply local time delta, ignoring: %s", strerror(-r));
- else
- log_info("RTC configured in localtime, applying delta of %i minutes to system time.", min);
- } else if (!in_initrd()) {
- /*
- * Do dummy first-time 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.
- */
- hwclock_reset_timezone();
-
- /* Tell the kernel our time zone */
- r = hwclock_set_timezone(NULL);
- if (r < 0)
- log_error("Failed to set the kernel's time zone, ignoring: %s", strerror(-r));
- }
- }
-
- /* Set the default for later on, but don't actually
- * open the logs like this for now. Note that if we
- * are transitioning from the initrd there might still
- * be journal fd open, and we shouldn't attempt
- * opening that before we parsed /proc/cmdline which
- * might redirect output elsewhere. */
- log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
-
- } else if (getpid() == 1) {
-
- /* Running inside a container, as PID 1 */
- arg_running_as = SYSTEMD_SYSTEM;
- log_set_target(LOG_TARGET_CONSOLE);
- log_open();
-
- /* For the later on, see above... */
- log_set_target(LOG_TARGET_JOURNAL);
-
- } else {
-
- /* Running as user instance */
- arg_running_as = SYSTEMD_USER;
- log_set_target(LOG_TARGET_AUTO);
- log_open();
- }
-
- /* Initialize default unit */
- r = set_default_unit(SPECIAL_DEFAULT_TARGET);
- if (r < 0) {
- log_error("Failed to set default unit %s: %s", SPECIAL_DEFAULT_TARGET, strerror(-r));
- goto finish;
- }
-
- r = initialize_join_controllers();
- if (r < 0)
- goto finish;
-
- /* Mount /proc, /sys and friends, so that /proc/cmdline and
- * /proc/$PID/fd is available. */
- if (geteuid() == 0 && !getenv("SYSTEMD_SKIP_API_MOUNTS")) {
- r = mount_setup(loaded_policy);
- if (r < 0)
- goto finish;
- }
-
- /* Reset all signal handlers. */
- assert_se(reset_all_signal_handlers() == 0);
-
- /* If we are init, we can block sigkill. Yay. */
- ignore_signals(SIGNALS_IGNORE, -1);
-
- if (parse_config_file() < 0)
- goto finish;
-
- if (arg_running_as == SYSTEMD_SYSTEM)
- if (parse_proc_cmdline() < 0)
- goto finish;
-
- log_parse_environment();
-
- if (parse_argv(argc, argv) < 0)
- goto finish;
-
- if (arg_action == ACTION_TEST &&
- geteuid() == 0) {
- log_error("Don't run test mode as root.");
- goto finish;
- }
-
- if (arg_running_as == SYSTEMD_USER &&
- arg_action == ACTION_RUN &&
- sd_booted() <= 0) {
- log_error("Trying to run as user instance, but the system has not been booted with systemd.");
- goto finish;
- }
-
- if (arg_running_as == SYSTEMD_SYSTEM &&
- arg_action == ACTION_RUN &&
- running_in_chroot() > 0) {
- log_error("Cannot be run in a chroot() environment.");
- goto finish;
- }
-
- if (arg_action == ACTION_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;
- }
-
- 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 */
- if (serialization) {
- r = fdset_new_fill(&fds);
- if (r < 0) {
- log_error("Failed to allocate fd set: %s", strerror(-r));
- goto finish;
- }
-
- assert_se(fdset_remove(fds, fileno(serialization)) >= 0);
- } else
- close_all_fds(NULL, 0);
-
- /* Set up PATH unless it is already set */
- setenv("PATH",
-#ifdef HAVE_SPLIT_USR
- "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
-#else
- "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin",
-#endif
- arg_running_as == SYSTEMD_SYSTEM);
-
- if (arg_running_as == SYSTEMD_SYSTEM) {
- /* Parse the data passed to us. We leave this
- * variables set, but the manager later on will not
- * pass them on to our children. */
- if (!in_initrd())
- parse_initrd_timestamp(&initrd_timestamp);
-
- /* Unset some environment variables passed in from the
- * kernel that don't really make sense for us. */
- unsetenv("HOME");
- unsetenv("TERM");
-
- /* When we are invoked by a shell, these might be set,
- * but make little sense to pass on */
- unsetenv("PWD");
- unsetenv("SHLVL");
- unsetenv("_");
-
- /* When we are invoked by a chroot-like tool such as
- * nspawn, these might be set, but make little sense
- * to pass on */
- unsetenv("USER");
- unsetenv("LOGNAME");
-
- /* All other variables are left as is, so that clients
- * can still read them via /proc/1/environ */
- }
-
- /* Move out of the way, so that we won't block unmounts */
- assert_se(chdir("/") == 0);
-
- if (arg_running_as == SYSTEMD_SYSTEM) {
- /* Become a session leader if we aren't one yet. */
- setsid();
-
- /* Disable the umask logic */
- umask(0);
- }
-
- /* Make sure D-Bus doesn't fiddle with the SIGPIPE handlers */
- dbus_connection_set_change_sigpipe(FALSE);
-
- /* Reset the console, but only if this is really init and we
- * are freshly booted */
- if (arg_running_as == SYSTEMD_SYSTEM && arg_action == ACTION_RUN)
- console_setup(getpid() == 1 && !skip_setup);
-
- /* Open the logging devices, if possible and necessary */
- log_open();
-
- /* Make sure we leave a core dump without panicing the
- * kernel. */
- if (getpid() == 1)
- install_crash_handler();
-
- if (geteuid() == 0 && !getenv("SYSTEMD_SKIP_API_MOUNTS")) {
- r = mount_cgroup_controllers(arg_join_controllers);
- if (r < 0)
- goto finish;
- }
-
- if (arg_running_as == SYSTEMD_SYSTEM) {
- const char *virtualization = NULL;
-
- log_info(PACKAGE_STRING " running in system mode. (" SYSTEMD_FEATURES "; " DISTRIBUTION ")");
-
- detect_virtualization(&virtualization);
- if (virtualization)
- log_info("Detected virtualization '%s'.", virtualization);
-
- if (in_initrd())
- log_info("Running in initial RAM disk.");
-
- } else
- log_debug(PACKAGE_STRING " running in user mode. (" SYSTEMD_FEATURES "; " DISTRIBUTION ")");
-
- if (arg_running_as == SYSTEMD_SYSTEM && !skip_setup) {
- locale_setup();
-
- if (arg_show_status || plymouth_running())
- status_welcome();
-
- kmod_setup();
- hostname_setup();
- machine_id_setup();
- loopback_setup();
-
- test_mtab();
- test_usr();
- test_cgroups();
- }
-
- if (arg_running_as == SYSTEMD_SYSTEM && arg_runtime_watchdog > 0)
- watchdog_set_timeout(&arg_runtime_watchdog);
-
- if (arg_timer_slack_nsec != (nsec_t) -1)
- if (prctl(PR_SET_TIMERSLACK, arg_timer_slack_nsec) < 0)
- log_error("Failed to adjust timer slack: %m");
-
- if (arg_capability_bounding_set_drop) {
- r = capability_bounding_set_drop(arg_capability_bounding_set_drop, true);
- if (r < 0) {
- log_error("Failed to drop capability bounding set: %s", strerror(-r));
- goto finish;
- }
- r = capability_bounding_set_drop_usermode(arg_capability_bounding_set_drop);
- if (r < 0) {
- log_error("Failed to drop capability bounding set of usermode helpers: %s", strerror(-r));
- goto finish;
- }
- }
-
- if (arg_running_as == SYSTEMD_USER) {
- /* Become reaper of our children */
- if (prctl(PR_SET_CHILD_SUBREAPER, 1) < 0) {
- log_warning("Failed to make us a subreaper: %m");
- if (errno == EINVAL)
- log_info("Perhaps the kernel version is too old (< 3.4?)");
- }
- }
-
- if (arg_running_as == SYSTEMD_SYSTEM)
- bump_rlimit_nofile(&saved_rlimit_nofile);
-
- r = manager_new(arg_running_as, &m);
- if (r < 0) {
- log_error("Failed to allocate manager object: %s", strerror(-r));
- goto finish;
- }
-
- m->confirm_spawn = arg_confirm_spawn;
- m->default_std_output = arg_default_std_output;
- m->default_std_error = arg_default_std_error;
- m->runtime_watchdog = arg_runtime_watchdog;
- m->shutdown_watchdog = arg_shutdown_watchdog;
-
- manager_set_default_rlimits(m, arg_default_rlimit);
-
- if (dual_timestamp_is_set(&initrd_timestamp))
- m->initrd_timestamp = initrd_timestamp;
-
- if (arg_default_controllers)
- manager_set_default_controllers(m, arg_default_controllers);
-
- manager_set_show_status(m, arg_show_status);
-
- /* Remember whether we should queue the default job */
- queue_default_job = !serialization || arg_switched_root;
-
- before_startup = now(CLOCK_MONOTONIC);
-
- r = manager_startup(m, serialization, fds);
- if (r < 0)
- log_error("Failed to fully start up daemon: %s", strerror(-r));
-
- /* This will close all file descriptors that were opened, but
- * not claimed by any unit. */
- if (fds) {
- fdset_free(fds);
- fds = NULL;
- }
-
- if (serialization) {
- fclose(serialization);
- serialization = NULL;
- }
-
- if (queue_default_job) {
- DBusError error;
- Unit *target = NULL;
- Job *default_unit_job;
-
- dbus_error_init(&error);
-
- 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(&error, r));
- dbus_error_free(&error);
- } else if (target->load_state == UNIT_ERROR)
- log_error("Failed to load default target: %s", strerror(-target->load_error));
- 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_error("Failed to load rescue target: %s", bus_error(&error, r));
- dbus_error_free(&error);
- goto finish;
- } else if (target->load_state == UNIT_ERROR) {
- log_error("Failed to load rescue target: %s", strerror(-target->load_error));
- goto finish;
- } else if (target->load_state == UNIT_MASKED) {
- log_error("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_REPLACE, false, &error, &default_unit_job);
- if (r < 0) {
- log_error("Failed to start default target: %s", bus_error(&error, r));
- dbus_error_free(&error);
- 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));
-
- 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_error("Failed to run mainloop: %s", strerror(-r));
- goto finish;
- }
-
- switch (m->exit_code) {
-
- case MANAGER_EXIT:
- retval = EXIT_SUCCESS;
- log_debug("Exit.");
- goto finish;
-
- case MANAGER_RELOAD:
- log_info("Reloading.");
- r = manager_reload(m);
- if (r < 0)
- log_error("Failed to reload: %s", strerror(-r));
- break;
-
- case MANAGER_REEXECUTE:
-
- if (prepare_reexecute(m, &serialization, &fds, true) < 0)
- 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, &serialization, &fds, false) < 0)
- goto finish;
-
- reexecute = true;
- log_notice("Switching root.");
- goto finish;
-
- case MANAGER_REBOOT:
- case MANAGER_POWEROFF:
- case MANAGER_HALT:
- case MANAGER_KEXEC: {
- static const char * const table[_MANAGER_EXIT_CODE_MAX] = {
- [MANAGER_REBOOT] = "reboot",
- [MANAGER_POWEROFF] = "poweroff",
- [MANAGER_HALT] = "halt",
- [MANAGER_KEXEC] = "kexec"
- };
-
- assert_se(shutdown_verb = table[m->exit_code]);
- arm_reboot_watchdog = m->exit_code == MANAGER_REBOOT;
-
- log_notice("Shutting down.");
- goto finish;
- }
-
- default:
- assert_not_reached("Unknown exit code.");
- }
- }
-
-finish:
- if (m)
- manager_free(m);
-
- for (j = 0; j < RLIMIT_NLIMITS; j++)
- free(arg_default_rlimit[j]);
-
- free(arg_default_unit);
- strv_free(arg_default_controllers);
- free_join_controllers();
-
- dbus_shutdown();
- label_finish();
-
- if (reexecute) {
- const char **args;
- unsigned i, args_size;
-
- /* Close and disarm the watchdog, so that the new
- * instance can reinitialize it, but doesn't get
- * rebooted while we do that */
- watchdog_close(true);
-
- /* Reset the RLIMIT_NOFILE to the kernel default, so
- * that the new systemd can pass the kernel default to
- * its child processes */
- if (saved_rlimit_nofile.rlim_cur > 0)
- setrlimit(RLIMIT_NOFILE, &saved_rlimit_nofile);
-
- if (switch_root_dir) {
- /* Kill all remaining processes from the
- * initrd, but don't wait for them, so that we
- * can handle the SIGCHLD for them after
- * deserializing. */
- broadcast_signal(SIGTERM, false);
-
- /* And switch root */
- r = switch_root(switch_root_dir);
- if (r < 0)
- log_error("Failed to switch root, ignoring: %s", strerror(-r));
- }
-
- args_size = MAX(6, argc+1);
- args = newa(const char*, args_size);
-
- if (!switch_root_init) {
- char sfd[16];
-
- /* 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(serialization);
- assert(fds);
-
- snprintf(sfd, sizeof(sfd), "%i", fileno(serialization));
- char_array_0(sfd);
-
- i = 0;
- args[i++] = SYSTEMD_BINARY_PATH;
- if (switch_root_dir)
- args[i++] = "--switched-root";
- args[i++] = arg_running_as == SYSTEMD_SYSTEM ? "--system" : "--user";
- args[i++] = "--deserialize";
- args[i++] = sfd;
- args[i++] = NULL;
-
- assert(i <= args_size);
- execv(args[0], (char* const*) args);
- }
-
- /* Try the fallback, if there is any, without any
- * serialization. We pass the original argv[] and
- * envp[]. (Well, modulo the ordering changes due to
- * getopt() in argv[], and some cleanups in envp[],
- * but let's hope that doesn't matter.) */
-
- if (serialization) {
- fclose(serialization);
- serialization = NULL;
- }
-
- if (fds) {
- fdset_free(fds);
- fds = NULL;
- }
-
- /* Reopen the console */
- make_console_stdio();
-
- for (j = 1, i = 1; j < argc; j++)
- args[i++] = argv[j];
- args[i++] = NULL;
- assert(i <= args_size);
-
- if (switch_root_init) {
- args[0] = switch_root_init;
- execv(args[0], (char* const*) args);
- log_warning("Failed to execute configured init, trying fallback: %m");
- }
-
- args[0] = "/sbin/init";
- execv(args[0], (char* const*) args);
-
- if (errno == ENOENT) {
- log_warning("No /sbin/init, trying fallback");
-
- args[0] = "/bin/sh";
- args[1] = NULL;
- execv(args[0], (char* const*) args);
- log_error("Failed to execute /bin/sh, giving up: %m");
- } else
- log_warning("Failed to execute /sbin/init, giving up: %m");
- }
-
- if (serialization)
- fclose(serialization);
-
- if (fds)
- fdset_free(fds);
-
- if (shutdown_verb) {
- const char * command_line[] = {
- SYSTEMD_SHUTDOWN_BINARY_PATH,
- shutdown_verb,
- NULL
- };
- char **env_block;
-
- if (arm_reboot_watchdog && arg_shutdown_watchdog > 0) {
- char e[32];
-
- /* If we reboot let's set the shutdown
- * watchdog and tell the shutdown binary to
- * repeatedly ping it */
- watchdog_set_timeout(&arg_shutdown_watchdog);
- watchdog_close(false);
-
- /* Tell the binary how often to ping */
- snprintf(e, sizeof(e), "WATCHDOG_USEC=%llu", (unsigned long long) arg_shutdown_watchdog);
- char_array_0(e);
-
- env_block = strv_append(environ, e);
- } else {
- env_block = strv_copy(environ);
- watchdog_close(true);
- }
-
- execve(SYSTEMD_SHUTDOWN_BINARY_PATH, (char **) command_line, env_block);
- free(env_block);
- log_error("Failed to execute shutdown binary, freezing: %m");
- }
-
- if (getpid() == 1)
- freeze();
-
- return retval;
-}
diff --git a/src/core/manager.c b/src/core/manager.c
deleted file mode 100644
index f932c79a1b..0000000000
--- a/src/core/manager.c
+++ /dev/null
@@ -1,2309 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <assert.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include <signal.h>
-#include <sys/signalfd.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <sys/poll.h>
-#include <sys/reboot.h>
-#include <sys/ioctl.h>
-#include <linux/kd.h>
-#include <termios.h>
-#include <fcntl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <dirent.h>
-
-#ifdef HAVE_AUDIT
-#include <libaudit.h>
-#endif
-
-#include "systemd/sd-daemon.h"
-#include "systemd/sd-id128.h"
-#include "systemd/sd-messages.h"
-
-#include "manager.h"
-#include "transaction.h"
-#include "hashmap.h"
-#include "macro.h"
-#include "strv.h"
-#include "log.h"
-#include "util.h"
-#include "mkdir.h"
-#include "ratelimit.h"
-#include "cgroup.h"
-#include "mount-setup.h"
-#include "unit-name.h"
-#include "dbus-unit.h"
-#include "dbus-job.h"
-#include "missing.h"
-#include "path-lookup.h"
-#include "special.h"
-#include "bus-errors.h"
-#include "exit-status.h"
-#include "virt.h"
-#include "watchdog.h"
-#include "cgroup-util.h"
-#include "path-util.h"
-#include "audit-fd.h"
-
-/* As soon as 16 units are in our GC queue, make sure to run a gc sweep */
-#define GC_QUEUE_ENTRIES_MAX 16
-
-/* As soon as 5s passed since a unit was added to our GC queue, make sure to run a gc sweep */
-#define GC_QUEUE_USEC_MAX (10*USEC_PER_SEC)
-
-/* Where clients shall send notification messages to */
-#define NOTIFY_SOCKET "@/org/freedesktop/systemd1/notify"
-
-static int manager_setup_notify(Manager *m) {
- union {
- struct sockaddr sa;
- struct sockaddr_un un;
- } sa;
- struct epoll_event ev;
- int one = 1;
-
- assert(m);
-
- m->notify_watch.type = WATCH_NOTIFY;
- m->notify_watch.fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
- if (m->notify_watch.fd < 0) {
- log_error("Failed to allocate notification socket: %m");
- return -errno;
- }
-
- zero(sa);
- sa.sa.sa_family = AF_UNIX;
-
- if (getpid() != 1 || detect_container(NULL) > 0)
- snprintf(sa.un.sun_path, sizeof(sa.un.sun_path), NOTIFY_SOCKET "/%llu", random_ull());
- else
- strncpy(sa.un.sun_path, NOTIFY_SOCKET, sizeof(sa.un.sun_path));
-
- sa.un.sun_path[0] = 0;
-
- if (bind(m->notify_watch.fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) {
- log_error("bind() failed: %m");
- return -errno;
- }
-
- if (setsockopt(m->notify_watch.fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0) {
- log_error("SO_PASSCRED failed: %m");
- return -errno;
- }
-
- zero(ev);
- ev.events = EPOLLIN;
- ev.data.ptr = &m->notify_watch;
-
- if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->notify_watch.fd, &ev) < 0)
- return -errno;
-
- sa.un.sun_path[0] = '@';
- m->notify_socket = strdup(sa.un.sun_path);
- if (!m->notify_socket)
- return -ENOMEM;
-
- log_debug("Using notification socket %s", m->notify_socket);
-
- return 0;
-}
-
-static int enable_special_signals(Manager *m) {
- int fd;
-
- assert(m);
-
- /* Enable that we get SIGINT on control-alt-del. In containers
- * this will fail with EPERM (older) or EINVAL (newer), so
- * ignore that. */
- if (reboot(RB_DISABLE_CAD) < 0 && errno != EPERM && errno != EINVAL)
- log_warning("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("Failed to open /dev/tty0: %m");
- } else {
- /* Enable that we get SIGWINCH on kbrequest */
- if (ioctl(fd, KDSIGACCEPT, SIGWINCH) < 0)
- log_warning("Failed to enable kbrequest handling: %s", strerror(errno));
-
- close_nointr_nofail(fd);
- }
-
- return 0;
-}
-
-static int manager_setup_signals(Manager *m) {
- sigset_t mask;
- struct epoll_event ev;
- struct sigaction sa;
-
- assert(m);
-
- /* We are not interested in SIGSTOP and friends. */
- zero(sa);
- sa.sa_handler = SIG_DFL;
- sa.sa_flags = SA_NOCLDSTOP|SA_RESTART;
- assert_se(sigaction(SIGCHLD, &sa, NULL) == 0);
-
- 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 */
- SIGRTMIN+13, /* systemd: Immediate halt */
- SIGRTMIN+14, /* systemd: Immediate poweroff */
- SIGRTMIN+15, /* systemd: Immediate reboot */
- SIGRTMIN+16, /* systemd: Immediate kexec */
- 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) */
- 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 */
- -1);
- assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
-
- m->signal_watch.type = WATCH_SIGNAL;
- if ((m->signal_watch.fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0)
- return -errno;
-
- zero(ev);
- ev.events = EPOLLIN;
- ev.data.ptr = &m->signal_watch;
-
- if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->signal_watch.fd, &ev) < 0)
- return -errno;
-
- if (m->running_as == SYSTEMD_SYSTEM)
- return enable_special_signals(m);
-
- return 0;
-}
-
-static void manager_strip_environment(Manager *m) {
- assert(m);
-
- /* Remove variables from the inherited set that are part of
- * the container interface:
- * http://www.freedesktop.org/wiki/Software/systemd/ContainerInterface */
- strv_remove_prefix(m->environment, "container=");
- strv_remove_prefix(m->environment, "container_");
-
- /* Remove variables from the inherited set that are part of
- * the initrd interface:
- * http://www.freedesktop.org/wiki/Software/systemd/InitrdInterface */
- strv_remove_prefix(m->environment, "RD_");
-}
-
-int manager_new(SystemdRunningAs running_as, Manager **_m) {
- Manager *m;
- int r = -ENOMEM;
-
- assert(_m);
- assert(running_as >= 0);
- assert(running_as < _SYSTEMD_RUNNING_AS_MAX);
-
- m = new0(Manager, 1);
- if (!m)
- return -ENOMEM;
-
- dual_timestamp_get(&m->userspace_timestamp);
-
- m->running_as = running_as;
- m->name_data_slot = m->conn_data_slot = m->subscribed_data_slot = -1;
- m->exit_code = _MANAGER_EXIT_CODE_INVALID;
- m->pin_cgroupfs_fd = -1;
- m->idle_pipe[0] = m->idle_pipe[1] = -1;
-
- m->signal_watch.fd = m->mount_watch.fd = m->udev_watch.fd = m->epoll_fd = m->dev_autofs_fd = m->swap_watch.fd = -1;
- m->current_job_id = 1; /* start as id #1, so that we can leave #0 around as "null-like" value */
-
- m->environment = strv_copy(environ);
- if (!m->environment)
- goto fail;
-
- manager_strip_environment(m);
-
- if (running_as == SYSTEMD_SYSTEM) {
- m->default_controllers = strv_new("cpu", NULL);
- if (!m->default_controllers)
- goto fail;
- }
-
- if (!(m->units = hashmap_new(string_hash_func, string_compare_func)))
- goto fail;
-
- if (!(m->jobs = hashmap_new(trivial_hash_func, trivial_compare_func)))
- goto fail;
-
- if (!(m->watch_pids = hashmap_new(trivial_hash_func, trivial_compare_func)))
- goto fail;
-
- if (!(m->cgroup_bondings = hashmap_new(string_hash_func, string_compare_func)))
- goto fail;
-
- if (!(m->watch_bus = hashmap_new(string_hash_func, string_compare_func)))
- goto fail;
-
- if ((m->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0)
- goto fail;
-
- if ((r = manager_setup_signals(m)) < 0)
- goto fail;
-
- if ((r = manager_setup_cgroup(m)) < 0)
- goto fail;
-
- if ((r = manager_setup_notify(m)) < 0)
- goto fail;
-
- /* Try to connect to the busses, if possible. */
- if ((r = bus_init(m, running_as != SYSTEMD_SYSTEM)) < 0)
- goto fail;
-
- m->taint_usr = dir_is_empty("/usr") > 0;
-
- *_m = m;
- return 0;
-
-fail:
- manager_free(m);
- return r;
-}
-
-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);
-
- if ((m->n_in_gc_queue < GC_QUEUE_ENTRIES_MAX) &&
- (m->gc_queue_timestamp <= 0 ||
- (m->gc_queue_timestamp + GC_QUEUE_USEC_MAX) > now(CLOCK_MONOTONIC)))
- return 0;
-
- 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(Unit, 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) {
- log_debug("Collecting %s", u->id);
- u->gc_marker = gc_marker + GC_OFFSET_BAD;
- unit_add_to_cleanup_queue(u);
- }
- }
-
- m->n_in_gc_queue = 0;
- m->gc_queue_timestamp = 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));
-}
-
-void manager_free(Manager *m) {
- UnitType c;
- int i;
-
- assert(m);
-
- 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_pids);
- hashmap_free(m->watch_bus);
-
- if (m->epoll_fd >= 0)
- close_nointr_nofail(m->epoll_fd);
- if (m->signal_watch.fd >= 0)
- close_nointr_nofail(m->signal_watch.fd);
- if (m->notify_watch.fd >= 0)
- close_nointr_nofail(m->notify_watch.fd);
-
- free(m->notify_socket);
-
- lookup_paths_free(&m->lookup_paths);
- strv_free(m->environment);
-
- strv_free(m->default_controllers);
-
- hashmap_free(m->cgroup_bondings);
- set_free_free(m->unit_path_cache);
-
- close_pipe(m->idle_pipe);
-
- free(m->switch_root);
- free(m->switch_root_init);
-
- for (i = 0; i < RLIMIT_NLIMITS; i++)
- free(m->rlimit[i]);
-
- free(m);
-}
-
-int manager_enumerate(Manager *m) {
- int r = 0, q;
- 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_vtable[c]->enumerate)
- if ((q = unit_vtable[c]->enumerate(m)) < 0)
- r = q;
-
- manager_dispatch_load_queue(m);
- return r;
-}
-
-int manager_coldplug(Manager *m) {
- int r = 0, q;
- Iterator i;
- Unit *u;
- char *k;
-
- 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;
-
- if ((q = unit_coldplug(u)) < 0)
- r = q;
- }
-
- return r;
-}
-
-static void manager_build_unit_path_cache(Manager *m) {
- char **i;
- DIR *d = NULL;
- int r;
-
- assert(m);
-
- set_free_free(m->unit_path_cache);
-
- if (!(m->unit_path_cache = set_new(string_hash_func, string_compare_func))) {
- 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;
-
- if (!(d = opendir(*i))) {
- log_error("Failed to open directory: %m");
- continue;
- }
-
- while ((de = readdir(d))) {
- char *p;
-
- if (ignore_file(de->d_name))
- continue;
-
- p = strjoin(streq(*i, "/") ? "" : *i, "/", de->d_name, NULL);
- if (!p) {
- r = -ENOMEM;
- goto fail;
- }
-
- if ((r = set_put(m->unit_path_cache, p)) < 0) {
- free(p);
- goto fail;
- }
- }
-
- closedir(d);
- d = NULL;
- }
-
- return;
-
-fail:
- log_error("Failed to build unit path cache: %s", strerror(-r));
-
- set_free_free(m->unit_path_cache);
- m->unit_path_cache = NULL;
-
- if (d)
- closedir(d);
-}
-
-int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
- int r, q;
-
- assert(m);
-
- manager_run_generators(m);
-
- r = lookup_paths_init(
- &m->lookup_paths, m->running_as, true,
- 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 */
- r = manager_enumerate(m);
-
- /* Second, deserialize if there is something to deserialize */
- if (serialization) {
- q = manager_deserialize(m, serialization, fds);
- if (q < 0)
- r = q;
- }
-
- /* Third, fire things up! */
- q = manager_coldplug(m);
- if (q < 0)
- r = q;
-
- if (serialization) {
- assert(m->n_reloading > 0);
- m->n_reloading --;
- }
-
- return r;
-}
-
-int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, DBusError *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) {
- dbus_set_error(e, BUS_ERROR_INVALID_JOB_MODE, "Isolate is only valid for start.");
- return -EINVAL;
- }
-
- if (mode == JOB_ISOLATE && !unit->allow_isolate) {
- dbus_set_error(e, BUS_ERROR_NO_ISOLATION, "Operation refused, unit may not be isolated.");
- return -EPERM;
- }
-
- log_debug("Trying to enqueue job %s/%s/%s", unit->id, job_type_to_string(type), job_mode_to_string(mode));
-
- job_type_collapse(&type, unit);
-
- tr = transaction_new();
- if (!tr)
- return -ENOMEM;
-
- r = transaction_add_job_and_dependencies(tr, type, unit, NULL, true, override, false,
- mode == JOB_IGNORE_DEPENDENCIES || mode == JOB_IGNORE_REQUIREMENTS,
- mode == JOB_IGNORE_DEPENDENCIES, e);
- if (r < 0)
- goto tr_abort;
-
- if (mode == JOB_ISOLATE) {
- r = transaction_add_isolate_jobs(tr, m);
- if (r < 0)
- goto tr_abort;
- }
-
- r = transaction_activate(tr, m, mode, e);
- if (r < 0)
- goto tr_abort;
-
- log_debug("Enqueued job %s/%s as %u", unit->id, job_type_to_string(type), (unsigned) tr->anchor_job->id);
-
- if (_ret)
- *_ret = tr->anchor_job;
-
- transaction_free(tr);
- return 0;
-
-tr_abort:
- transaction_abort(tr);
- transaction_free(tr);
- return r;
-}
-
-int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool override, DBusError *e, Job **_ret) {
- Unit *unit;
- int r;
-
- assert(m);
- assert(type < _JOB_TYPE_MAX);
- assert(name);
- assert(mode < _JOB_MODE_MAX);
-
- r = manager_load_unit(m, name, NULL, NULL, &unit);
- if (r < 0)
- return r;
-
- return manager_add_job(m, type, unit, mode, override, e, _ret);
-}
-
-Job *manager_get_job(Manager *m, uint32_t id) {
- assert(m);
-
- return hashmap_get(m->jobs, UINT32_TO_PTR(id));
-}
-
-Unit *manager_get_unit(Manager *m, const char *name) {
- assert(m);
- assert(name);
-
- return hashmap_get(m->units, name);
-}
-
-unsigned manager_dispatch_load_queue(Manager *m) {
- Unit *u;
- unsigned n = 0;
-
- assert(m);
-
- /* Make sure we are not run recursively */
- if (m->dispatching_load_queue)
- return 0;
-
- m->dispatching_load_queue = true;
-
- /* Dispatches the load queue. Takes a unit from the queue and
- * tries to load its data until the queue is empty */
-
- while ((u = m->load_queue)) {
- assert(u->in_load_queue);
-
- unit_load(u);
- n++;
- }
-
- m->dispatching_load_queue = false;
- return n;
-}
-
-int manager_load_unit_prepare(Manager *m, const char *name, const char *path, DBusError *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)) {
- dbus_set_error(e, BUS_ERROR_INVALID_PATH, "Path %s is not absolute.", path);
- return -EINVAL;
- }
-
- if (!name)
- name = path_get_file_name(path);
-
- t = unit_name_to_type(name);
-
- if (t == _UNIT_TYPE_INVALID || !unit_name_is_valid(name, false)) {
- dbus_set_error(e, BUS_ERROR_INVALID_NAME, "Unit name %s is not valid.", name);
- return -EINVAL;
- }
-
- 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;
- }
- }
-
- if ((r = unit_add_name(ret, name)) < 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, DBusError *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);
-}
-
-unsigned manager_dispatch_run_queue(Manager *m) {
- Job *j;
- unsigned n = 0;
-
- if (m->dispatching_run_queue)
- return 0;
-
- m->dispatching_run_queue = true;
-
- while ((j = m->run_queue)) {
- assert(j->installed);
- assert(j->in_run_queue);
-
- job_run_and_invalidate(j);
- n++;
- }
-
- m->dispatching_run_queue = false;
- return n;
-}
-
-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;
- return n;
-}
-
-static int manager_process_notify_fd(Manager *m) {
- ssize_t n;
-
- assert(m);
-
- for (;;) {
- char buf[4096];
- struct msghdr msghdr;
- struct iovec iovec;
- struct ucred *ucred;
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(struct ucred))];
- } control;
- Unit *u;
- char **tags;
-
- zero(iovec);
- iovec.iov_base = buf;
- iovec.iov_len = sizeof(buf)-1;
-
- zero(control);
- zero(msghdr);
- msghdr.msg_iov = &iovec;
- msghdr.msg_iovlen = 1;
- msghdr.msg_control = &control;
- msghdr.msg_controllen = sizeof(control);
-
- if ((n = recvmsg(m->notify_watch.fd, &msghdr, MSG_DONTWAIT)) <= 0) {
- if (n >= 0)
- return -EIO;
-
- if (errno == EAGAIN || errno == EINTR)
- break;
-
- return -errno;
- }
-
- if (msghdr.msg_controllen < CMSG_LEN(sizeof(struct ucred)) ||
- control.cmsghdr.cmsg_level != SOL_SOCKET ||
- control.cmsghdr.cmsg_type != SCM_CREDENTIALS ||
- control.cmsghdr.cmsg_len != CMSG_LEN(sizeof(struct ucred))) {
- log_warning("Received notify message without credentials. Ignoring.");
- continue;
- }
-
- ucred = (struct ucred*) CMSG_DATA(&control.cmsghdr);
-
- if (!(u = hashmap_get(m->watch_pids, LONG_TO_PTR(ucred->pid))))
- if (!(u = cgroup_unit_by_pid(m, ucred->pid))) {
- log_warning("Cannot find unit for notify message of PID %lu.", (unsigned long) ucred->pid);
- continue;
- }
-
- assert((size_t) n < sizeof(buf));
- buf[n] = 0;
- if (!(tags = strv_split(buf, "\n\r")))
- return -ENOMEM;
-
- log_debug("Got notification message for unit %s", u->id);
-
- if (UNIT_VTABLE(u)->notify_message)
- UNIT_VTABLE(u)->notify_message(u, ucred->pid, tags);
-
- strv_free(tags);
- }
-
- return 0;
-}
-
-static int manager_dispatch_sigchld(Manager *m) {
- assert(m);
-
- for (;;) {
- siginfo_t si;
- Unit *u;
- int r;
-
- zero(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) {
- char *name = NULL;
-
- get_process_comm(si.si_pid, &name);
- log_debug("Got SIGCHLD for process %lu (%s)", (unsigned long) si.si_pid, strna(name));
- free(name);
- }
-
- /* Let's flush any message the dying child might still
- * have queued for us. This ensures that the process
- * still exists in /proc so that we can figure out
- * which cgroup and hence unit it belongs to. */
- if ((r = manager_process_notify_fd(m)) < 0)
- return r;
-
- /* And now figure out the unit this belongs to */
- if (!(u = hashmap_get(m->watch_pids, LONG_TO_PTR(si.si_pid))))
- u = cgroup_unit_by_pid(m, si.si_pid);
-
- /* And now, we actually reap the zombie. */
- if (waitid(P_PID, si.si_pid, &si, WEXITED) < 0) {
- if (errno == EINTR)
- continue;
-
- return -errno;
- }
-
- if (si.si_code != CLD_EXITED && si.si_code != CLD_KILLED && si.si_code != CLD_DUMPED)
- continue;
-
- log_debug("Child %lu died (code=%s, status=%i/%s)",
- (long unsigned) si.si_pid,
- 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)));
-
- if (!u)
- continue;
-
- log_debug("Child %lu belongs to %s", (long unsigned) si.si_pid, u->id);
-
- hashmap_remove(m->watch_pids, LONG_TO_PTR(si.si_pid));
- UNIT_VTABLE(u)->sigchld_event(u, si.si_pid, si.si_code, si.si_status);
- }
-
- return 0;
-}
-
-static int manager_start_target(Manager *m, const char *name, JobMode mode) {
- int r;
- DBusError error;
-
- dbus_error_init(&error);
-
- log_debug("Activating special unit %s", name);
-
- if ((r = manager_add_job_by_name(m, JOB_START, name, mode, true, &error, NULL)) < 0)
- log_error("Failed to enqueue %s job: %s", name, bus_error(&error, r));
-
- dbus_error_free(&error);
-
- return r;
-}
-
-static int manager_process_signal_fd(Manager *m) {
- ssize_t n;
- struct signalfd_siginfo sfsi;
- bool sigchld = false;
-
- assert(m);
-
- for (;;) {
- if ((n = read(m->signal_watch.fd, &sfsi, sizeof(sfsi))) != sizeof(sfsi)) {
-
- if (n >= 0)
- return -EIO;
-
- if (errno == EINTR || errno == EAGAIN)
- break;
-
- return -errno;
- }
-
- if (sfsi.ssi_pid > 0) {
- char *p = NULL;
-
- get_process_comm(sfsi.ssi_pid, &p);
-
- log_debug("Received SIG%s from PID %lu (%s).",
- signal_to_string(sfsi.ssi_signo),
- (unsigned long) sfsi.ssi_pid, strna(p));
- free(p);
- } else
- log_debug("Received SIG%s.", signal_to_string(sfsi.ssi_signo));
-
- switch (sfsi.ssi_signo) {
-
- case SIGCHLD:
- sigchld = true;
- break;
-
- case SIGTERM:
- if (m->running_as == SYSTEMD_SYSTEM) {
- /* This is for compatibility with the
- * original sysvinit */
- m->exit_code = MANAGER_REEXECUTE;
- break;
- }
-
- /* Fall through */
-
- case SIGINT:
- if (m->running_as == SYSTEMD_SYSTEM) {
- manager_start_target(m, SPECIAL_CTRL_ALT_DEL_TARGET, JOB_REPLACE);
- break;
- }
-
- /* Run the exit target if there is one, if not, just exit. */
- if (manager_start_target(m, SPECIAL_EXIT_TARGET, JOB_REPLACE) < 0) {
- m->exit_code = MANAGER_EXIT;
- return 0;
- }
-
- break;
-
- case SIGWINCH:
- if (m->running_as == SYSTEMD_SYSTEM)
- manager_start_target(m, SPECIAL_KBREQUEST_TARGET, JOB_REPLACE);
-
- /* This is a nop on non-init */
- break;
-
- case SIGPWR:
- if (m->running_as == SYSTEMD_SYSTEM)
- manager_start_target(m, SPECIAL_SIGPWR_TARGET, JOB_REPLACE);
-
- /* This is a nop on non-init */
- break;
-
- case SIGUSR1: {
- Unit *u;
-
- u = manager_get_unit(m, SPECIAL_DBUS_SERVICE);
-
- if (!u || UNIT_IS_ACTIVE_OR_RELOADING(unit_active_state(u))) {
- log_info("Trying to reconnect to bus...");
- bus_init(m, true);
- }
-
- if (!u || !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u))) {
- log_info("Loading D-Bus service...");
- manager_start_target(m, SPECIAL_DBUS_SERVICE, JOB_REPLACE);
- }
-
- break;
- }
-
- case SIGUSR2: {
- FILE *f;
- char *dump = NULL;
- size_t size;
-
- if (!(f = open_memstream(&dump, &size))) {
- log_warning("Failed to allocate memory stream.");
- break;
- }
-
- manager_dump_units(m, f, "\t");
- manager_dump_jobs(m, f, "\t");
-
- if (ferror(f)) {
- fclose(f);
- free(dump);
- log_warning("Failed to write status stream");
- break;
- }
-
- fclose(f);
- log_dump(LOG_INFO, dump);
- free(dump);
-
- break;
- }
-
- case SIGHUP:
- m->exit_code = MANAGER_RELOAD;
- break;
-
- default: {
-
- /* Starting SIGRTMIN+0 */
- static const char * const target_table[] = {
- [0] = SPECIAL_DEFAULT_TARGET,
- [1] = SPECIAL_RESCUE_TARGET,
- [2] = SPECIAL_EMERGENCY_TARGET,
- [3] = SPECIAL_HALT_TARGET,
- [4] = SPECIAL_POWEROFF_TARGET,
- [5] = SPECIAL_REBOOT_TARGET,
- [6] = SPECIAL_KEXEC_TARGET
- };
-
- /* Starting SIGRTMIN+13, so that target halt and system halt are 10 apart */
- static const ManagerExitCode code_table[] = {
- [0] = MANAGER_HALT,
- [1] = MANAGER_POWEROFF,
- [2] = MANAGER_REBOOT,
- [3] = MANAGER_KEXEC
- };
-
- if ((int) sfsi.ssi_signo >= SIGRTMIN+0 &&
- (int) sfsi.ssi_signo < SIGRTMIN+(int) ELEMENTSOF(target_table)) {
- int idx = (int) sfsi.ssi_signo - SIGRTMIN;
- manager_start_target(m, target_table[idx],
- (idx == 1 || idx == 2) ? JOB_ISOLATE : JOB_REPLACE);
- break;
- }
-
- if ((int) sfsi.ssi_signo >= SIGRTMIN+13 &&
- (int) sfsi.ssi_signo < SIGRTMIN+13+(int) ELEMENTSOF(code_table)) {
- m->exit_code = code_table[sfsi.ssi_signo - SIGRTMIN - 13];
- break;
- }
-
- switch (sfsi.ssi_signo - SIGRTMIN) {
-
- case 20:
- log_debug("Enabling showing of status.");
- manager_set_show_status(m, true);
- break;
-
- case 21:
- log_debug("Disabling showing of status.");
- manager_set_show_status(m, false);
- break;
-
- case 22:
- log_set_max_level(LOG_DEBUG);
- log_notice("Setting log level to debug.");
- break;
-
- case 23:
- log_set_max_level(LOG_INFO);
- log_notice("Setting log level to info.");
- break;
-
- case 24:
- if (m->running_as == SYSTEMD_USER) {
- m->exit_code = MANAGER_EXIT;
- return 0;
- }
-
- /* This is a nop on init */
- break;
-
- case 26:
- 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;
-
- case 29:
- log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
- log_notice("Setting log target to syslog-or-kmsg.");
- break;
-
- default:
- log_warning("Got unhandled signal <%s>.", signal_to_string(sfsi.ssi_signo));
- }
- }
- }
- }
-
- if (sigchld)
- return manager_dispatch_sigchld(m);
-
- return 0;
-}
-
-static int process_event(Manager *m, struct epoll_event *ev) {
- int r;
- Watch *w;
-
- assert(m);
- assert(ev);
-
- assert_se(w = ev->data.ptr);
-
- if (w->type == WATCH_INVALID)
- return 0;
-
- switch (w->type) {
-
- case WATCH_SIGNAL:
-
- /* An incoming signal? */
- if (ev->events != EPOLLIN)
- return -EINVAL;
-
- if ((r = manager_process_signal_fd(m)) < 0)
- return r;
-
- break;
-
- case WATCH_NOTIFY:
-
- /* An incoming daemon notification event? */
- if (ev->events != EPOLLIN)
- return -EINVAL;
-
- if ((r = manager_process_notify_fd(m)) < 0)
- return r;
-
- break;
-
- case WATCH_FD:
-
- /* Some fd event, to be dispatched to the units */
- UNIT_VTABLE(w->data.unit)->fd_event(w->data.unit, w->fd, ev->events, w);
- break;
-
- case WATCH_UNIT_TIMER:
- case WATCH_JOB_TIMER: {
- uint64_t v;
- ssize_t k;
-
- /* Some timer event, to be dispatched to the units */
- if ((k = read(w->fd, &v, sizeof(v))) != sizeof(v)) {
-
- if (k < 0 && (errno == EINTR || errno == EAGAIN))
- break;
-
- return k < 0 ? -errno : -EIO;
- }
-
- if (w->type == WATCH_UNIT_TIMER)
- UNIT_VTABLE(w->data.unit)->timer_event(w->data.unit, v, w);
- else
- job_timer_event(w->data.job, v, w);
- break;
- }
-
- case WATCH_MOUNT:
- /* Some mount table change, intended for the mount subsystem */
- mount_fd_event(m, ev->events);
- break;
-
- case WATCH_SWAP:
- /* Some swap table change, intended for the swap subsystem */
- swap_fd_event(m, ev->events);
- break;
-
- case WATCH_UDEV:
- /* Some notification from udev, intended for the device subsystem */
- device_fd_event(m, ev->events);
- break;
-
- case WATCH_DBUS_WATCH:
- bus_watch_event(m, w, ev->events);
- break;
-
- case WATCH_DBUS_TIMEOUT:
- bus_timeout_event(m, w, ev->events);
- break;
-
- default:
- log_error("event type=%i", w->type);
- assert_not_reached("Unknown epoll event type.");
- }
-
- return 0;
-}
-
-int manager_loop(Manager *m) {
- int r;
-
- RATELIMIT_DEFINE(rl, 1*USEC_PER_SEC, 50000);
-
- assert(m);
- m->exit_code = MANAGER_RUNNING;
-
- /* Release the path cache */
- set_free_free(m->unit_path_cache);
- m->unit_path_cache = NULL;
-
- manager_check_finished(m);
-
- /* There might still be some zombies hanging around from
- * before we were exec()'ed. Leat's reap them */
- r = manager_dispatch_sigchld(m);
- if (r < 0)
- return r;
-
- while (m->exit_code == MANAGER_RUNNING) {
- struct epoll_event event;
- int n;
- int wait_msec = -1;
-
- if (m->runtime_watchdog > 0 && m->running_as == SYSTEMD_SYSTEM)
- watchdog_ping();
-
- if (!ratelimit_test(&rl)) {
- /* Yay, something is going seriously wrong, pause a little */
- log_warning("Looping too fast. Throttling execution a little.");
- sleep(1);
- continue;
- }
-
- if (manager_dispatch_load_queue(m) > 0)
- continue;
-
- if (manager_dispatch_run_queue(m) > 0)
- continue;
-
- if (bus_dispatch(m) > 0)
- continue;
-
- if (manager_dispatch_cleanup_queue(m) > 0)
- continue;
-
- if (manager_dispatch_gc_queue(m) > 0)
- continue;
-
- if (manager_dispatch_dbus_queue(m) > 0)
- continue;
-
- if (swap_dispatch_reload(m) > 0)
- continue;
-
- /* Sleep for half the watchdog time */
- if (m->runtime_watchdog > 0 && m->running_as == SYSTEMD_SYSTEM) {
- wait_msec = (int) (m->runtime_watchdog / 2 / USEC_PER_MSEC);
- if (wait_msec <= 0)
- wait_msec = 1;
- } else
- wait_msec = -1;
-
- n = epoll_wait(m->epoll_fd, &event, 1, wait_msec);
- if (n < 0) {
-
- if (errno == EINTR)
- continue;
-
- return -errno;
- } else if (n == 0)
- continue;
-
- assert(n == 1);
-
- r = process_event(m, &event);
- if (r < 0)
- return r;
- }
-
- return m->exit_code;
-}
-
-int manager_load_unit_from_dbus_path(Manager *m, const char *s, DBusError *e, Unit **_u) {
- char *n;
- Unit *u;
- int r;
-
- assert(m);
- assert(s);
- assert(_u);
-
- if (!startswith(s, "/org/freedesktop/systemd1/unit/"))
- return -EINVAL;
-
- n = bus_path_unescape(s+31);
- if (!n)
- return -ENOMEM;
-
- r = manager_load_unit(m, n, NULL, e, &u);
- free(n);
-
- if (r < 0)
- return r;
-
- *_u = u;
-
- return 0;
-}
-
-int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j) {
- Job *j;
- unsigned id;
- int r;
-
- assert(m);
- assert(s);
- assert(_j);
-
- if (!startswith(s, "/org/freedesktop/systemd1/job/"))
- return -EINVAL;
-
- if ((r = safe_atou(s + 30, &id)) < 0)
- return r;
-
- if (!(j = manager_get_job(m, id)))
- return -ENOENT;
-
- *_j = j;
-
- return 0;
-}
-
-void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
-
-#ifdef HAVE_AUDIT
- char *p;
- int audit_fd;
-
- audit_fd = get_audit_fd();
- if (audit_fd < 0)
- return;
-
- /* Don't generate audit events if the service was already
- * started and we're just deserializing */
- if (m->n_reloading > 0)
- return;
-
- if (m->running_as != SYSTEMD_SYSTEM)
- return;
-
- if (u->type != UNIT_SERVICE)
- return;
-
- if (!(p = unit_name_to_prefix_and_instance(u->id))) {
- log_error("Failed to allocate unit name for audit message: %s", strerror(ENOMEM));
- return;
- }
-
- if (audit_log_user_comm_message(audit_fd, type, "", p, 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("Failed to send audit message: %m");
- }
-
- free(p);
-#endif
-
-}
-
-void manager_send_unit_plymouth(Manager *m, Unit *u) {
- int fd = -1;
- union sockaddr_union sa;
- int n = 0;
- char *message = NULL;
-
- /* Don't generate plymouth events if the service was already
- * started and we're just deserializing */
- if (m->n_reloading > 0)
- return;
-
- if (m->running_as != SYSTEMD_SYSTEM)
- return;
-
- if (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 */
- if ((fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) {
- log_error("socket() failed: %m");
- return;
- }
-
- zero(sa);
- sa.sa.sa_family = AF_UNIX;
- strncpy(sa.un.sun_path+1, "/org/freedesktop/plymouthd", sizeof(sa.un.sun_path)-1);
- if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) {
-
- if (errno != EPIPE &&
- errno != EAGAIN &&
- errno != ENOENT &&
- errno != ECONNREFUSED &&
- errno != ECONNRESET &&
- errno != ECONNABORTED)
- log_error("connect() failed: %m");
-
- goto finish;
- }
-
- if (asprintf(&message, "U\002%c%s%n", (int) (strlen(u->id) + 1), u->id, &n) < 0) {
- log_oom();
- goto finish;
- }
-
- errno = 0;
- if (write(fd, message, n + 1) != n + 1) {
-
- if (errno != EPIPE &&
- errno != EAGAIN &&
- errno != ENOENT &&
- errno != ECONNREFUSED &&
- errno != ECONNRESET &&
- errno != ECONNABORTED)
- log_error("Failed to write Plymouth message: %m");
-
- goto finish;
- }
-
-finish:
- if (fd >= 0)
- close_nointr_nofail(fd);
-
- free(message);
-}
-
-void manager_dispatch_bus_name_owner_changed(
- Manager *m,
- const char *name,
- const char* old_owner,
- const char *new_owner) {
-
- Unit *u;
-
- assert(m);
- assert(name);
-
- if (!(u = hashmap_get(m->watch_bus, name)))
- return;
-
- UNIT_VTABLE(u)->bus_name_owner_change(u, name, old_owner, new_owner);
-}
-
-void manager_dispatch_bus_query_pid_done(
- Manager *m,
- const char *name,
- pid_t pid) {
-
- Unit *u;
-
- assert(m);
- assert(name);
- assert(pid >= 1);
-
- if (!(u = hashmap_get(m->watch_bus, name)))
- return;
-
- UNIT_VTABLE(u)->bus_query_pid_done(u, name, pid);
-}
-
-int manager_open_serialization(Manager *m, FILE **_f) {
- char *path = NULL;
- mode_t saved_umask;
- int fd;
- FILE *f;
-
- assert(_f);
-
- if (m->running_as == SYSTEMD_SYSTEM)
- asprintf(&path, "/run/systemd/dump-%lu-XXXXXX", (unsigned long) getpid());
- else
- asprintf(&path, "/tmp/systemd-dump-%lu-XXXXXX", (unsigned long) getpid());
-
- if (!path)
- return -ENOMEM;
-
- saved_umask = umask(0077);
- fd = mkostemp(path, O_RDWR|O_CLOEXEC);
- umask(saved_umask);
-
- if (fd < 0) {
- free(path);
- return -errno;
- }
-
- unlink(path);
-
- log_debug("Serializing state to %s", path);
- free(path);
-
- if (!(f = fdopen(fd, "w+")))
- return -errno;
-
- *_f = f;
-
- return 0;
-}
-
-int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool serialize_jobs) {
- Iterator i;
- Unit *u;
- const char *t;
- int r;
-
- assert(m);
- assert(f);
- assert(fds);
-
- m->n_reloading ++;
-
- fprintf(f, "current-job-id=%i\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, "kernel-timestamp", &m->kernel_timestamp);
- dual_timestamp_serialize(f, "loader-timestamp", &m->loader_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);
- }
-
- fputc('\n', f);
-
- HASHMAP_FOREACH_KEY(u, t, m->units, i) {
- if (u->id != t)
- continue;
-
- if (!unit_can_serialize(u))
- continue;
-
- /* Start marker */
- fputs(u->id, f);
- fputc('\n', f);
-
- if ((r = unit_serialize(u, f, fds, serialize_jobs)) < 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;
-
- if ((b = parse_boolean(l+10)) < 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
- 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);
-
- if ((r = manager_load_unit(m, strstrip(name), NULL, NULL, &u)) < 0)
- goto finish;
-
- if ((r = unit_deserialize(u, f, fds)) < 0)
- goto finish;
- }
-
-finish:
- if (ferror(f)) {
- r = -EIO;
- goto finish;
- }
-
- assert(m->n_reloading > 0);
- m->n_reloading --;
-
- return r;
-}
-
-int manager_reload(Manager *m) {
- int r, q;
- FILE *f;
- FDSet *fds;
-
- assert(m);
-
- r = manager_open_serialization(m, &f);
- if (r < 0)
- return r;
-
- m->n_reloading ++;
-
- fds = fdset_new();
- if (!fds) {
- m->n_reloading --;
- r = -ENOMEM;
- goto finish;
- }
-
- r = manager_serialize(m, f, fds, true);
- if (r < 0) {
- m->n_reloading --;
- goto finish;
- }
-
- if (fseeko(f, 0, SEEK_SET) < 0) {
- m->n_reloading --;
- r = -errno;
- goto finish;
- }
-
- /* 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 */
- manager_run_generators(m);
-
- q = lookup_paths_init(
- &m->lookup_paths, m->running_as, true,
- m->generator_unit_path,
- m->generator_unit_path_early,
- m->generator_unit_path_late);
- if (q < 0)
- r = q;
-
- manager_build_unit_path_cache(m);
-
- /* First, enumerate what we can from all config files */
- q = manager_enumerate(m);
- if (q < 0)
- r = q;
-
- /* Second, deserialize our stored data */
- q = manager_deserialize(m, f, fds);
- if (q < 0)
- r = q;
-
- fclose(f);
- f = NULL;
-
- /* Third, fire things up! */
- q = manager_coldplug(m);
- if (q < 0)
- r = q;
-
- assert(m->n_reloading > 0);
- m->n_reloading--;
-
-finish:
- if (f)
- fclose(f);
-
- if (fds)
- fdset_free(fds);
-
- return r;
-}
-
-bool manager_is_booting_or_shutting_down(Manager *m) {
- Unit *u;
-
- assert(m);
-
- /* Is the initial job still around? */
- if (manager_get_job(m, m->default_unit_job_id))
- return true;
-
- /* Is there a job for the shutdown target? */
- u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET);
- if (u)
- return !!u->job;
-
- return false;
-}
-
-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_pending_inactive(Manager *m, const char *name) {
- Unit *u;
-
- assert(m);
- assert(name);
-
- /* Returns true if the unit is inactive or going down */
- if (!(u = manager_get_unit(m, name)))
- return true;
-
- return unit_pending_inactive(u);
-}
-
-void manager_check_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;
-
- assert(m);
-
- if (hashmap_size(m->jobs) > 0)
- return;
-
- /* Notify Type=idle units that we are done now */
- close_pipe(m->idle_pipe);
-
- /* Turn off confirm spawn now */
- m->confirm_spawn = false;
-
- if (dual_timestamp_is_set(&m->finish_timestamp))
- return;
-
- dual_timestamp_get(&m->finish_timestamp);
-
- if (m->running_as == SYSTEMD_SYSTEM && detect_container(NULL) <= 0) {
-
- /* Note that m->kernel_usec.monotonic is always at 0,
- * and m->firmware_usec.monotonic and
- * m->loader_usec.monotonic should be considered
- * negative values. */
-
- firmware_usec = m->firmware_timestamp.monotonic - m->loader_timestamp.monotonic;
- loader_usec = m->loader_timestamp.monotonic - m->kernel_timestamp.monotonic;
- userspace_usec = m->finish_timestamp.monotonic - m->userspace_timestamp.monotonic;
- total_usec = m->firmware_timestamp.monotonic + m->finish_timestamp.monotonic;
-
- if (dual_timestamp_is_set(&m->initrd_timestamp)) {
-
- kernel_usec = m->initrd_timestamp.monotonic - m->kernel_timestamp.monotonic;
- initrd_usec = m->userspace_timestamp.monotonic - m->initrd_timestamp.monotonic;
-
- if (!log_on_console())
- log_struct(LOG_INFO,
- MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
- "KERNEL_USEC=%llu", (unsigned long long) kernel_usec,
- "INITRD_USEC=%llu", (unsigned long long) initrd_usec,
- "USERSPACE_USEC=%llu", (unsigned long long) userspace_usec,
- "MESSAGE=Startup finished in %s (kernel) + %s (initrd) + %s (userspace) = %s.",
- format_timespan(kernel, sizeof(kernel), kernel_usec),
- format_timespan(initrd, sizeof(initrd), initrd_usec),
- format_timespan(userspace, sizeof(userspace), userspace_usec),
- format_timespan(sum, sizeof(sum), total_usec),
- NULL);
- } else {
- kernel_usec = m->userspace_timestamp.monotonic - m->kernel_timestamp.monotonic;
- initrd_usec = 0;
-
- if (!log_on_console())
- log_struct(LOG_INFO,
- MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
- "KERNEL_USEC=%llu", (unsigned long long) kernel_usec,
- "USERSPACE_USEC=%llu", (unsigned long long) userspace_usec,
- "MESSAGE=Startup finished in %s (kernel) + %s (userspace) = %s.",
- format_timespan(kernel, sizeof(kernel), kernel_usec),
- format_timespan(userspace, sizeof(userspace), userspace_usec),
- format_timespan(sum, sizeof(sum), total_usec),
- NULL);
- }
- } else {
- firmware_usec = loader_usec = initrd_usec = kernel_usec = 0;
- total_usec = userspace_usec = m->finish_timestamp.monotonic - m->userspace_timestamp.monotonic;
-
- if (!log_on_console())
- log_struct(LOG_INFO,
- MESSAGE_ID(SD_MESSAGE_STARTUP_FINISHED),
- "USERSPACE_USEC=%llu", (unsigned long long) userspace_usec,
- "MESSAGE=Startup finished in %s.",
- format_timespan(sum, sizeof(sum), total_usec),
- NULL);
- }
-
- bus_broadcast_finished(m, firmware_usec, loader_usec, kernel_usec, initrd_usec, userspace_usec, total_usec);
-
- sd_notifyf(false,
- "READY=1\nSTATUS=Startup finished in %s.",
- format_timespan(sum, sizeof(sum), total_usec));
-}
-
-static int create_generator_dir(Manager *m, char **generator, const char *name) {
- char *p;
- int r;
-
- assert(m);
- assert(generator);
- assert(name);
-
- if (*generator)
- return 0;
-
- if (m->running_as == SYSTEMD_SYSTEM && getpid() == 1) {
-
- p = strappend("/run/systemd/", name);
- if (!p)
- return log_oom();
-
- r = mkdir_p_label(p, 0755);
- if (r < 0) {
- log_error("Failed to create generator directory: %s", strerror(-r));
- free(p);
- return r;
- }
- } else {
- p = strjoin("/tmp/systemd-", name, ".XXXXXX", NULL);
- if (!p)
- return log_oom();
-
- if (!mkdtemp(p)) {
- free(p);
- log_error("Failed to create generator directory: %m");
- return -errno;
- }
- }
-
- *generator = p;
- return 0;
-}
-
-static void trim_generator_dir(Manager *m, char **generator) {
- assert(m);
- assert(generator);
-
- if (!*generator)
- return;
-
- if (rmdir(*generator) >= 0) {
- free(*generator);
- *generator = NULL;
- }
-
- return;
-}
-
-void manager_run_generators(Manager *m) {
- DIR *d = NULL;
- const char *generator_path;
- const char *argv[5];
- mode_t u;
- int r;
-
- assert(m);
-
- generator_path = m->running_as == SYSTEMD_SYSTEM ? SYSTEM_GENERATOR_PATH : USER_GENERATOR_PATH;
- d = opendir(generator_path);
- if (!d) {
- if (errno == ENOENT)
- return;
-
- log_error("Failed to enumerate generator directory: %m");
- return;
- }
-
- 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;
-
- u = umask(0022);
- execute_directory(generator_path, d, (char**) argv);
- umask(u);
-
- 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);
-
-finish:
- if (d)
- closedir(d);
-}
-
-static void remove_generator_dir(Manager *m, char **generator) {
- assert(m);
- assert(generator);
-
- if (!*generator)
- return;
-
- strv_remove(m->lookup_paths.unit_path, *generator);
- rm_rf(*generator, false, true, false);
-
- free(*generator);
- *generator = NULL;
-}
-
-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_set_default_controllers(Manager *m, char **controllers) {
- char **l;
-
- assert(m);
-
- l = strv_copy(controllers);
- if (!l)
- return -ENOMEM;
-
- strv_free(m->default_controllers);
- m->default_controllers = l;
-
- cg_shorten_controllers(m->default_controllers);
-
- return 0;
-}
-
-int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit) {
- int i;
-
- assert(m);
-
- for (i = 0; i < RLIMIT_NLIMITS; i++) {
- if (!default_rlimit[i])
- continue;
-
- m->rlimit[i] = newdup(struct rlimit, default_rlimit[i], 1);
- if (!m->rlimit[i])
- return -ENOMEM;
- }
-
- return 0;
-}
-
-void manager_recheck_journal(Manager *m) {
- Unit *u;
-
- assert(m);
-
- if (m->running_as != SYSTEMD_SYSTEM)
- return;
-
- u = manager_get_unit(m, SPECIAL_JOURNALD_SOCKET);
- if (u && SOCKET(u)->state != SOCKET_RUNNING) {
- log_close_journal();
- return;
- }
-
- u = manager_get_unit(m, SPECIAL_JOURNALD_SERVICE);
- if (u && SERVICE(u)->state != SERVICE_RUNNING) {
- log_close_journal();
- return;
- }
-
- /* Hmm, OK, so the socket is fully up and the service is up
- * too, then let's make use of the thing. */
- log_open();
-}
-
-void manager_set_show_status(Manager *m, bool b) {
- assert(m);
-
- if (m->running_as != SYSTEMD_SYSTEM)
- return;
-
- m->show_status = b;
-
- if (b)
- touch("/run/systemd/show-status");
- else
- unlink("/run/systemd/show-status");
-}
-
-bool manager_get_show_status(Manager *m) {
- assert(m);
-
- if (m->running_as != SYSTEMD_SYSTEM)
- return false;
-
- if (m->show_status)
- return true;
-
- /* If Plymouth is running make sure we show the status, so
- * that there's something nice to see when people press Esc */
-
- return plymouth_running();
-}
diff --git a/src/core/manager.h b/src/core/manager.h
deleted file mode 100644
index 22145024f1..0000000000
--- a/src/core/manager.h
+++ /dev/null
@@ -1,293 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-#include <inttypes.h>
-#include <stdio.h>
-#include <dbus/dbus.h>
-
-#include "fdset.h"
-
-/* Enforce upper limit how many names we allow */
-#define MANAGER_MAX_NAMES 131072 /* 128K */
-
-typedef struct Manager Manager;
-typedef enum WatchType WatchType;
-typedef struct Watch Watch;
-
-typedef enum ManagerExitCode {
- MANAGER_RUNNING,
- 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;
-
-enum WatchType {
- WATCH_INVALID,
- WATCH_SIGNAL,
- WATCH_NOTIFY,
- WATCH_FD,
- WATCH_UNIT_TIMER,
- WATCH_JOB_TIMER,
- WATCH_MOUNT,
- WATCH_SWAP,
- WATCH_UDEV,
- WATCH_DBUS_WATCH,
- WATCH_DBUS_TIMEOUT
-};
-
-struct Watch {
- int fd;
- WatchType type;
- union {
- struct Unit *unit;
- struct Job *job;
- DBusWatch *bus_watch;
- DBusTimeout *bus_timeout;
- } data;
- bool fd_is_dupped:1;
- bool socket_accept:1;
-};
-
-#include "unit.h"
-#include "job.h"
-#include "hashmap.h"
-#include "list.h"
-#include "set.h"
-#include "dbus.h"
-#include "path-lookup.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]);
-
- /* To optimize iteration of units that have requires_mounts_for set */
- LIST_HEAD(Unit, has_requires_mounts_for);
-
- /* 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);
-
- Hashmap *watch_pids; /* pid => Unit object n:1 */
-
- char *notify_socket;
-
- Watch notify_watch;
- Watch signal_watch;
-
- int epoll_fd;
-
- unsigned n_snapshots;
-
- LookupPaths lookup_paths;
- Set *unit_path_cache;
-
- char **environment;
- char **default_controllers;
-
- 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;
-
- char *generator_unit_path;
- char *generator_unit_path_early;
- char *generator_unit_path_late;
-
- /* Data specific to the device subsystem */
- struct udev* udev;
- struct udev_monitor* udev_monitor;
- Watch udev_watch;
- Hashmap *devices_by_sysfs;
-
- /* Data specific to the mount subsystem */
- FILE *proc_self_mountinfo;
- Watch mount_watch;
-
- /* Data specific to the swap filesystem */
- FILE *proc_swaps;
- Hashmap *swaps_by_proc_swaps;
- bool request_reload;
- Watch swap_watch;
-
- /* Data specific to the D-Bus subsystem */
- DBusConnection *api_bus, *system_bus;
- DBusServer *private_bus;
- Set *bus_connections, *bus_connections_for_dispatch;
-
- DBusMessage *queued_message; /* This is used during reloading:
- * before the reload we queue the
- * reply message here, and
- * afterwards we send it */
- DBusConnection *queued_message_connection; /* The connection to send the queued message on */
-
- Hashmap *watch_bus; /* D-Bus names => Unit object n:1 */
- int32_t name_data_slot;
- int32_t conn_data_slot;
- int32_t subscribed_data_slot;
-
- 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_bondings; /* path string => CGroupBonding object 1:n */
- char *cgroup_hierarchy;
-
- usec_t gc_queue_timestamp;
- int gc_marker;
- unsigned n_in_gc_queue;
-
- /* Make sure the user cannot accidentally unmount our cgroup
- * file system */
- int pin_cgroupfs_fd;
-
- /* Flags */
- SystemdRunningAs running_as;
- ManagerExitCode exit_code:5;
-
- bool dispatching_load_queue:1;
- bool dispatching_run_queue:1;
- bool dispatching_dbus_queue:1;
-
- bool taint_usr:1;
-
- bool show_status;
- bool confirm_spawn;
-
- ExecOutput default_std_output, default_std_error;
-
- struct rlimit *rlimit[RLIMIT_NLIMITS];
-
- /* non-zero if we are reloading or reexecuting, */
- int n_reloading;
-
- unsigned n_installed_jobs;
- unsigned n_failed_jobs;
-
- /* Type=idle pipes */
- int idle_pipe[2];
-
- char *switch_root;
- char *switch_root_init;
-};
-
-int manager_new(SystemdRunningAs running_as, Manager **m);
-void manager_free(Manager *m);
-
-int manager_enumerate(Manager *m);
-int manager_coldplug(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, DBusError *e, Unit **_ret);
-int manager_load_unit(Manager *m, const char *name, const char *path, DBusError *e, Unit **_ret);
-int manager_load_unit_from_dbus_path(Manager *m, const char *s, DBusError *e, Unit **_u);
-
-int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool force, DBusError *e, Job **_ret);
-int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool force, DBusError *e, Job **_ret);
-
-void manager_dump_units(Manager *s, FILE *f, const char *prefix);
-void manager_dump_jobs(Manager *s, FILE *f, const char *prefix);
-
-void manager_clear_jobs(Manager *m);
-
-unsigned manager_dispatch_load_queue(Manager *m);
-unsigned manager_dispatch_run_queue(Manager *m);
-unsigned manager_dispatch_dbus_queue(Manager *m);
-
-int manager_set_default_controllers(Manager *m, char **controllers);
-int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit);
-
-int manager_loop(Manager *m);
-
-void manager_dispatch_bus_name_owner_changed(Manager *m, const char *name, const char* old_owner, const char *new_owner);
-void manager_dispatch_bus_query_pid_done(Manager *m, const char *name, pid_t pid);
-
-int manager_open_serialization(Manager *m, FILE **_f);
-
-int manager_serialize(Manager *m, FILE *f, FDSet *fds, bool serialize_jobs);
-int manager_deserialize(Manager *m, FILE *f, FDSet *fds);
-
-int manager_reload(Manager *m);
-
-bool manager_is_booting_or_shutting_down(Manager *m);
-
-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_pending_inactive(Manager *m, const char *name);
-
-void manager_check_finished(Manager *m);
-
-void manager_run_generators(Manager *m);
-void manager_undo_generators(Manager *m);
-
-void manager_recheck_journal(Manager *m);
-
-void manager_set_show_status(Manager *m, bool b);
-bool manager_get_show_status(Manager *m);
diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c
deleted file mode 100644
index 98614d0c3e..0000000000
--- a/src/core/mount-setup.c
+++ /dev/null
@@ -1,441 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/mount.h>
-#include <errno.h>
-#include <sys/stat.h>
-#include <stdlib.h>
-#include <string.h>
-#include <libgen.h>
-#include <assert.h>
-#include <unistd.h>
-#include <ftw.h>
-
-#include "mount-setup.h"
-#include "dev-setup.h"
-#include "log.h"
-#include "macro.h"
-#include "util.h"
-#include "label.h"
-#include "set.h"
-#include "strv.h"
-#include "mkdir.h"
-#include "path-util.h"
-#include "missing.h"
-#include "virt.h"
-
-#ifndef TTY_GID
-#define TTY_GID 5
-#endif
-
-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. */
-#define N_EARLY_MOUNT 4
-
-static const MountPoint mount_table[] = {
- { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
- NULL, MNT_FATAL|MNT_IN_CONTAINER },
- { "sysfs", "/sys", "sysfs", 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 },
- { "efivarfs", "/sys/firmware/efi/efivars", "efivarfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
- is_efiboot, MNT_NONE },
- { "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 },
- { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
- NULL, MNT_FATAL|MNT_IN_CONTAINER },
- { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
- NULL, MNT_IN_CONTAINER },
- { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV,
- NULL, 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"
- "/selinux\0"
- /* Legacy cgroup mount points */
- "/dev/cgroup\0"
- "/cgroup\0"
- /* Legacy kernel file system */
- "/proc/bus/usb\0"
- /* Container bind mounts */
- "/proc/sys\0"
- "/dev/console\0"
- "/proc/kmsg\0";
-
-bool mount_point_is_api(const char *path) {
- unsigned i;
-
- /* Checks if this mount point is considered "API", and hence
- * should be ignored */
-
- for (i = 0; i < ELEMENTSOF(mount_table); i ++)
- if (path_equal(path, mount_table[i].where))
- return true;
-
- return path_startswith(path, "/sys/fs/cgroup/");
-}
-
-bool mount_point_ignore(const char *path) {
- const char *i;
-
- NULSTR_FOREACH(i, ignore_paths)
- if (path_equal(path, i))
- return true;
-
- return false;
-}
-
-static int mount_one(const MountPoint *p, bool relabel) {
- int r;
-
- assert(p);
-
- if (p->condition_fn && !p->condition_fn())
- return 0;
-
- /* Relabel first, just in case */
- if (relabel)
- label_fix(p->where, true, true);
-
- r = path_is_mount_point(p->where, true);
- if (r < 0)
- return r;
-
- if (r > 0)
- return 0;
-
- /* Skip securityfs in a container */
- if (!(p->mode & MNT_IN_CONTAINER) && detect_container(NULL) > 0)
- return 0;
-
- /* The access mode here doesn't really matter too much, since
- * the mounted file system will take precedence anyway. */
- mkdir_p_label(p->where, 0755);
-
- log_debug("Mounting %s to %s of type %s with options %s.",
- p->what,
- p->where,
- p->type,
- strna(p->options));
-
- if (mount(p->what,
- p->where,
- p->type,
- p->flags,
- p->options) < 0) {
- log_full((p->mode & MNT_FATAL) ? LOG_ERR : LOG_DEBUG, "Failed to mount %s: %s", p->where, strerror(errno));
- return (p->mode & MNT_FATAL) ? -errno : 0;
- }
-
- /* Relabel again, since we now mounted something fresh here */
- if (relabel)
- label_fix(p->where, false, false);
-
- return 1;
-}
-
-int mount_setup_early(void) {
- unsigned i;
- int r = 0;
-
- assert_cc(N_EARLY_MOUNT <= ELEMENTSOF(mount_table));
-
- /* Do a minimal mount of /proc and friends to enable the most
- * basic stuff, such as SELinux */
- for (i = 0; i < N_EARLY_MOUNT; i ++) {
- int j;
-
- j = mount_one(mount_table + i, false);
- if (r == 0)
- r = j;
- }
-
- return r;
-}
-
-int mount_cgroup_controllers(char ***join_controllers) {
- int r;
- FILE *f;
- char buf[LINE_MAX];
- Set *controllers;
-
- /* Mount all available cgroup controllers that are built into the kernel. */
-
- f = fopen("/proc/cgroups", "re");
- if (!f) {
- log_error("Failed to enumerate cgroup controllers: %m");
- return 0;
- }
-
- controllers = set_new(string_hash_func, string_compare_func);
- if (!controllers) {
- r = log_oom();
- goto finish;
- }
-
- /* Ignore the header line */
- (void) fgets(buf, sizeof(buf), f);
-
- for (;;) {
- char *controller;
- int enabled = 0;
-
- if (fscanf(f, "%ms %*i %*i %i", &controller, &enabled) != 2) {
-
- if (feof(f))
- break;
-
- log_error("Failed to parse /proc/cgroups.");
- r = -EIO;
- goto finish;
- }
-
- if (!enabled) {
- free(controller);
- continue;
- }
-
- r = set_put(controllers, controller);
- if (r < 0) {
- log_error("Failed to add controller to set.");
- free(controller);
- goto finish;
- }
- }
-
- for (;;) {
- MountPoint p;
- char *controller, *where, *options;
- 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)) {
- char *t;
-
- t = set_remove(controllers, *i);
- if (!t) {
- free(*i);
- continue;
- }
- free(t);
- }
-
- *(j++) = *i;
- }
-
- *j = NULL;
-
- options = strv_join(*k, ",");
- if (!options) {
- free(controller);
- r = log_oom();
- goto finish;
- }
-
- } else {
- options = controller;
- controller = NULL;
- }
-
- where = strappend("/sys/fs/cgroup/", options);
- if (!where) {
- free(options);
- r = log_oom();
- goto finish;
- }
-
- zero(p);
- p.what = "cgroup";
- p.where = where;
- p.type = "cgroup";
- p.options = options;
- p.flags = MS_NOSUID|MS_NOEXEC|MS_NODEV;
-
- r = mount_one(&p, true);
- free(controller);
- free(where);
-
- if (r < 0) {
- free(options);
- goto finish;
- }
-
- if (r > 0 && k && *k) {
- char **i;
-
- for (i = *k; *i; i++) {
- char *t;
-
- t = strappend("/sys/fs/cgroup/", *i);
- if (!t) {
- r = log_oom();
- free(options);
- goto finish;
- }
-
- r = symlink(options, t);
- free(t);
-
- if (r < 0 && errno != EEXIST) {
- log_error("Failed to create symlink: %m");
- r = -errno;
- free(options);
- goto finish;
- }
- }
- }
-
- free(options);
- }
-
- r = 0;
-
-finish:
- set_free_free(controllers);
-
- fclose(f);
-
- return r;
-}
-
-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;
-};
-
-int mount_setup(bool loaded_policy) {
-
- static const char relabel[] =
- "/run/initramfs/root-fsck\0"
- "/run/initramfs/shutdown\0";
-
- int r;
- unsigned i;
- const char *j;
-
- for (i = 0; i < ELEMENTSOF(mount_table); i ++) {
- r = mount_one(mount_table + i, true);
-
- if (r < 0)
- return r;
- }
-
- /* 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);
-
- /* Explicitly relabel these */
- NULSTR_FOREACH(j, relabel)
- label_fix(j, true, false);
-
- after_relabel = now(CLOCK_MONOTONIC);
-
- log_info("Relabelled /dev and /run in %s.",
- format_timespan(timespan, sizeof(timespan), after_relabel - before_relabel));
- }
-
- /* Create a few default symlinks, which are normally created
- * by udevd, but some scripts might need them before we start
- * udevd. */
- dev_setup(NULL);
-
- /* Mark the root directory as shared in regards to mount
- * propagation. The kernel defaults to "private", but we think
- * it makes more sense to have a default of "shared" so that
- * nspawn and the container tools work out of the box. If
- * specific setups need other settings they can reset the
- * propagation mode to private if needed. */
- if (detect_container(NULL) <= 0)
- if (mount(NULL, "/", NULL, MS_REC|MS_SHARED, NULL) < 0)
- log_warning("Failed to set up the root directory for shared mount propagation: %m");
-
- /* Create a few directories we always want around */
- mkdir_label("/run/systemd", 0755);
- mkdir_label("/run/systemd/system", 0755);
-
- return 0;
-}
diff --git a/src/core/mount-setup.h b/src/core/mount-setup.h
deleted file mode 100644
index 4b521ad0e1..0000000000
--- a/src/core/mount-setup.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-
-int mount_setup_early(void);
-
-int mount_setup(bool loaded_policy);
-
-int mount_cgroup_controllers(char ***join_controllers);
-
-bool mount_point_is_api(const char *path);
-bool mount_point_ignore(const char *path);
diff --git a/src/core/mount.c b/src/core/mount.c
deleted file mode 100644
index 14f4863dc6..0000000000
--- a/src/core/mount.c
+++ /dev/null
@@ -1,1885 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <stdio.h>
-#include <mntent.h>
-#include <sys/epoll.h>
-#include <signal.h>
-
-#include "unit.h"
-#include "mount.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
-#include "log.h"
-#include "strv.h"
-#include "mkdir.h"
-#include "path-util.h"
-#include "mount-setup.h"
-#include "unit-name.h"
-#include "dbus-mount.h"
-#include "special.h"
-#include "bus-errors.h"
-#include "exit-status.h"
-#include "def.h"
-
-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 void mount_init(Unit *u) {
- Mount *m = MOUNT(u);
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
-
- m->timeout_usec = DEFAULT_TIMEOUT_USEC;
- m->directory_mode = 0755;
-
- exec_context_init(&m->exec_context);
-
- if (unit_has_name(u, "-.mount")) {
- /* Don't allow start/stop for root directory */
- UNIT(m)->refuse_manual_start = true;
- UNIT(m)->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;
- }
-
- kill_context_init(&m->kill_context);
-
- /* We need to make sure that /bin/mount is always called in
- * the same process group as us, so that the autofs kernel
- * side doesn't send us another mount request while we are
- * already trying to comply its last one. */
- m->exec_context.same_pgrp = true;
-
- m->timer_watch.type = WATCH_INVALID;
-
- m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
-
- UNIT(m)->ignore_on_isolate = true;
-}
-
-static void mount_unwatch_control_pid(Mount *m) {
- assert(m);
-
- if (m->control_pid <= 0)
- return;
-
- unit_unwatch_pid(UNIT(m), m->control_pid);
- m->control_pid = 0;
-}
-
-static void mount_parameters_done(MountParameters *p) {
- assert(p);
-
- free(p->what);
- free(p->options);
- free(p->fstype);
-
- p->what = p->options = p->fstype = NULL;
-}
-
-static void mount_done(Unit *u) {
- Mount *m = MOUNT(u);
-
- assert(m);
-
- free(m->where);
- m->where = NULL;
-
- mount_parameters_done(&m->parameters_proc_self_mountinfo);
- mount_parameters_done(&m->parameters_fragment);
-
- exec_context_done(&m->exec_context);
- exec_command_done_array(m->exec_command, _MOUNT_EXEC_COMMAND_MAX);
- m->control_command = NULL;
-
- mount_unwatch_control_pid(m);
-
- unit_unwatch_timer(u, &m->timer_watch);
-}
-
-static MountParameters* get_mount_parameters_fragment(Mount *m) {
- assert(m);
-
- if (m->from_fragment)
- return &m->parameters_fragment;
-
- return NULL;
-}
-
-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) {
- Unit *other;
- int r;
- MountParameters *pm;
-
- assert(m);
-
- pm = get_mount_parameters_fragment(m);
-
- /* Adds in links to other mount points that might lie below or
- * above us in the hierarchy */
-
- LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_MOUNT]) {
- Mount *n = MOUNT(other);
- MountParameters *pn;
-
- if (n == m)
- continue;
-
- if (UNIT(n)->load_state != UNIT_LOADED)
- continue;
-
- pn = get_mount_parameters_fragment(n);
-
- if (path_startswith(m->where, n->where)) {
-
- if ((r = unit_add_dependency(UNIT(m), UNIT_AFTER, UNIT(n), true)) < 0)
- return r;
-
- if (pn)
- if ((r = unit_add_dependency(UNIT(m), UNIT_REQUIRES, UNIT(n), true)) < 0)
- return r;
-
- } else if (path_startswith(n->where, m->where)) {
-
- if ((r = unit_add_dependency(UNIT(n), UNIT_AFTER, UNIT(m), true)) < 0)
- return r;
-
- if (pm)
- if ((r = unit_add_dependency(UNIT(n), UNIT_REQUIRES, UNIT(m), true)) < 0)
- return r;
-
- } else if (pm && pm->what && path_startswith(pm->what, n->where)) {
-
- if ((r = unit_add_dependency(UNIT(m), UNIT_AFTER, UNIT(n), true)) < 0)
- return r;
-
- if ((r = unit_add_dependency(UNIT(m), UNIT_REQUIRES, UNIT(n), true)) < 0)
- return r;
-
- } else if (pn && pn->what && path_startswith(pn->what, m->where)) {
-
- if ((r = unit_add_dependency(UNIT(n), UNIT_AFTER, UNIT(m), true)) < 0)
- return r;
-
- if ((r = unit_add_dependency(UNIT(n), UNIT_REQUIRES, UNIT(m), true)) < 0)
- return r;
- }
- }
-
- return 0;
-}
-
-static int mount_add_swap_links(Mount *m) {
- Unit *other;
- int r;
-
- assert(m);
-
- LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_SWAP])
- if ((r = swap_add_one_mount_link(SWAP(other), m)) < 0)
- return r;
-
- return 0;
-}
-
-static int mount_add_path_links(Mount *m) {
- Unit *other;
- int r;
-
- assert(m);
-
- LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_PATH])
- if ((r = path_add_one_mount_link(PATH(other), m)) < 0)
- return r;
-
- return 0;
-}
-
-static int mount_add_automount_links(Mount *m) {
- Unit *other;
- int r;
-
- assert(m);
-
- LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_AUTOMOUNT])
- if ((r = automount_add_one_mount_link(AUTOMOUNT(other), m)) < 0)
- return r;
-
- return 0;
-}
-
-static int mount_add_socket_links(Mount *m) {
- Unit *other;
- int r;
-
- assert(m);
-
- LIST_FOREACH(units_by_type, other, UNIT(m)->manager->units_by_type[UNIT_SOCKET])
- if ((r = socket_add_one_mount_link(SOCKET(other), m)) < 0)
- return r;
-
- return 0;
-}
-
-static int mount_add_requires_mounts_links(Mount *m) {
- Unit *other;
- int r;
-
- assert(m);
-
- LIST_FOREACH(has_requires_mounts_for, other, UNIT(m)->manager->has_requires_mounts_for) {
- r = unit_add_one_mount_link(other, m);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-static char* mount_test_option(const char *haystack, const char *needle) {
- struct mntent me;
-
- assert(needle);
-
- /* Like glibc's hasmntopt(), but works on a string, not a
- * struct mntent */
-
- if (!haystack)
- return NULL;
-
- zero(me);
- me.mnt_opts = (char*) haystack;
-
- return hasmntopt(&me, needle);
-}
-
-static bool mount_is_network(MountParameters *p) {
- assert(p);
-
- if (mount_test_option(p->options, "_netdev"))
- return true;
-
- if (p->fstype && fstype_is_network(p->fstype))
- return true;
-
- return false;
-}
-
-static bool mount_is_bind(MountParameters *p) {
- assert(p);
-
- if (mount_test_option(p->options, "bind"))
- return true;
-
- if (p->fstype && streq(p->fstype, "bind"))
- return true;
-
- return false;
-}
-
-static bool needs_quota(MountParameters *p) {
- assert(p);
-
- if (mount_is_network(p))
- return false;
-
- if (mount_is_bind(p))
- return false;
-
- return mount_test_option(p->options, "usrquota") ||
- mount_test_option(p->options, "grpquota") ||
- mount_test_option(p->options, "quota") ||
- mount_test_option(p->options, "usrjquota") ||
- mount_test_option(p->options, "grpjquota");
-}
-
-static int mount_add_device_links(Mount *m) {
- MountParameters *p;
- int r;
-
- assert(m);
-
- p = get_mount_parameters_fragment(m);
- if (!p)
- return 0;
-
- if (!p->what)
- return 0;
-
- if (mount_is_bind(p))
- return 0;
-
- if (!is_device_path(p->what))
- return 0;
-
- if (path_equal(m->where, "/"))
- return 0;
-
- r = unit_add_node_link(UNIT(m), p->what, false);
- if (r < 0)
- return r;
-
- if (p->passno > 0 &&
- UNIT(m)->manager->running_as == SYSTEMD_SYSTEM) {
- char *name;
- Unit *fsck;
- /* Let's add in the fsck service */
-
- /* aka SPECIAL_FSCK_SERVICE */
- name = unit_name_from_path_instance("systemd-fsck", p->what, ".service");
- if (!name)
- return -ENOMEM;
-
- r = manager_load_unit_prepare(UNIT(m)->manager, name, NULL, NULL, &fsck);
- if (r < 0) {
- log_warning("Failed to prepare unit %s: %s", name, strerror(-r));
- free(name);
- return r;
- }
- free(name);
-
- SERVICE(fsck)->fsck_passno = p->passno;
-
- r = unit_add_two_dependencies(UNIT(m), UNIT_AFTER, UNIT_REQUIRES, fsck, true);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-static int mount_add_quota_links(Mount *m) {
- int r;
- MountParameters *p;
-
- assert(m);
-
- if (UNIT(m)->manager->running_as != SYSTEMD_SYSTEM)
- return 0;
-
- p = get_mount_parameters_fragment(m);
- if (!p)
- return 0;
-
- if (!needs_quota(p))
- return 0;
-
- r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTACHECK_SERVICE, NULL, true);
- if (r < 0)
- return r;
-
- r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTAON_SERVICE, NULL, true);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-static int mount_add_default_dependencies(Mount *m) {
- int r;
- MountParameters *p;
- const char *after;
-
- assert(m);
-
- if (UNIT(m)->manager->running_as != SYSTEMD_SYSTEM)
- return 0;
-
- p = get_mount_parameters_fragment(m);
- if (!p)
- return 0;
-
- if (path_equal(m->where, "/"))
- return 0;
-
- if (mount_is_network(p))
- after = SPECIAL_REMOTE_FS_PRE_TARGET;
- else
- after = SPECIAL_LOCAL_FS_PRE_TARGET;
-
- r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, after, NULL, true);
- if (r < 0)
- return r;
-
- 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_fix_timeouts(Mount *m) {
- MountParameters *p;
- const char *timeout = NULL;
- Unit *other;
- Iterator i;
- usec_t u;
- char *t;
- int r;
-
- assert(m);
-
- p = get_mount_parameters_fragment(m);
- if (!p)
- return 0;
-
- /* Allow configuration how long we wait for a device that
- * backs a mount point to show up. This is useful to support
- * endless device timeouts for devices that show up only after
- * user input, like crypto devices. */
-
- if ((timeout = mount_test_option(p->options, "comment=systemd.device-timeout")))
- timeout += 31;
- else if ((timeout = mount_test_option(p->options, "x-systemd.device-timeout")))
- timeout += 25;
- else
- return 0;
-
- t = strndup(timeout, strcspn(timeout, ",;" WHITESPACE));
- if (!t)
- return -ENOMEM;
-
- r = parse_usec(t, &u);
- free(t);
-
- if (r < 0) {
- log_warning("Failed to parse timeout for %s, ignoring: %s", m->where, timeout);
- return r;
- }
-
- SET_FOREACH(other, UNIT(m)->dependencies[UNIT_AFTER], i) {
- if (other->type != UNIT_DEVICE)
- continue;
-
- other->job_timeout = u;
- }
-
- return 0;
-}
-
-static int mount_verify(Mount *m) {
- bool b;
- char *e;
- assert(m);
-
- if (UNIT(m)->load_state != UNIT_LOADED)
- return 0;
-
- if (!m->from_fragment && !m->from_proc_self_mountinfo)
- return -ENOENT;
-
- if (!(e = unit_name_from_path(m->where, ".mount")))
- return -ENOMEM;
-
- b = unit_has_name(UNIT(m), e);
- free(e);
-
- if (!b) {
- log_error("%s's Where setting doesn't match unit name. Refusing.", UNIT(m)->id);
- return -EINVAL;
- }
-
- if (mount_point_is_api(m->where) || mount_point_ignore(m->where)) {
- log_error("Cannot create mount unit for API file system %s. Refusing.", m->where);
- return -EINVAL;
- }
-
- if (UNIT(m)->fragment_path && !m->parameters_fragment.what) {
- log_error("%s's What setting is missing. Refusing.", UNIT(m)->id);
- return -EBADMSG;
- }
-
- if (m->exec_context.pam_name && m->kill_context.kill_mode != KILL_CONTROL_GROUP) {
- log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(m)->id);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int mount_add_extras(Mount *m) {
- Unit *u = UNIT(m);
- int r;
-
- if (UNIT(m)->fragment_path)
- m->from_fragment = true;
-
- if (!m->where) {
- m->where = unit_name_to_path(u->id);
- if (!m->where)
- return -ENOMEM;
- }
-
- path_kill_slashes(m->where);
-
- r = unit_add_exec_dependencies(u, &m->exec_context);
- if (r < 0)
- return r;
-
- if (!UNIT(m)->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_socket_links(m);
- if (r < 0)
- return r;
-
- r = mount_add_swap_links(m);
- if (r < 0)
- return r;
-
- r = mount_add_path_links(m);
- if (r < 0)
- return r;
-
- r = mount_add_requires_mounts_links(m);
- if (r < 0)
- return r;
-
- r = mount_add_automount_links(m);
- if (r < 0)
- return r;
-
- r = mount_add_quota_links(m);
- if (r < 0)
- return r;
-
- if (UNIT(m)->default_dependencies) {
- r = mount_add_default_dependencies(m);
- if (r < 0)
- return r;
- }
-
- r = unit_add_default_cgroups(u);
- if (r < 0)
- return r;
-
- r = mount_fix_timeouts(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;
-
- r = unit_exec_context_defaults(u, &m->exec_context);
- if (r < 0)
- return r;
- }
-
- return mount_verify(m);
-}
-
-static int mount_notify_automount(Mount *m, int status) {
- Unit *p;
- int r;
- Iterator i;
-
- assert(m);
-
- SET_FOREACH(p, UNIT(m)->dependencies[UNIT_TRIGGERED_BY], i)
- if (p->type == UNIT_AUTOMOUNT) {
- r = automount_send_ready(AUTOMOUNT(p), status);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-static void mount_set_state(Mount *m, MountState state) {
- MountState old_state;
- assert(m);
-
- old_state = m->state;
- m->state = state;
-
- if (state != MOUNT_MOUNTING &&
- state != MOUNT_MOUNTING_DONE &&
- state != MOUNT_REMOUNTING &&
- state != MOUNT_UNMOUNTING &&
- state != MOUNT_MOUNTING_SIGTERM &&
- state != MOUNT_MOUNTING_SIGKILL &&
- state != MOUNT_UNMOUNTING_SIGTERM &&
- state != MOUNT_UNMOUNTING_SIGKILL &&
- state != MOUNT_REMOUNTING_SIGTERM &&
- state != MOUNT_REMOUNTING_SIGKILL) {
- unit_unwatch_timer(UNIT(m), &m->timer_watch);
- mount_unwatch_control_pid(m);
- m->control_command = NULL;
- m->control_command_id = _MOUNT_EXEC_COMMAND_INVALID;
- }
-
- if (state == MOUNT_MOUNTED ||
- state == MOUNT_REMOUNTING)
- mount_notify_automount(m, 0);
- else if (state == MOUNT_DEAD ||
- state == MOUNT_UNMOUNTING ||
- state == MOUNT_MOUNTING_SIGTERM ||
- state == MOUNT_MOUNTING_SIGKILL ||
- state == MOUNT_REMOUNTING_SIGTERM ||
- state == MOUNT_REMOUNTING_SIGKILL ||
- state == MOUNT_UNMOUNTING_SIGTERM ||
- state == MOUNT_UNMOUNTING_SIGKILL ||
- state == MOUNT_FAILED) {
- if (state != old_state)
- mount_notify_automount(m, -ENODEV);
- }
-
- if (state != old_state)
- log_debug("%s changed %s -> %s",
- UNIT(m)->id,
- mount_state_to_string(old_state),
- mount_state_to_string(state));
-
- unit_notify(UNIT(m), state_translation_table[old_state], state_translation_table[state], m->reload_result == MOUNT_SUCCESS);
- m->reload_result = MOUNT_SUCCESS;
-}
-
-static int mount_coldplug(Unit *u) {
- 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) {
-
- if (new_state == MOUNT_MOUNTING ||
- new_state == MOUNT_MOUNTING_DONE ||
- new_state == MOUNT_REMOUNTING ||
- new_state == MOUNT_UNMOUNTING ||
- new_state == MOUNT_MOUNTING_SIGTERM ||
- new_state == MOUNT_MOUNTING_SIGKILL ||
- new_state == MOUNT_UNMOUNTING_SIGTERM ||
- new_state == MOUNT_UNMOUNTING_SIGKILL ||
- new_state == MOUNT_REMOUNTING_SIGTERM ||
- new_state == MOUNT_REMOUNTING_SIGKILL) {
-
- if (m->control_pid <= 0)
- return -EBADMSG;
-
- if ((r = unit_watch_pid(UNIT(m), m->control_pid)) < 0)
- return r;
-
- if ((r = unit_watch_timer(UNIT(m), m->timeout_usec, &m->timer_watch)) < 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, strna(p->what),
- prefix, strna(p->fstype),
- prefix, strna(p->options),
- 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: %lu\n",
- prefix, (unsigned long) 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;
-
- assert(m);
- assert(c);
- assert(_pid);
-
- if ((r = unit_watch_timer(UNIT(m), m->timeout_usec, &m->timer_watch)) < 0)
- goto fail;
-
- if ((r = exec_spawn(c,
- NULL,
- &m->exec_context,
- NULL, 0,
- UNIT(m)->manager->environment,
- true,
- true,
- true,
- UNIT(m)->manager->confirm_spawn,
- UNIT(m)->cgroup_bondings,
- UNIT(m)->cgroup_attributes,
- NULL,
- UNIT(m)->id,
- NULL,
- &pid)) < 0)
- goto fail;
-
- if ((r = unit_watch_pid(UNIT(m), pid)) < 0)
- /* FIXME: we need to do something here */
- goto fail;
-
- *_pid = pid;
-
- return 0;
-
-fail:
- unit_unwatch_timer(UNIT(m), &m->timer_watch);
-
- return r;
-}
-
-static void mount_enter_dead(Mount *m, MountResult f) {
- assert(m);
-
- if (f != MOUNT_SUCCESS)
- m->result = f;
-
- 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;
- Set *pid_set = NULL;
- bool wait_for_exit = false;
-
- assert(m);
-
- if (f != MOUNT_SUCCESS)
- m->result = f;
-
- if (m->kill_context.kill_mode != KILL_NONE) {
- int sig = (state == MOUNT_MOUNTING_SIGTERM ||
- state == MOUNT_UNMOUNTING_SIGTERM ||
- state == MOUNT_REMOUNTING_SIGTERM) ? m->kill_context.kill_signal : SIGKILL;
-
- if (m->control_pid > 0) {
- if (kill_and_sigcont(m->control_pid, sig) < 0 && errno != ESRCH)
-
- log_warning("Failed to kill control process %li: %m", (long) m->control_pid);
- else
- wait_for_exit = true;
- }
-
- if (m->kill_context.kill_mode == KILL_CONTROL_GROUP) {
-
- if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) {
- r = -ENOMEM;
- goto fail;
- }
-
- /* Exclude the control pid from being killed via the cgroup */
- if (m->control_pid > 0)
- if ((r = set_put(pid_set, LONG_TO_PTR(m->control_pid))) < 0)
- goto fail;
-
- r = cgroup_bonding_kill_list(UNIT(m)->cgroup_bondings, sig, true, false, pid_set, NULL);
- if (r < 0) {
- if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
- log_warning("Failed to kill control group: %s", strerror(-r));
- } else if (r > 0)
- wait_for_exit = true;
-
- set_free(pid_set);
- pid_set = NULL;
- }
- }
-
- if (wait_for_exit) {
- if ((r = unit_watch_timer(UNIT(m), m->timeout_usec, &m->timer_watch)) < 0)
- goto fail;
-
- mount_set_state(m, state);
- } else if (state == MOUNT_REMOUNTING_SIGTERM || state == MOUNT_REMOUNTING_SIGKILL)
- mount_enter_mounted(m, MOUNT_SUCCESS);
- else
- mount_enter_dead(m, MOUNT_SUCCESS);
-
- return;
-
-fail:
- log_warning("%s failed to kill processes: %s", UNIT(m)->id, strerror(-r));
-
- if (state == MOUNT_REMOUNTING_SIGTERM || state == MOUNT_REMOUNTING_SIGKILL)
- mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
- else
- mount_enter_dead(m, MOUNT_FAILURE_RESOURCES);
-
- if (pid_set)
- set_free(pid_set);
-}
-
-static void mount_enter_unmounting(Mount *m) {
- int r;
-
- assert(m);
-
- m->control_command_id = MOUNT_EXEC_UNMOUNT;
- m->control_command = m->exec_command + MOUNT_EXEC_UNMOUNT;
-
- if ((r = exec_command_set(
- m->control_command,
- "/bin/umount",
- m->where,
- NULL)) < 0)
- goto fail;
-
- mount_unwatch_control_pid(m);
-
- if ((r = mount_spawn(m, m->control_command, &m->control_pid)) < 0)
- goto fail;
-
- mount_set_state(m, MOUNT_UNMOUNTING);
-
- return;
-
-fail:
- log_warning("%s failed to run 'umount' task: %s", UNIT(m)->id, strerror(-r));
- mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
-}
-
-static void mount_enter_mounting(Mount *m) {
- int r;
- MountParameters *p;
-
- assert(m);
-
- m->control_command_id = MOUNT_EXEC_MOUNT;
- m->control_command = m->exec_command + MOUNT_EXEC_MOUNT;
-
- mkdir_p_label(m->where, m->directory_mode);
-
- if (dir_is_empty(m->where) <= 0)
- log_notice("%s: Directory %s to mount over is not empty, mounting anyway. (To see the over-mounted files, please manually mount the underlying file system to a secondary location.)", m->meta.id, m->where);
-
- /* Create the source directory for bind-mounts if needed */
- p = get_mount_parameters_fragment(m);
- if (p && mount_is_bind(p))
- mkdir_p_label(p->what, m->directory_mode);
-
- if (m->from_fragment)
- r = exec_command_set(
- m->control_command,
- "/bin/mount",
- m->parameters_fragment.what,
- m->where,
- "-t", m->parameters_fragment.fstype ? m->parameters_fragment.fstype : "auto",
- m->parameters_fragment.options ? "-o" : NULL, m->parameters_fragment.options,
- 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_warning("%s failed to run 'mount' task: %s", UNIT(m)->id, strerror(-r));
- mount_enter_dead(m, MOUNT_FAILURE_RESOURCES);
-}
-
-static void mount_enter_mounting_done(Mount *m) {
- assert(m);
-
- mount_set_state(m, MOUNT_MOUNTING_DONE);
-}
-
-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) {
- char *buf = NULL;
- const char *o;
-
- if (m->parameters_fragment.options) {
- if (!(buf = strappend("remount,", m->parameters_fragment.options))) {
- r = -ENOMEM;
- goto fail;
- }
-
- o = buf;
- } else
- o = "remount";
-
- r = exec_command_set(
- m->control_command,
- "/bin/mount",
- m->parameters_fragment.what,
- m->where,
- "-t", m->parameters_fragment.fstype ? m->parameters_fragment.fstype : "auto",
- "-o", o,
- NULL);
-
- free(buf);
- } else
- r = -ENOENT;
-
- if (r < 0)
- goto fail;
-
- mount_unwatch_control_pid(m);
-
- if ((r = mount_spawn(m, m->control_command, &m->control_pid)) < 0)
- goto fail;
-
- mount_set_state(m, MOUNT_REMOUNTING);
-
- return;
-
-fail:
- log_warning("%s failed to run 'remount' task: %s", UNIT(m)->id, strerror(-r));
- m->reload_result = MOUNT_FAILURE_RESOURCES;
- mount_enter_mounted(m, MOUNT_SUCCESS);
-}
-
-static int mount_start(Unit *u) {
- Mount *m = MOUNT(u);
-
- assert(m);
-
- /* We cannot fulfill this request right now, try again later
- * please! */
- if (m->state == MOUNT_UNMOUNTING ||
- m->state == MOUNT_UNMOUNTING_SIGTERM ||
- m->state == MOUNT_UNMOUNTING_SIGKILL ||
- m->state == MOUNT_MOUNTING_SIGTERM ||
- m->state == MOUNT_MOUNTING_SIGKILL)
- return -EAGAIN;
-
- /* Already on it! */
- if (m->state == MOUNT_MOUNTING)
- return 0;
-
- assert(m->state == MOUNT_DEAD || m->state == MOUNT_FAILED);
-
- m->result = MOUNT_SUCCESS;
- m->reload_result = MOUNT_SUCCESS;
-
- mount_enter_mounting(m);
- return 0;
-}
-
-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 0;
-}
-
-static int mount_reload(Unit *u) {
- Mount *m = MOUNT(u);
-
- assert(m);
-
- if (m->state == MOUNT_MOUNTING_DONE)
- return -EAGAIN;
-
- assert(m->state == MOUNT_MOUNTED);
-
- mount_enter_remounting(m);
- return 0;
-}
-
-static int mount_serialize(Unit *u, FILE *f, FDSet *fds) {
- Mount *m = MOUNT(u);
-
- assert(m);
- assert(f);
- assert(fds);
-
- unit_serialize_item(u, f, "state", mount_state_to_string(m->state));
- unit_serialize_item(u, f, "result", mount_result_to_string(m->result));
- unit_serialize_item(u, f, "reload-result", mount_result_to_string(m->reload_result));
-
- if (m->control_pid > 0)
- unit_serialize_item_format(u, f, "control-pid", "%lu", (unsigned long) 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_debug("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_debug("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_debug("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_debug("Failed to parse control-pid value %s", value);
- else
- m->control_pid = pid;
- } else if (streq(key, "control-command")) {
- MountExecCommand id;
-
- if ((id = mount_exec_command_from_string(value)) < 0)
- log_debug("Failed to parse exec-command value %s", value);
- else {
- m->control_command_id = id;
- m->control_command = m->exec_command + id;
- }
-
- } else
- log_debug("Unknown serialization key '%s'", key);
-
- return 0;
-}
-
-static UnitActiveState mount_active_state(Unit *u) {
- assert(u);
-
- return state_translation_table[MOUNT(u)->state];
-}
-
-static const char *mount_sub_state_to_string(Unit *u) {
- assert(u);
-
- return mount_state_to_string(MOUNT(u)->state);
-}
-
-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_full(f == MOUNT_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
- "%s mount process exited, code=%s status=%i", u->id, sigchld_code_to_string(code), status);
-
- /* Note that mount(8) returning and the kernel sending us a
- * mount table change event might happen out-of-order. If an
- * operation succeed we assume the kernel will follow soon too
- * and already change into the resulting state. If it fails
- * we check if the kernel still knows about the mount. and
- * change state accordingly. */
-
- switch (m->state) {
-
- case MOUNT_MOUNTING:
- case MOUNT_MOUNTING_DONE:
- case MOUNT_MOUNTING_SIGKILL:
- case MOUNT_MOUNTING_SIGTERM:
-
- if (f == MOUNT_SUCCESS)
- mount_enter_mounted(m, f);
- else if (m->from_proc_self_mountinfo)
- mount_enter_mounted(m, f);
- else
- mount_enter_dead(m, f);
- break;
-
- case MOUNT_REMOUNTING:
- case MOUNT_REMOUNTING_SIGKILL:
- case MOUNT_REMOUNTING_SIGTERM:
-
- m->reload_result = f;
- if (m->from_proc_self_mountinfo)
- mount_enter_mounted(m, MOUNT_SUCCESS);
- else
- mount_enter_dead(m, MOUNT_SUCCESS);
-
- break;
-
- case MOUNT_UNMOUNTING:
- case MOUNT_UNMOUNTING_SIGKILL:
- case MOUNT_UNMOUNTING_SIGTERM:
-
- if (f == MOUNT_SUCCESS)
- 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 void mount_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
- Mount *m = MOUNT(u);
-
- assert(m);
- assert(elapsed == 1);
- assert(w == &m->timer_watch);
-
- switch (m->state) {
-
- case MOUNT_MOUNTING:
- case MOUNT_MOUNTING_DONE:
- log_warning("%s mounting timed out. Stopping.", u->id);
- mount_enter_signal(m, MOUNT_MOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
- break;
-
- case MOUNT_REMOUNTING:
- log_warning("%s remounting timed out. Stopping.", u->id);
- m->reload_result = MOUNT_FAILURE_TIMEOUT;
- mount_enter_mounted(m, MOUNT_SUCCESS);
- break;
-
- case MOUNT_UNMOUNTING:
- log_warning("%s unmounting timed out. Stopping.", u->id);
- mount_enter_signal(m, MOUNT_UNMOUNTING_SIGTERM, MOUNT_FAILURE_TIMEOUT);
- break;
-
- case MOUNT_MOUNTING_SIGTERM:
- if (m->kill_context.send_sigkill) {
- log_warning("%s mounting timed out. Killing.", u->id);
- mount_enter_signal(m, MOUNT_MOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
- } else {
- log_warning("%s mounting timed out. Skipping SIGKILL. Ignoring.", u->id);
-
- if (m->from_proc_self_mountinfo)
- mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
- else
- mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
- }
- break;
-
- case MOUNT_REMOUNTING_SIGTERM:
- if (m->kill_context.send_sigkill) {
- log_warning("%s remounting timed out. Killing.", u->id);
- mount_enter_signal(m, MOUNT_REMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
- } else {
- log_warning("%s remounting timed out. Skipping SIGKILL. Ignoring.", u->id);
-
- if (m->from_proc_self_mountinfo)
- mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
- else
- mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
- }
- break;
-
- case MOUNT_UNMOUNTING_SIGTERM:
- if (m->kill_context.send_sigkill) {
- log_warning("%s unmounting timed out. Killing.", u->id);
- mount_enter_signal(m, MOUNT_UNMOUNTING_SIGKILL, MOUNT_FAILURE_TIMEOUT);
- } else {
- log_warning("%s unmounting timed out. Skipping SIGKILL. Ignoring.", u->id);
-
- if (m->from_proc_self_mountinfo)
- mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
- else
- mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
- }
- break;
-
- case MOUNT_MOUNTING_SIGKILL:
- case MOUNT_REMOUNTING_SIGKILL:
- case MOUNT_UNMOUNTING_SIGKILL:
- log_warning("%s mount process still around after SIGKILL. Ignoring.", u->id);
-
- if (m->from_proc_self_mountinfo)
- mount_enter_mounted(m, MOUNT_FAILURE_TIMEOUT);
- else
- mount_enter_dead(m, MOUNT_FAILURE_TIMEOUT);
- break;
-
- default:
- assert_not_reached("Timeout at wrong time.");
- }
-}
-
-static int mount_add_one(
- Manager *m,
- const char *what,
- const char *where,
- const char *options,
- const char *fstype,
- int passno,
- bool set_flags) {
- int r;
- Unit *u;
- bool delete;
- char *e, *w = NULL, *o = NULL, *f = NULL;
- MountParameters *p;
- bool load_extras = false;
-
- assert(m);
- assert(what);
- assert(where);
- assert(options);
- assert(fstype);
-
- /* Ignore API mount points. They should never be referenced in
- * dependencies ever. */
- if (mount_point_is_api(where) || mount_point_ignore(where))
- return 0;
-
- if (streq(fstype, "autofs"))
- return 0;
-
- /* probably some kind of swap, ignore */
- if (!is_path(where))
- return 0;
-
- e = unit_name_from_path(where, ".mount");
- if (!e)
- return -ENOMEM;
-
- u = manager_get_unit(m, e);
- if (!u) {
- delete = true;
-
- u = unit_new(m, sizeof(Mount));
- if (!u) {
- free(e);
- return -ENOMEM;
- }
-
- r = unit_add_name(u, e);
- free(e);
-
- if (r < 0)
- goto fail;
-
- MOUNT(u)->where = strdup(where);
- if (!MOUNT(u)->where) {
- r = -ENOMEM;
- goto fail;
- }
-
- unit_add_to_load_queue(u);
- } else {
- delete = false;
- free(e);
-
- if (!MOUNT(u)->where) {
- MOUNT(u)->where = strdup(where);
- if (!MOUNT(u)->where) {
- r = -ENOMEM;
- goto fail;
- }
- }
-
- if (u->load_state == UNIT_ERROR) {
- 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;
- }
- }
-
- if (!(w = strdup(what)) ||
- !(o = strdup(options)) ||
- !(f = strdup(fstype))) {
- r = -ENOMEM;
- goto fail;
- }
-
- p = &MOUNT(u)->parameters_proc_self_mountinfo;
- if (set_flags) {
- MOUNT(u)->is_mounted = true;
- MOUNT(u)->just_mounted = !MOUNT(u)->from_proc_self_mountinfo;
- MOUNT(u)->just_changed = !streq_ptr(p->options, o);
- }
-
- MOUNT(u)->from_proc_self_mountinfo = true;
-
- free(p->what);
- p->what = w;
-
- free(p->options);
- p->options = o;
-
- free(p->fstype);
- p->fstype = f;
-
- p->passno = passno;
-
- if (load_extras) {
- r = mount_add_extras(MOUNT(u));
- if (r < 0)
- goto fail;
- }
-
- unit_add_to_dbus_queue(u);
-
- return 0;
-
-fail:
- free(w);
- free(o);
- free(f);
-
- if (delete && u)
- unit_free(u);
-
- return r;
-}
-
-static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
- int r = 0;
- unsigned i;
- char *device, *path, *options, *options2, *fstype, *d, *p, *o;
-
- assert(m);
-
- rewind(m->proc_self_mountinfo);
-
- for (i = 1;; i++) {
- int k;
-
- device = path = options = options2 = fstype = d = p = o = NULL;
-
- if ((k = fscanf(m->proc_self_mountinfo,
- "%*s " /* (1) mount id */
- "%*s " /* (2) parent id */
- "%*s " /* (3) major:minor */
- "%*s " /* (4) root */
- "%ms " /* (5) mount point */
- "%ms" /* (6) mount options */
- "%*[^-]" /* (7) optional fields */
- "- " /* (8) separator */
- "%ms " /* (9) file system type */
- "%ms" /* (10) mount source */
- "%ms" /* (11) mount options 2 */
- "%*[^\n]", /* some rubbish at the end */
- &path,
- &options,
- &fstype,
- &device,
- &options2)) != 5) {
-
- if (k == EOF)
- break;
-
- log_warning("Failed to parse /proc/self/mountinfo:%u.", i);
- goto clean_up;
- }
-
- o = strjoin(options, ",", options2, NULL);
- if (!o) {
- r = -ENOMEM;
- goto finish;
- }
-
- if (!(d = cunescape(device)) ||
- !(p = cunescape(path))) {
- r = -ENOMEM;
- goto finish;
- }
-
- if ((k = mount_add_one(m, d, p, o, fstype, 0, set_flags)) < 0)
- r = k;
-
-clean_up:
- free(device);
- free(path);
- free(options);
- free(options2);
- free(fstype);
- free(d);
- free(p);
- free(o);
- }
-
-finish:
- free(device);
- free(path);
- free(options);
- free(options2);
- free(fstype);
- free(d);
- free(p);
- free(o);
-
- return r;
-}
-
-static void mount_shutdown(Manager *m) {
- assert(m);
-
- if (m->proc_self_mountinfo) {
- fclose(m->proc_self_mountinfo);
- m->proc_self_mountinfo = NULL;
- }
-}
-
-static int mount_enumerate(Manager *m) {
- int r;
- struct epoll_event ev;
- assert(m);
-
- if (!m->proc_self_mountinfo) {
- if (!(m->proc_self_mountinfo = fopen("/proc/self/mountinfo", "re")))
- return -errno;
-
- m->mount_watch.type = WATCH_MOUNT;
- m->mount_watch.fd = fileno(m->proc_self_mountinfo);
-
- zero(ev);
- ev.events = EPOLLPRI;
- ev.data.ptr = &m->mount_watch;
-
- if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->mount_watch.fd, &ev) < 0)
- return -errno;
- }
-
- if ((r = mount_load_proc_self_mountinfo(m, false)) < 0)
- goto fail;
-
- return 0;
-
-fail:
- mount_shutdown(m);
- return r;
-}
-
-void mount_fd_event(Manager *m, int events) {
- Unit *u;
- int r;
-
- assert(m);
- assert(events & EPOLLPRI);
-
- /* The manager calls this for every fd event happening on the
- * /proc/self/mountinfo file, which informs us about mounting
- * table changes */
-
- if ((r = mount_load_proc_self_mountinfo(m, true)) < 0) {
- log_error("Failed to reread /proc/self/mountinfo: %s", strerror(-r));
-
- /* 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;
- }
-
- 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) {
- /* This has just been unmounted. */
-
- mount->from_proc_self_mountinfo = false;
-
- switch (mount->state) {
-
- case MOUNT_MOUNTED:
- mount_enter_dead(mount, MOUNT_SUCCESS);
- break;
-
- default:
- mount_set_state(mount, mount->state);
- break;
-
- }
-
- } else if (mount->just_mounted || mount->just_changed) {
-
- /* New or changed mount entry */
-
- switch (mount->state) {
-
- case MOUNT_DEAD:
- case MOUNT_FAILED:
- mount_enter_mounted(mount, MOUNT_SUCCESS);
- break;
-
- case MOUNT_MOUNTING:
- mount_enter_mounting_done(mount);
- break;
-
- default:
- /* Nothing really changed, but let's
- * issue an notification call
- * nonetheless, in case somebody is
- * waiting for this. (e.g. file system
- * ro/rw remounts.) */
- mount_set_state(mount, mount->state);
- break;
- }
- }
-
- /* Reset the flags for later calls */
- mount->is_mounted = mount->just_mounted = mount->just_changed = false;
- }
-}
-
-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, DBusError *error) {
- Mount *m = MOUNT(u);
- int r = 0;
- Set *pid_set = NULL;
-
- assert(m);
-
- if (who == KILL_MAIN) {
- dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "Mount units have no main processes");
- return -ESRCH;
- }
-
- if (m->control_pid <= 0 && who == KILL_CONTROL) {
- dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
- return -ESRCH;
- }
-
- if (who == KILL_CONTROL || who == KILL_ALL)
- if (m->control_pid > 0)
- if (kill(m->control_pid, signo) < 0)
- r = -errno;
-
- if (who == KILL_ALL) {
- int q;
-
- pid_set = set_new(trivial_hash_func, trivial_compare_func);
- if (!pid_set)
- return -ENOMEM;
-
- /* Exclude the control pid from being killed via the cgroup */
- if (m->control_pid > 0) {
- q = set_put(pid_set, LONG_TO_PTR(m->control_pid));
- if (q < 0) {
- r = q;
- goto finish;
- }
- }
-
- q = cgroup_bonding_kill_list(UNIT(m)->cgroup_bondings, signo, false, false, pid_set, NULL);
- if (q < 0 && q != -EAGAIN && q != -ESRCH && q != -ENOENT)
- r = q;
- }
-
-finish:
- if (pid_set)
- set_free(pid_set);
-
- return r;
-}
-
-static const char* const mount_state_table[_MOUNT_STATE_MAX] = {
- [MOUNT_DEAD] = "dead",
- [MOUNT_MOUNTING] = "mounting",
- [MOUNT_MOUNTING_DONE] = "mounting-done",
- [MOUNT_MOUNTED] = "mounted",
- [MOUNT_REMOUNTING] = "remounting",
- [MOUNT_UNMOUNTING] = "unmounting",
- [MOUNT_MOUNTING_SIGTERM] = "mounting-sigterm",
- [MOUNT_MOUNTING_SIGKILL] = "mounting-sigkill",
- [MOUNT_REMOUNTING_SIGTERM] = "remounting-sigterm",
- [MOUNT_REMOUNTING_SIGKILL] = "remounting-sigkill",
- [MOUNT_UNMOUNTING_SIGTERM] = "unmounting-sigterm",
- [MOUNT_UNMOUNTING_SIGKILL] = "unmounting-sigkill",
- [MOUNT_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(mount_state, MountState);
-
-static const char* const mount_exec_command_table[_MOUNT_EXEC_COMMAND_MAX] = {
- [MOUNT_EXEC_MOUNT] = "ExecMount",
- [MOUNT_EXEC_UNMOUNT] = "ExecUnmount",
- [MOUNT_EXEC_REMOUNT] = "ExecRemount",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(mount_exec_command, MountExecCommand);
-
-static const char* const mount_result_table[_MOUNT_RESULT_MAX] = {
- [MOUNT_SUCCESS] = "success",
- [MOUNT_FAILURE_RESOURCES] = "resources",
- [MOUNT_FAILURE_TIMEOUT] = "timeout",
- [MOUNT_FAILURE_EXIT_CODE] = "exit-code",
- [MOUNT_FAILURE_SIGNAL] = "signal",
- [MOUNT_FAILURE_CORE_DUMP] = "core-dump"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(mount_result, MountResult);
-
-const UnitVTable mount_vtable = {
- .object_size = sizeof(Mount),
- .exec_context_offset = offsetof(Mount, exec_context),
-
- .sections =
- "Unit\0"
- "Mount\0"
- "Install\0",
-
- .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,
- .timer_event = mount_timer_event,
-
- .reset_failed = mount_reset_failed,
-
- .bus_interface = "org.freedesktop.systemd1.Mount",
- .bus_message_handler = bus_mount_message_handler,
- .bus_invalidating_properties = bus_mount_invalidating_properties,
-
- .enumerate = mount_enumerate,
- .shutdown = mount_shutdown,
-
- .status_message_formats = {
- .starting_stopping = {
- [0] = "Mounting %s...",
- [1] = "Unmounting %s...",
- },
- .finished_start_job = {
- [JOB_DONE] = "Mounted %s.",
- [JOB_FAILED] = "Failed to mount %s.",
- [JOB_DEPENDENCY] = "Dependency failed for %s.",
- [JOB_TIMEOUT] = "Timed out mounting %s.",
- },
- .finished_stop_job = {
- [JOB_DONE] = "Unmounted %s.",
- [JOB_FAILED] = "Failed unmounting %s.",
- [JOB_TIMEOUT] = "Timed out unmounting %s.",
- },
- },
-};
diff --git a/src/core/mount.h b/src/core/mount.h
deleted file mode 100644
index 67d6132a5d..0000000000
--- a/src/core/mount.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct Mount Mount;
-
-#include "unit.h"
-#include "kill.h"
-
-typedef enum MountState {
- MOUNT_DEAD,
- MOUNT_MOUNTING, /* /bin/mount is running, but the mount is not done yet. */
- MOUNT_MOUNTING_DONE, /* /bin/mount is running, and the mount is done. */
- MOUNT_MOUNTED,
- MOUNT_REMOUNTING,
- MOUNT_UNMOUNTING,
- MOUNT_MOUNTING_SIGTERM,
- MOUNT_MOUNTING_SIGKILL,
- MOUNT_REMOUNTING_SIGTERM,
- MOUNT_REMOUNTING_SIGKILL,
- MOUNT_UNMOUNTING_SIGTERM,
- MOUNT_UNMOUNTING_SIGKILL,
- MOUNT_FAILED,
- _MOUNT_STATE_MAX,
- _MOUNT_STATE_INVALID = -1
-} MountState;
-
-typedef enum MountExecCommand {
- MOUNT_EXEC_MOUNT,
- MOUNT_EXEC_UNMOUNT,
- MOUNT_EXEC_REMOUNT,
- _MOUNT_EXEC_COMMAND_MAX,
- _MOUNT_EXEC_COMMAND_INVALID = -1
-} MountExecCommand;
-
-typedef struct MountParameters {
- char *what;
- char *options;
- char *fstype;
- int passno;
-} MountParameters;
-
-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;
-
-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;
-
- 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;
-
- MountState state, deserialized_state;
-
- ExecCommand* control_command;
- MountExecCommand control_command_id;
- pid_t control_pid;
-
- Watch timer_watch;
-};
-
-extern const UnitVTable mount_vtable;
-
-void mount_fd_event(Manager *m, int events);
-
-const char* mount_state_to_string(MountState i);
-MountState mount_state_from_string(const char *s);
-
-const char* mount_exec_command_to_string(MountExecCommand i);
-MountExecCommand mount_exec_command_from_string(const char *s);
-
-const char* mount_result_to_string(MountResult i);
-MountResult mount_result_from_string(const char *s);
diff --git a/src/core/namespace.c b/src/core/namespace.c
deleted file mode 100644
index ba18ddc5b0..0000000000
--- a/src/core/namespace.c
+++ /dev/null
@@ -1,330 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <sys/mount.h>
-#include <string.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sched.h>
-#include <sys/syscall.h>
-#include <limits.h>
-#include <linux/fs.h>
-
-#include "strv.h"
-#include "util.h"
-#include "path-util.h"
-#include "namespace.h"
-#include "missing.h"
-
-typedef enum PathMode {
- /* This is ordered by priority! */
- INACCESSIBLE,
- READONLY,
- PRIVATE_TMP,
- PRIVATE_VAR_TMP,
- READWRITE
-} PathMode;
-
-typedef struct Path {
- const char *path;
- PathMode mode;
- bool done;
-} Path;
-
-static int append_paths(Path **p, char **strv, PathMode mode) {
- char **i;
-
- STRV_FOREACH(i, strv) {
-
- if (!path_is_absolute(*i))
- return -EINVAL;
-
- (*p)->path = *i;
- (*p)->mode = mode;
- (*p)++;
- }
-
- return 0;
-}
-
-static int path_compare(const void *a, const void *b) {
- const Path *p = a, *q = b;
-
- if (path_equal(p->path, q->path)) {
-
- /* 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 */
- if (path_startswith(p->path, q->path))
- return 1;
-
- if (path_startswith(q->path, p->path))
- return -1;
-
- return 0;
-}
-
-static void drop_duplicates(Path *p, unsigned *n, bool *need_inaccessible) {
- Path *f, *t, *previous;
-
- assert(p);
- assert(n);
- assert(need_inaccessible);
-
- for (f = p, t = p, previous = NULL; f < p+*n; f++) {
-
- /* The first one wins */
- if (previous && path_equal(f->path, previous->path))
- continue;
-
- t->path = f->path;
- t->mode = f->mode;
-
- if (t->mode == INACCESSIBLE)
- *need_inaccessible = true;
-
- previous = t;
-
- t++;
- }
-
- *n = t - p;
-}
-
-static int apply_mount(
- Path *p,
- const char *tmp_dir,
- const char *var_tmp_dir,
- const char *inaccessible_dir) {
-
- const char *what;
- int r;
-
- assert(p);
-
- switch (p->mode) {
-
- case INACCESSIBLE:
- what = inaccessible_dir;
- break;
-
- case READONLY:
- case READWRITE:
- what = p->path;
- break;
-
- case PRIVATE_TMP:
- what = tmp_dir;
- break;
-
- case PRIVATE_VAR_TMP:
- what = var_tmp_dir;
- break;
-
- default:
- assert_not_reached("Unknown mode");
- }
-
- assert(what);
-
- r = mount(what, p->path, NULL, MS_BIND|MS_REC, NULL);
- if (r >= 0)
- log_debug("Successfully mounted %s to %s", what, p->path);
-
- return r;
-}
-
-static int make_read_only(Path *p) {
- int r;
-
- assert(p);
-
- if (p->mode != INACCESSIBLE && p->mode != READONLY)
- return 0;
-
- r = mount(NULL, p->path, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY|MS_REC, NULL);
- if (r < 0)
- return -errno;
-
- return 0;
-}
-
-int setup_namespace(
- char **writable,
- char **readable,
- char **inaccessible,
- bool private_tmp,
- unsigned long flags) {
-
- char
- tmp_dir[] = "/tmp/systemd-private-XXXXXX",
- var_tmp_dir[] = "/var/tmp/systemd-private-XXXXXX",
- inaccessible_dir[] = "/tmp/systemd-inaccessible-XXXXXX";
-
- Path *paths, *p;
- unsigned n;
- bool need_inaccessible = false;
- bool remove_tmp = false, remove_var_tmp = false, remove_inaccessible = false;
- int r;
-
- if (!flags)
- flags = MS_SHARED;
-
- n =
- strv_length(writable) +
- strv_length(readable) +
- strv_length(inaccessible) +
- (private_tmp ? 2 : 0);
-
- p = paths = alloca(sizeof(Path) * n);
- if ((r = append_paths(&p, writable, READWRITE)) < 0 ||
- (r = append_paths(&p, readable, READONLY)) < 0 ||
- (r = append_paths(&p, inaccessible, INACCESSIBLE)) < 0)
- goto fail;
-
- if (private_tmp) {
- p->path = "/tmp";
- p->mode = PRIVATE_TMP;
- p++;
-
- p->path = "/var/tmp";
- p->mode = PRIVATE_VAR_TMP;
- p++;
- }
-
- assert(paths + n == p);
-
- qsort(paths, n, sizeof(Path), path_compare);
- drop_duplicates(paths, &n, &need_inaccessible);
-
- if (need_inaccessible) {
- mode_t u;
- char *d;
-
- u = umask(0777);
- d = mkdtemp(inaccessible_dir);
- umask(u);
-
- if (!d) {
- r = -errno;
- goto fail;
- }
-
- remove_inaccessible = true;
- }
-
- if (private_tmp) {
- mode_t u;
- char *d;
-
- u = umask(0000);
- d = mkdtemp(tmp_dir);
- umask(u);
-
- if (!d) {
- r = -errno;
- goto fail;
- }
-
- remove_tmp = true;
-
- u = umask(0000);
- d = mkdtemp(var_tmp_dir);
- umask(u);
-
- if (!d) {
- r = -errno;
- goto fail;
- }
-
- remove_var_tmp = true;
-
- if (chmod(tmp_dir, 0777 + S_ISVTX) < 0) {
- r = -errno;
- goto fail;
- }
-
- if (chmod(var_tmp_dir, 0777 + S_ISVTX) < 0) {
- r = -errno;
- goto fail;
- }
- }
-
- if (unshare(CLONE_NEWNS) < 0) {
- r = -errno;
- goto fail;
- }
-
- /* 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) {
- r = -errno;
- goto fail;
- }
-
- for (p = paths; p < paths + n; p++) {
- r = apply_mount(p, tmp_dir, var_tmp_dir, inaccessible_dir);
- if (r < 0)
- goto undo_mounts;
- }
-
- for (p = paths; p < paths + n; p++) {
- r = make_read_only(p);
- if (r < 0)
- goto undo_mounts;
- }
-
- /* Remount / as the desired mode */
- if (mount(NULL, "/", NULL, flags|MS_REC, NULL) < 0) {
- r = -errno;
- goto undo_mounts;
- }
-
- return 0;
-
-undo_mounts:
- for (p = paths; p < paths + n; p++)
- if (p->done)
- umount2(p->path, MNT_DETACH);
-
-fail:
- if (remove_inaccessible)
- rmdir(inaccessible_dir);
-
- if (remove_tmp)
- rmdir(tmp_dir);
-
- if (remove_var_tmp)
- rmdir(var_tmp_dir);
-
- return r;
-}
diff --git a/src/core/namespace.h b/src/core/namespace.h
deleted file mode 100644
index 5d72ed91fb..0000000000
--- a/src/core/namespace.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You 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 setup_namespace(
- char **writable,
- char **readable,
- char **inaccessible,
- bool private_tmp,
- unsigned long flags);
diff --git a/src/core/org.freedesktop.systemd1.conf b/src/core/org.freedesktop.systemd1.conf
deleted file mode 100644
index a07a8e1ce3..0000000000
--- a/src/core/org.freedesktop.systemd1.conf
+++ /dev/null
@@ -1,92 +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"/>
-
- <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="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 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 51bdafac45..0000000000
--- a/src/core/org.freedesktop.systemd1.policy.in.in
+++ /dev/null
@@ -1,41 +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.bus-access">
- <_description>Privileged system and service manager access</_description>
- <_message>Authentication is required to access the system and service manager.</_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">@bindir@/systemd-stdio-bridge</annotate>
- </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 3936971b41..0000000000
--- a/src/core/path.c
+++ /dev/null
@@ -1,773 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/inotify.h>
-#include <sys/epoll.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include "unit.h"
-#include "unit-name.h"
-#include "path.h"
-#include "mkdir.h"
-#include "dbus-path.h"
-#include "special.h"
-#include "bus-errors.h"
-#include "path-util.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
-};
-
-int path_spec_watch(PathSpec *s, Unit *u) {
-
- 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 *k, *slash;
- int r;
-
- assert(u);
- assert(s);
-
- path_spec_unwatch(s, u);
-
- if (!(k = strdup(s->path)))
- return -ENOMEM;
-
- if ((s->inotify_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC)) < 0) {
- r = -errno;
- goto fail;
- }
-
- if (unit_watch_fd(u, s->inotify_fd, EPOLLIN, &s->watch) < 0) {
- r = -errno;
- goto fail;
- }
-
- s->primary_wd = inotify_add_watch(s->inotify_fd, k, flags_table[s->type]);
- if (s->primary_wd >= 0)
- exists = true;
-
- do {
- int flags;
-
- /* This assumes the path was passed through path_kill_slashes()! */
- slash = strrchr(k, '/');
- if (!slash)
- break;
-
- /* Trim the path at the last slash. Keep the slash if it's the root dir. */
- slash[slash == k] = 0;
-
- flags = IN_MOVE_SELF;
- if (!exists)
- flags |= IN_DELETE_SELF | IN_ATTRIB | IN_CREATE | IN_MOVED_TO;
-
- if (inotify_add_watch(s->inotify_fd, k, flags) >= 0)
- exists = true;
- } while (slash != k);
-
- return 0;
-
-fail:
- free(k);
-
- path_spec_unwatch(s, u);
- return r;
-}
-
-void path_spec_unwatch(PathSpec *s, Unit *u) {
-
- if (s->inotify_fd < 0)
- return;
-
- unit_unwatch_fd(u, &s->watch);
-
- close_nointr_nofail(s->inotify_fd);
- s->inotify_fd = -1;
-}
-
-int path_spec_fd_event(PathSpec *s, uint32_t events) {
- uint8_t *buf = NULL;
- struct inotify_event *e;
- ssize_t k;
- int l;
- int r = 0;
-
- if (events != EPOLLIN) {
- log_error("Got Invalid poll event on inotify.");
- r = -EINVAL;
- goto out;
- }
-
- if (ioctl(s->inotify_fd, FIONREAD, &l) < 0) {
- log_error("FIONREAD failed: %m");
- r = -errno;
- goto out;
- }
-
- assert(l > 0);
-
- if (!(buf = malloc(l))) {
- log_error("Failed to allocate buffer: %m");
- r = -errno;
- goto out;
- }
-
- if ((k = read(s->inotify_fd, buf, l)) < 0) {
- log_error("Failed to read inotify event: %m");
- r = -errno;
- goto out;
- }
-
- e = (struct inotify_event*) buf;
-
- while (k > 0) {
- size_t step;
-
- if ((s->type == PATH_CHANGED || s->type == PATH_MODIFIED) &&
- s->primary_wd == e->wd)
- r = 1;
-
- step = sizeof(struct inotify_event) + e->len;
- assert(step <= (size_t) k);
-
- e = (struct inotify_event*) ((uint8_t*) e + step);
- k -= step;
- }
-out:
- free(buf);
- 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 bool path_spec_startswith(PathSpec *s, const char *what) {
- return path_startswith(s->path, what);
-}
-
-static void path_spec_mkdir(PathSpec *s, mode_t mode) {
- int r;
-
- if (s->type == PATH_EXISTS || s->type == PATH_EXISTS_GLOB)
- return;
-
- if ((r = mkdir_p_label(s->path, mode)) < 0)
- log_warning("mkdir(%s) failed: %s", s->path, strerror(-r));
-}
-
-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;
-}
-
-static void path_done(Unit *u) {
- Path *p = PATH(u);
- PathSpec *s;
-
- assert(p);
-
- unit_ref_unset(&p->unit);
-
- while ((s = p->specs)) {
- path_spec_unwatch(s, u);
- LIST_REMOVE(PathSpec, spec, p->specs, s);
- path_spec_done(s);
- free(s);
- }
-}
-
-int path_add_one_mount_link(Path *p, Mount *m) {
- PathSpec *s;
- int r;
-
- assert(p);
- assert(m);
-
- if (UNIT(p)->load_state != UNIT_LOADED ||
- UNIT(m)->load_state != UNIT_LOADED)
- return 0;
-
- LIST_FOREACH(spec, s, p->specs) {
-
- if (!path_spec_startswith(s, m->where))
- continue;
-
- if ((r = unit_add_two_dependencies(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true)) < 0)
- return r;
- }
-
- return 0;
-}
-
-static int path_add_mount_links(Path *p) {
- Unit *other;
- int r;
-
- assert(p);
-
- LIST_FOREACH(units_by_type, other, UNIT(p)->manager->units_by_type[UNIT_MOUNT])
- if ((r = path_add_one_mount_link(p, MOUNT(other))) < 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_error("%s lacks path setting. Refusing.", UNIT(p)->id);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int path_add_default_dependencies(Path *p) {
- int r;
-
- assert(p);
-
- if (UNIT(p)->manager->running_as == SYSTEMD_SYSTEM) {
- if ((r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE, SPECIAL_BASIC_TARGET, NULL, true)) < 0)
- return r;
-
- if ((r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true)) < 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);
-
- if ((r = unit_load_fragment_and_dropin(u)) < 0)
- return r;
-
- if (u->load_state == UNIT_LOADED) {
-
- if (!UNIT_DEREF(p->unit)) {
- Unit *x;
-
- r = unit_load_related_unit(u, ".service", &x);
- if (r < 0)
- return r;
-
- unit_ref_set(&p->unit, x);
- }
-
- r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(p->unit), true);
- if (r < 0)
- return r;
-
- if ((r = path_add_mount_links(p)) < 0)
- return r;
-
- if (UNIT(p)->default_dependencies)
- if ((r = path_add_default_dependencies(p)) < 0)
- return r;
- }
-
- return path_verify(p);
-}
-
-static void path_dump(Unit *u, FILE *f, const char *prefix) {
- Path *p = PATH(u);
- PathSpec *s;
-
- assert(p);
- assert(f);
-
- 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, UNIT_DEREF(p->unit)->id,
- 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, UNIT(p));
-}
-
-static int path_watch(Path *p) {
- int r;
- PathSpec *s;
-
- assert(p);
-
- LIST_FOREACH(spec, s, p->specs)
- if ((r = path_spec_watch(s, UNIT(p))) < 0)
- return r;
-
- return 0;
-}
-
-static void path_set_state(Path *p, PathState state) {
- PathState old_state;
- assert(p);
-
- old_state = p->state;
- p->state = state;
-
- if (state != PATH_WAITING &&
- (state != PATH_RUNNING || p->inotify_triggered))
- path_unwatch(p);
-
- if (state != old_state)
- log_debug("%s changed %s -> %s",
- UNIT(p)->id,
- path_state_to_string(old_state),
- path_state_to_string(state));
-
- unit_notify(UNIT(p), state_translation_table[old_state], state_translation_table[state], true);
-}
-
-static void path_enter_waiting(Path *p, bool initial, bool recheck);
-
-static int path_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) {
- int r;
- DBusError error;
-
- assert(p);
- dbus_error_init(&error);
-
- /* Don't start job if we are supposed to go down */
- if (UNIT(p)->job && UNIT(p)->job->type == JOB_STOP)
- return;
-
- if ((r = manager_add_job(UNIT(p)->manager, JOB_START, UNIT_DEREF(p->unit), JOB_REPLACE, true, &error, NULL)) < 0)
- goto fail;
-
- p->inotify_triggered = false;
-
- if ((r = path_watch(p)) < 0)
- goto fail;
-
- path_set_state(p, PATH_RUNNING);
- return;
-
-fail:
- log_warning("%s failed to queue unit startup job: %s", UNIT(p)->id, bus_error(&error, r));
- path_enter_dead(p, PATH_FAILURE_RESOURCES);
-
- dbus_error_free(&error);
-}
-
-static bool path_check_good(Path *p, bool initial) {
- PathSpec *s;
- bool good = false;
-
- assert(p);
-
- LIST_FOREACH(spec, s, p->specs) {
- good = path_spec_check_good(s, initial);
-
- if (good)
- break;
- }
-
- return good;
-}
-
-static void path_enter_waiting(Path *p, bool initial, bool recheck) {
- int r;
-
- if (recheck)
- if (path_check_good(p, initial)) {
- log_debug("%s got triggered.", UNIT(p)->id);
- path_enter_running(p);
- return;
- }
-
- if ((r = path_watch(p)) < 0)
- goto fail;
-
- /* Hmm, so now we have created inotify watches, but the file
- * might have appeared/been removed by now, so we must
- * recheck */
-
- if (recheck)
- if (path_check_good(p, false)) {
- log_debug("%s got triggered.", UNIT(p)->id);
- path_enter_running(p);
- return;
- }
-
- path_set_state(p, PATH_WAITING);
- return;
-
-fail:
- log_warning("%s failed to enter waiting state: %s", UNIT(p)->id, strerror(-r));
- path_enter_dead(p, PATH_FAILURE_RESOURCES);
-}
-
-static void path_mkdir(Path *p) {
- PathSpec *s;
-
- assert(p);
-
- if (!p->make_directory)
- return;
-
- LIST_FOREACH(spec, s, p->specs)
- path_spec_mkdir(s, p->directory_mode);
-}
-
-static int path_start(Unit *u) {
- Path *p = PATH(u);
-
- assert(p);
- assert(p->state == PATH_DEAD || p->state == PATH_FAILED);
-
- if (UNIT_DEREF(p->unit)->load_state != UNIT_LOADED)
- return -ENOENT;
-
- path_mkdir(p);
-
- p->result = PATH_SUCCESS;
- path_enter_waiting(p, true, true);
-
- return 0;
-}
-
-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 0;
-}
-
-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;
-
- if ((state = path_state_from_string(value)) < 0)
- log_debug("Failed to parse state value %s", value);
- else
- p->deserialized_state = state;
-
- } else if (streq(key, "result")) {
- PathResult f;
-
- f = path_result_from_string(value);
- if (f < 0)
- log_debug("Failed to parse result value %s", value);
- else if (f != PATH_SUCCESS)
- p->result = f;
-
- } else
- log_debug("Unknown serialization key '%s'", key);
-
- return 0;
-}
-
-static UnitActiveState path_active_state(Unit *u) {
- assert(u);
-
- return state_translation_table[PATH(u)->state];
-}
-
-static const char *path_sub_state_to_string(Unit *u) {
- assert(u);
-
- return path_state_to_string(PATH(u)->state);
-}
-
-static void path_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
- Path *p = PATH(u);
- PathSpec *s;
- int changed;
-
- assert(p);
- assert(fd >= 0);
-
- if (p->state != PATH_WAITING &&
- p->state != PATH_RUNNING)
- return;
-
- /* 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, events);
- 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;
-
-fail:
- path_enter_dead(p, PATH_FAILURE_RESOURCES);
-}
-
-void path_unit_notify(Unit *u, UnitActiveState new_state) {
- Iterator i;
- Unit *k;
-
- if (u->type == UNIT_PATH)
- return;
-
- SET_FOREACH(k, u->dependencies[UNIT_TRIGGERED_BY], i) {
- Path *p;
-
- if (k->type != UNIT_PATH)
- continue;
-
- if (k->load_state != UNIT_LOADED)
- continue;
-
- p = PATH(k);
-
- if (p->state == PATH_RUNNING && new_state == UNIT_INACTIVE) {
- log_debug("%s got notified about unit deactivation.", UNIT(p)->id);
-
- /* Hmm, so inotify was triggered since the
- * last activation, so I guess we need to
- * recheck what is going on. */
- path_enter_waiting(p, false, p->inotify_triggered);
- }
- }
-}
-
-static void path_reset_failed(Unit *u) {
- Path *p = PATH(u);
-
- assert(p);
-
- if (p->state == PATH_FAILED)
- path_set_state(p, PATH_DEAD);
-
- p->result = PATH_SUCCESS;
-}
-
-static const char* const path_state_table[_PATH_STATE_MAX] = {
- [PATH_DEAD] = "dead",
- [PATH_WAITING] = "waiting",
- [PATH_RUNNING] = "running",
- [PATH_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(path_state, PathState);
-
-static const char* const path_type_table[_PATH_TYPE_MAX] = {
- [PATH_EXISTS] = "PathExists",
- [PATH_EXISTS_GLOB] = "PathExistsGlob",
- [PATH_CHANGED] = "PathChanged",
- [PATH_MODIFIED] = "PathModified",
- [PATH_DIRECTORY_NOT_EMPTY] = "DirectoryNotEmpty"
-};
-
-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,
-
- .fd_event = path_fd_event,
-
- .reset_failed = path_reset_failed,
-
- .bus_interface = "org.freedesktop.systemd1.Path",
- .bus_message_handler = bus_path_message_handler,
- .bus_invalidating_properties = bus_path_invalidating_properties
-};
diff --git a/src/core/path.h b/src/core/path.h
deleted file mode 100644
index 77926888ae..0000000000
--- a/src/core/path.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct Path Path;
-
-#include "unit.h"
-#include "mount.h"
-
-typedef enum PathState {
- PATH_DEAD,
- PATH_WAITING,
- PATH_RUNNING,
- PATH_FAILED,
- _PATH_STATE_MAX,
- _PATH_STATE_INVALID = -1
-} PathState;
-
-typedef enum PathType {
- PATH_EXISTS,
- PATH_EXISTS_GLOB,
- PATH_DIRECTORY_NOT_EMPTY,
- PATH_CHANGED,
- PATH_MODIFIED,
- _PATH_TYPE_MAX,
- _PATH_TYPE_INVALID = -1
-} PathType;
-
-typedef struct PathSpec {
- char *path;
-
- Watch watch;
-
- LIST_FIELDS(struct PathSpec, spec);
-
- PathType type;
- int inotify_fd;
- int primary_wd;
-
- bool previous_exists;
-} PathSpec;
-
-int path_spec_watch(PathSpec *s, Unit *u);
-void path_spec_unwatch(PathSpec *s, Unit *u);
-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);
-
- UnitRef unit;
-
- PathState state, deserialized_state;
-
- bool inotify_triggered;
-
- bool make_directory;
- mode_t directory_mode;
-
- PathResult result;
-};
-
-void path_unit_notify(Unit *u, UnitActiveState new_state);
-
-/* Called from the mount code figure out if a mount is a dependency of
- * any of the paths of this path object */
-int path_add_one_mount_link(Path *p, Mount *m);
-
-extern const UnitVTable path_vtable;
-
-const char* path_state_to_string(PathState i);
-PathState path_state_from_string(const char *s);
-
-const char* path_type_to_string(PathType i);
-PathType path_type_from_string(const char *s);
-
-const char* path_result_to_string(PathResult i);
-PathResult path_result_from_string(const char *s);
diff --git a/src/core/securebits.h b/src/core/securebits.h
deleted file mode 100644
index ba0bba5353..0000000000
--- a/src/core/securebits.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef _LINUX_SECUREBITS_H
-#define _LINUX_SECUREBITS_H 1
-
-/* This is minimal version of Linux' linux/securebits.h header file,
- * which is licensed GPL2 */
-
-#define SECUREBITS_DEFAULT 0x00000000
-
-/* When set UID 0 has no special privileges. When unset, we support
- inheritance of root-permissions and suid-root executable under
- compatibility mode. We raise the effective and inheritable bitmasks
- *of the executable file* if the effective uid of the new process is
- 0. If the real uid is 0, we raise the effective (legacy) bit of the
- executable file. */
-#define SECURE_NOROOT 0
-#define SECURE_NOROOT_LOCKED 1 /* make bit-0 immutable */
-
-/* When set, setuid to/from uid 0 does not trigger capability-"fixup".
- When unset, to provide compatibility with old programs relying on
- set*uid to gain/lose privilege, transitions to/from uid 0 cause
- capabilities to be gained/lost. */
-#define SECURE_NO_SETUID_FIXUP 2
-#define SECURE_NO_SETUID_FIXUP_LOCKED 3 /* make bit-2 immutable */
-
-/* When set, a process can retain its capabilities even after
- transitioning to a non-root user (the set-uid fixup suppressed by
- bit 2). Bit-4 is cleared when a process calls exec(); setting both
- bit 4 and 5 will create a barrier through exec that no exec()'d
- child can use this feature again. */
-#define SECURE_KEEP_CAPS 4
-#define SECURE_KEEP_CAPS_LOCKED 5 /* make bit-4 immutable */
-
-/* Each securesetting is implemented using two bits. One bit specifies
- whether the setting is on or off. The other bit specify whether the
- setting is locked or not. A setting which is locked cannot be
- changed from user-level. */
-#define issecure_mask(X) (1 << (X))
-#define issecure(X) (issecure_mask(X) & current_cred_xxx(securebits))
-
-#define SECURE_ALL_BITS (issecure_mask(SECURE_NOROOT) | \
- issecure_mask(SECURE_NO_SETUID_FIXUP) | \
- issecure_mask(SECURE_KEEP_CAPS))
-#define SECURE_ALL_LOCKS (SECURE_ALL_BITS << 1)
-
-#endif /* !_LINUX_SECUREBITS_H */
diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c
deleted file mode 100644
index 6dfe8b45f3..0000000000
--- a/src/core/selinux-access.c
+++ /dev/null
@@ -1,441 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2012 Dan Walsh
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "selinux-access.h"
-
-#ifdef HAVE_SELINUX
-
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <limits.h>
-#include <selinux/selinux.h>
-#include <selinux/avc.h>
-#ifdef HAVE_AUDIT
-#include <libaudit.h>
-#endif
-#include <dbus.h>
-
-#include "util.h"
-#include "log.h"
-#include "bus-errors.h"
-#include "dbus-common.h"
-#include "audit.h"
-#include "selinux-util.h"
-#include "audit-fd.h"
-
-static bool initialized = false;
-
-struct auditstruct {
- const char *path;
- char *cmdline;
- uid_t loginuid;
- uid_t uid;
- gid_t gid;
-};
-
-static int bus_get_selinux_security_context(
- DBusConnection *connection,
- const char *name,
- char **scon,
- DBusError *error) {
-
- _cleanup_dbus_message_unref_ DBusMessage *m = NULL, *reply = NULL;
- DBusMessageIter iter, sub;
- const char *bytes;
- char *b;
- int nbytes;
-
- m = dbus_message_new_method_call(
- DBUS_SERVICE_DBUS,
- DBUS_PATH_DBUS,
- DBUS_INTERFACE_DBUS,
- "GetConnectionSELinuxSecurityContext");
- if (!m) {
- dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
- return -ENOMEM;
- }
-
- if (!dbus_message_append_args(
- m,
- DBUS_TYPE_STRING, &name,
- DBUS_TYPE_INVALID)) {
- dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
- return -ENOMEM;
- }
-
- reply = dbus_connection_send_with_reply_and_block(connection, m, -1, error);
- if (!reply)
- return -EIO;
-
- if (dbus_set_error_from_message(error, reply))
- return -EIO;
-
- if (!dbus_message_iter_init(reply, &iter))
- return -EIO;
-
- if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
- return -EIO;
-
- dbus_message_iter_recurse(&iter, &sub);
- dbus_message_iter_get_fixed_array(&sub, &bytes, &nbytes);
-
- b = strndup(bytes, nbytes);
- if (!b)
- return -ENOMEM;
-
- *scon = b;
-
- log_debug("GetConnectionSELinuxSecurityContext %s (pid %ld)", *scon, (long) bus_get_unix_process_id(connection, name, error));
-
- return 0;
-}
-
-static int bus_get_audit_data(
- DBusConnection *connection,
- const char *name,
- struct auditstruct *audit,
- DBusError *error) {
-
- pid_t pid;
- int r;
-
- pid = bus_get_unix_process_id(connection, name, error);
- if (pid <= 0)
- return -EIO;
-
- r = audit_loginuid_from_pid(pid, &audit->loginuid);
- if (r < 0)
- return r;
-
- r = get_process_uid(pid, &audit->uid);
- if (r < 0)
- return r;
-
- r = get_process_gid(pid, &audit->gid);
- if (r < 0)
- return r;
-
- r = get_process_cmdline(pid, LINE_MAX, true, &audit->cmdline);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-/*
- Any time an access gets denied this callback will be called
- with the aduit 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) {
-
- struct auditstruct *audit = (struct auditstruct *) auditdata;
-
- snprintf(msgbuf, msgbufsize,
- "auid=%d uid=%d gid=%d%s%s%s%s%s%s",
- audit->loginuid,
- audit->uid,
- audit->gid,
- (audit->path ? " path=\"" : ""),
- strempty(audit->path),
- (audit->path ? "\"" : ""),
- (audit->cmdline ? " cmdline=\"" : ""),
- strempty(audit->cmdline),
- (audit->cmdline ? "\"" : ""));
-
- msgbuf[msgbufsize-1] = 0;
-
- return 0;
-}
-
-/*
- Any time an access gets denied this callback will be called
- code copied from dbus. If audit is turned on the messages will go as
- user_avc's into the /var/log/audit/audit.log, otherwise they will be
- sent to syslog.
-*/
-static int log_callback(int type, const char *fmt, ...) {
- va_list ap;
-
- va_start(ap, fmt);
-
-#ifdef HAVE_AUDIT
- if (get_audit_fd() >= 0) {
- char buf[LINE_MAX];
-
- vsnprintf(buf, sizeof(buf), fmt, ap);
- audit_log_user_avc_message(get_audit_fd(), AUDIT_USER_AVC, buf, NULL, NULL, NULL, 0);
- va_end(ap);
-
- return 0;
- }
-#endif
- log_metav(LOG_USER | LOG_INFO, __FILE__, __LINE__, __FUNCTION__, fmt, ap);
- va_end(ap);
-
- return 0;
-}
-
-/*
- Function must be called once to initialize the SELinux AVC environment.
- Sets up callbacks.
- If you want to cleanup memory you should need to call selinux_access_finish.
-*/
-static int access_init(void) {
- int r;
-
- if (avc_open(NULL, 0)) {
- log_error("avc_open() failed: %m");
- return -errno;
- }
-
- selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback) audit_callback);
- selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) log_callback);
-
- if (security_getenforce() >= 0)
- return 0;
-
- r = -errno;
- avc_destroy();
-
- return r;
-}
-
-static int selinux_access_init(DBusError *error) {
- int r;
-
- if (initialized)
- return 0;
-
- if (use_selinux()) {
- r = access_init();
- if (r < 0) {
- dbus_set_error(error, DBUS_ERROR_ACCESS_DENIED, "Failed to initialize SELinux.");
- return r;
- }
- }
-
- initialized = true;
- return 0;
-}
-
-void selinux_access_free(void) {
- if (!initialized)
- return;
-
- avc_destroy();
- initialized = false;
-}
-
-static int get_audit_data(
- DBusConnection *connection,
- DBusMessage *message,
- struct auditstruct *audit,
- DBusError *error) {
-
- const char *sender;
- int r, fd;
- struct ucred ucred;
- socklen_t len;
-
- sender = dbus_message_get_sender(message);
- if (sender)
- return bus_get_audit_data(connection, sender, audit, error);
-
- if (!dbus_connection_get_unix_fd(connection, &fd))
- return -EINVAL;
-
- r = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &len);
- if (r < 0) {
- log_error("Failed to determine peer credentials: %m");
- return -errno;
- }
-
- audit->uid = ucred.uid;
- audit->gid = ucred.gid;
-
- r = audit_loginuid_from_pid(ucred.pid, &audit->loginuid);
- if (r < 0)
- return r;
-
- r = get_process_cmdline(ucred.pid, LINE_MAX, true, &audit->cmdline);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-/*
- This function returns the security context of the remote end of the dbus
- connections. Whether it is on the bus or a local connection.
-*/
-static int get_calling_context(
- DBusConnection *connection,
- DBusMessage *message,
- security_context_t *scon,
- DBusError *error) {
-
- const char *sender;
- int r;
- int fd;
-
- /*
- If sender exists then
- if sender is NULL this indicates a local connection. Grab the fd
- from dbus and do an getpeercon to peers process context
- */
- sender = dbus_message_get_sender(message);
- if (sender) {
- log_error("SELinux Got Sender %s", sender);
-
- r = bus_get_selinux_security_context(connection, sender, scon, error);
- if (r >= 0)
- return r;
-
- log_error("bus_get_selinux_security_context failed: %m");
- return r;
- }
-
- log_debug("SELinux No Sender");
- if (!dbus_connection_get_unix_fd(connection, &fd)) {
- log_error("bus_connection_get_unix_fd failed %m");
- return -EINVAL;
- }
-
- r = getpeercon(fd, scon);
- if (r < 0) {
- log_error("getpeercon failed %m");
- return -errno;
- }
-
- return 0;
-}
-
-/*
- 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 selinux_access_check(
- DBusConnection *connection,
- DBusMessage *message,
- const char *path,
- const char *permission,
- DBusError *error) {
-
- security_context_t scon = NULL, fcon = NULL;
- int r = 0;
- const char *tclass = NULL;
- struct auditstruct audit;
-
- assert(connection);
- assert(message);
- assert(permission);
- assert(error);
-
- if (!use_selinux())
- return 0;
-
- r = selinux_access_init(error);
- if (r < 0)
- return r;
-
- log_debug("SELinux access check for path=%s permission=%s", strna(path), permission);
-
- audit.uid = audit.loginuid = (uid_t) -1;
- audit.gid = (gid_t) -1;
- audit.cmdline = NULL;
- audit.path = path;
-
- r = get_calling_context(connection, message, &scon, error);
- if (r < 0) {
- log_error("Failed to get caller's security context on: %m");
- goto finish;
- }
-
- if (path) {
- tclass = "service";
- /* get the file context of the unit file */
- r = getfilecon(path, &fcon);
- if (r < 0) {
- dbus_set_error(error, DBUS_ERROR_ACCESS_DENIED, "Failed to get file context on %s.", path);
- r = -errno;
- log_error("Failed to get security context on %s: %m",path);
- goto finish;
- }
-
- } else {
- tclass = "system";
- r = getcon(&fcon);
- if (r < 0) {
- dbus_set_error(error, DBUS_ERROR_ACCESS_DENIED, "Failed to get current context.");
- r = -errno;
- log_error("Failed to get current process context on: %m");
- goto finish;
- }
- }
-
- (void) get_audit_data(connection, message, &audit, error);
-
- errno = 0;
- r = selinux_check_access(scon, fcon, tclass, permission, &audit);
- if (r < 0) {
- dbus_set_error(error, DBUS_ERROR_ACCESS_DENIED, "SELinux policy denies access.");
- r = -errno;
- log_error("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, audit.cmdline, r);
-
-finish:
- free(audit.cmdline);
- freecon(scon);
- freecon(fcon);
-
- if (r && security_getenforce() != 1) {
- dbus_error_init(error);
- r = 0;
- }
-
- return r;
-}
-
-#else
-
-int selinux_access_check(
- DBusConnection *connection,
- DBusMessage *message,
- const char *path,
- const char *permission,
- DBusError *error) {
-
- return 0;
-}
-
-void selinux_access_free(void) {
-}
-
-#endif
diff --git a/src/core/selinux-access.h b/src/core/selinux-access.h
deleted file mode 100644
index 9183cbc9a6..0000000000
--- a/src/core/selinux-access.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2012 Dan Walsh
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <dbus.h>
-
-void selinux_access_free(void);
-
-int selinux_access_check(DBusConnection *connection, DBusMessage *message, const char *path, const char *permission, DBusError *error);
-
-#ifdef HAVE_SELINUX
-
-#define SELINUX_ACCESS_CHECK(connection, message, permission) \
- do { \
- DBusError _error; \
- int _r; \
- DBusConnection *_c = (connection); \
- DBusMessage *_m = (message); \
- dbus_error_init(&_error); \
- _r = selinux_access_check(_c, _m, NULL, (permission), &_error); \
- if (_r < 0) \
- return bus_send_error_reply(_c, _m, &_error, _r); \
- } while (false)
-
-#define SELINUX_UNIT_ACCESS_CHECK(unit, connection, message, permission) \
- do { \
- DBusError _error; \
- int _r; \
- DBusConnection *_c = (connection); \
- DBusMessage *_m = (message); \
- Unit *_u = (unit); \
- dbus_error_init(&_error); \
- _r = selinux_access_check(_c, _m, _u->source_path ?: _u->fragment_path, (permission), &_error); \
- if (_r < 0) \
- return bus_send_error_reply(_c, _m, &_error, _r); \
- } while (false)
-
-#else
-
-#define SELINUX_ACCESS_CHECK(connection, message, permission) do { } while (false)
-#define SELINUX_UNIT_ACCESS_CHECK(unit, connection, message, permission) do { } while (false)
-
-#endif
diff --git a/src/core/selinux-setup.c b/src/core/selinux-setup.c
deleted file mode 100644
index e9c0de92f1..0000000000
--- a/src/core/selinux-setup.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <unistd.h>
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-
-#ifdef HAVE_SELINUX
-#include <selinux/selinux.h>
-#endif
-
-#include "selinux-setup.h"
-#include "selinux-util.h"
-#include "label.h"
-#include "mount-setup.h"
-#include "macro.h"
-#include "util.h"
-#include "log.h"
-
-#ifdef HAVE_SELINUX
-static int null_log(int type, const char *fmt, ...) {
- return 0;
-}
-#endif
-
-int 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;
-
- 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);
-
- /* Make sure getcon() works, which needs /proc and /sys */
- mount_setup_early();
-
- /* Already initialized by somebody else? */
- r = getcon_raw(&con);
- if (r == 0) {
- bool initialized;
-
- initialized = !streq(con, "kernel");
- freecon(con);
-
- if (initialized)
- return 0;
- }
-
- /* Make sure we have no fds open while loading the policy and
- * transitioning */
- log_close();
-
- /* Now load the policy */
- before_load = now(CLOCK_MONOTONIC);
- r = selinux_init_load_policy(&enforce);
- if (r == 0) {
- char timespan[FORMAT_TIMESPAN_MAX];
- char *label;
-
- retest_selinux();
-
- /* Transition to the new context */
- r = label_get_create_label_from_exe(SYSTEMD_BINARY_PATH, &label);
- if (r < 0 || label == NULL) {
- log_open();
- log_error("Failed to compute init label, ignoring.");
- } else {
- r = setcon(label);
-
- log_open();
- if (r < 0)
- log_error("Failed to transition into init label '%s', ignoring.", label);
-
- label_free(label);
- }
-
- after_load = now(CLOCK_MONOTONIC);
-
- log_info("Successfully loaded SELinux policy in %s.",
- format_timespan(timespan, sizeof(timespan), after_load - before_load));
-
- *loaded_policy = true;
-
- } else {
- log_open();
-
- if (enforce > 0) {
- log_error("Failed to load SELinux policy. Freezing.");
- return -EIO;
- } 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 39e2bc25bb..0000000000
--- a/src/core/selinux-setup.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-
-int selinux_setup(bool *loaded_policy);
diff --git a/src/core/service.c b/src/core/service.c
deleted file mode 100644
index cf08485374..0000000000
--- a/src/core/service.c
+++ /dev/null
@@ -1,3941 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <signal.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <sys/reboot.h>
-
-#include "manager.h"
-#include "unit.h"
-#include "service.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
-#include "log.h"
-#include "strv.h"
-#include "unit-name.h"
-#include "unit-printf.h"
-#include "dbus-service.h"
-#include "special.h"
-#include "bus-errors.h"
-#include "exit-status.h"
-#include "def.h"
-#include "path-util.h"
-#include "util.h"
-#include "utf8.h"
-
-#ifdef HAVE_SYSV_COMPAT
-
-#define DEFAULT_SYSV_TIMEOUT_USEC (5*USEC_PER_MINUTE)
-
-typedef enum RunlevelType {
- RUNLEVEL_UP,
- RUNLEVEL_DOWN,
- RUNLEVEL_SYSINIT
-} RunlevelType;
-
-static const struct {
- const char *path;
- const char *target;
- const RunlevelType type;
-} rcnd_table[] = {
- /* Standard SysV runlevels for start-up */
- { "rc1.d", SPECIAL_RESCUE_TARGET, RUNLEVEL_UP },
- { "rc2.d", SPECIAL_RUNLEVEL2_TARGET, RUNLEVEL_UP },
- { "rc3.d", SPECIAL_RUNLEVEL3_TARGET, RUNLEVEL_UP },
- { "rc4.d", SPECIAL_RUNLEVEL4_TARGET, RUNLEVEL_UP },
- { "rc5.d", SPECIAL_RUNLEVEL5_TARGET, RUNLEVEL_UP },
-
-#ifdef TARGET_SUSE
- /* SUSE style boot.d */
- { "boot.d", SPECIAL_SYSINIT_TARGET, RUNLEVEL_SYSINIT },
-#endif
-
-#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM)
- /* Debian style rcS.d */
- { "rcS.d", SPECIAL_SYSINIT_TARGET, RUNLEVEL_SYSINIT },
-#endif
-
- /* Standard SysV runlevels for shutdown */
- { "rc0.d", SPECIAL_POWEROFF_TARGET, RUNLEVEL_DOWN },
- { "rc6.d", SPECIAL_REBOOT_TARGET, RUNLEVEL_DOWN }
-
- /* Note that the order here matters, as we read the
- directories in this order, and we want to make sure that
- sysv_start_priority is known when we first load the
- unit. And that value we only know from S links. Hence
- UP/SYSINIT must be read before DOWN */
-};
-
-#define RUNLEVELS_UP "12345"
-/* #define RUNLEVELS_DOWN "06" */
-#define RUNLEVELS_BOOT "bBsS"
-#endif
-
-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_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_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 void service_init(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
-
- s->timeout_start_usec = DEFAULT_TIMEOUT_USEC;
- s->timeout_stop_usec = DEFAULT_TIMEOUT_USEC;
- s->restart_usec = DEFAULT_RESTART_USEC;
- s->type = _SERVICE_TYPE_INVALID;
-
- s->watchdog_watch.type = WATCH_INVALID;
-
- s->timer_watch.type = WATCH_INVALID;
-#ifdef HAVE_SYSV_COMPAT
- s->sysv_start_priority = -1;
- s->sysv_start_priority_from_rcnd = -1;
-#endif
- s->socket_fd = -1;
- s->guess_main_pid = true;
-
- exec_context_init(&s->exec_context);
- kill_context_init(&s->kill_context);
-
- RATELIMIT_INIT(s->start_limit, 10*USEC_PER_SEC, 5);
-
- 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_debug("Stopping watch for %s's PID file %s", UNIT(s)->id, s->pid_file_pathspec->path);
- path_spec_unwatch(s->pid_file_pathspec, UNIT(s));
- path_spec_done(s->pid_file_pathspec);
- free(s->pid_file_pathspec);
- s->pid_file_pathspec = NULL;
-}
-
-static int service_set_main_pid(Service *s, pid_t pid) {
- pid_t ppid;
-
- assert(s);
-
- if (pid <= 1)
- return -EINVAL;
-
- if (pid == getpid())
- return -EINVAL;
-
- s->main_pid = pid;
- s->main_pid_known = true;
-
- if (get_parent_of_pid(pid, &ppid) >= 0 && ppid != getpid()) {
- log_warning("%s: Supervising process %lu which is not our child. We'll most likely not notice when it exits.",
- UNIT(s)->id, (unsigned long) pid);
-
- s->main_pid_alien = true;
- } else
- s->main_pid_alien = false;
-
- exec_status_start(&s->main_exec_status, pid);
-
- return 0;
-}
-
-static void service_close_socket_fd(Service *s) {
- assert(s);
-
- if (s->socket_fd < 0)
- return;
-
- close_nointr_nofail(s->socket_fd);
- s->socket_fd = -1;
-}
-
-static void service_connection_unref(Service *s) {
- assert(s);
-
- if (!UNIT_DEREF(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);
-
- unit_unwatch_timer(UNIT(s), &s->watchdog_watch);
- s->watchdog_timestamp.realtime = 0;
- s->watchdog_timestamp.monotonic = 0;
-}
-
-static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart);
-
-static void service_handle_watchdog(Service *s) {
- usec_t offset;
- int r;
-
- assert(s);
-
- if (s->watchdog_usec == 0)
- return;
-
- offset = now(CLOCK_MONOTONIC) - s->watchdog_timestamp.monotonic;
- if (offset >= s->watchdog_usec) {
- log_error("%s watchdog timeout!", UNIT(s)->id);
- service_enter_dead(s, SERVICE_FAILURE_WATCHDOG, true);
- return;
- }
-
- r = unit_watch_timer(UNIT(s), s->watchdog_usec - offset, &s->watchdog_watch);
- if (r < 0)
- log_warning("%s failed to install watchdog timer: %s", UNIT(s)->id, strerror(-r));
-}
-
-static void service_reset_watchdog(Service *s) {
- assert(s);
-
- dual_timestamp_get(&s->watchdog_timestamp);
- service_handle_watchdog(s);
-}
-
-static void service_done(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
-
- free(s->pid_file);
- s->pid_file = NULL;
-
-#ifdef HAVE_SYSV_COMPAT
- free(s->sysv_runlevels);
- s->sysv_runlevels = NULL;
-#endif
-
- free(s->status_text);
- s->status_text = NULL;
-
- exec_context_done(&s->exec_context);
- exec_command_free_array(s->exec_command, _SERVICE_EXEC_COMMAND_MAX);
- s->control_command = NULL;
- s->main_command = NULL;
-
- set_free(s->restart_ignore_status.code);
- s->restart_ignore_status.code = NULL;
- set_free(s->restart_ignore_status.signal);
- s->restart_ignore_status.signal = NULL;
-
- set_free(s->success_status.code);
- s->success_status.code = NULL;
- set_free(s->success_status.signal);
- s->success_status.signal = NULL;
-
- /* This will leak a process, but at least no memory or any of
- * our resources */
- service_unwatch_main_pid(s);
- service_unwatch_control_pid(s);
- service_unwatch_pid_file(s);
-
- if (s->bus_name) {
- unit_unwatch_bus_name(u, s->bus_name);
- free(s->bus_name);
- s->bus_name = NULL;
- }
-
- service_close_socket_fd(s);
- service_connection_unref(s);
-
- unit_ref_unset(&s->accept_socket);
-
- service_stop_watchdog(s);
-
- unit_unwatch_timer(u, &s->timer_watch);
-}
-
-#ifdef HAVE_SYSV_COMPAT
-static char *sysv_translate_name(const char *name) {
- char *r;
-
- if (!(r = new(char, strlen(name) + sizeof(".service"))))
- return NULL;
-
-#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM)
- if (endswith(name, ".sh"))
- /* Drop Debian-style .sh suffix */
- strcpy(stpcpy(r, name) - 3, ".service");
-#endif
-#ifdef TARGET_SUSE
- if (startswith(name, "boot."))
- /* Drop SuSE-style boot. prefix */
- strcpy(stpcpy(r, name + 5), ".service");
-#endif
-#ifdef TARGET_FRUGALWARE
- if (startswith(name, "rc."))
- /* Drop Frugalware-style rc. prefix */
- strcpy(stpcpy(r, name + 3), ".service");
-#endif
- else
- /* Normal init scripts */
- strcpy(stpcpy(r, name), ".service");
-
- return r;
-}
-
-static int sysv_translate_facility(const char *name, const char *filename, char **_r) {
-
- /* We silently ignore the $ prefix here. According to the LSB
- * spec it simply indicates whether something is a
- * standardized name or a distribution-specific one. Since we
- * just follow what already exists and do not introduce new
- * uses or names we don't care who introduced a new name. */
-
- static const char * const table[] = {
- /* LSB defined facilities */
- "local_fs", SPECIAL_LOCAL_FS_TARGET,
-#if defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA)
-#else
- /* Due to unfortunate name selection in Mandriva,
- * $network is provided by network-up which is ordered
- * after network which actually starts interfaces.
- * To break the loop, just ignore it */
- "network", SPECIAL_NETWORK_TARGET,
-#endif
- "named", SPECIAL_NSS_LOOKUP_TARGET,
- "portmap", SPECIAL_RPCBIND_TARGET,
- "remote_fs", SPECIAL_REMOTE_FS_TARGET,
- "syslog", SPECIAL_SYSLOG_TARGET,
- "time", SPECIAL_TIME_SYNC_TARGET,
-
- /* common extensions */
- "mail-transfer-agent", SPECIAL_MAIL_TRANSFER_AGENT_TARGET,
- "x-display-manager", SPECIAL_DISPLAY_MANAGER_SERVICE,
- "null", NULL,
-
-#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM)
- "mail-transport-agent", SPECIAL_MAIL_TRANSFER_AGENT_TARGET,
-#endif
-
-#ifdef TARGET_SUSE
- "smtp", SPECIAL_MAIL_TRANSFER_AGENT_TARGET,
-#endif
- };
-
- unsigned i;
- char *r;
- const char *n;
-
- assert(name);
- assert(_r);
-
- n = *name == '$' ? name + 1 : name;
-
- for (i = 0; i < ELEMENTSOF(table); i += 2) {
-
- if (!streq(table[i], n))
- continue;
-
- if (!table[i+1])
- return 0;
-
- if (!(r = strdup(table[i+1])))
- return -ENOMEM;
-
- goto finish;
- }
-
- /* If we don't know this name, fallback heuristics to figure
- * out whether something is a target or a service alias. */
-
- if (*name == '$') {
- if (!unit_prefix_is_valid(n))
- return -EINVAL;
-
- /* Facilities starting with $ are most likely targets */
- r = unit_name_build(n, NULL, ".target");
- } else if (filename && streq(name, filename))
- /* Names equaling the file name of the services are redundant */
- return 0;
- else
- /* Everything else we assume to be normal service names */
- r = sysv_translate_name(n);
-
- if (!r)
- return -ENOMEM;
-
-finish:
- *_r = r;
-
- return 1;
-}
-
-static int sysv_fix_order(Service *s) {
- Unit *other;
- int r;
-
- assert(s);
-
- if (s->sysv_start_priority < 0)
- return 0;
-
- /* For each pair of services where at least one lacks a LSB
- * header, we use the start priority value to order things. */
-
- LIST_FOREACH(units_by_type, other, UNIT(s)->manager->units_by_type[UNIT_SERVICE]) {
- Service *t;
- UnitDependency d;
- bool special_s, special_t;
-
- t = SERVICE(other);
-
- if (s == t)
- continue;
-
- if (UNIT(t)->load_state != UNIT_LOADED)
- continue;
-
- if (t->sysv_start_priority < 0)
- continue;
-
- /* If both units have modern headers we don't care
- * about the priorities */
- if ((UNIT(s)->fragment_path || s->sysv_has_lsb) &&
- (UNIT(t)->fragment_path || t->sysv_has_lsb))
- continue;
-
- special_s = s->sysv_runlevels && !chars_intersect(RUNLEVELS_UP, s->sysv_runlevels);
- special_t = t->sysv_runlevels && !chars_intersect(RUNLEVELS_UP, t->sysv_runlevels);
-
- if (special_t && !special_s)
- d = UNIT_AFTER;
- else if (special_s && !special_t)
- d = UNIT_BEFORE;
- else if (t->sysv_start_priority < s->sysv_start_priority)
- d = UNIT_AFTER;
- else if (t->sysv_start_priority > s->sysv_start_priority)
- d = UNIT_BEFORE;
- else
- continue;
-
- /* FIXME: Maybe we should compare the name here lexicographically? */
-
- if ((r = unit_add_dependency(UNIT(s), d, UNIT(t), true)) < 0)
- return r;
- }
-
- return 0;
-}
-
-static ExecCommand *exec_command_new(const char *path, const char *arg1) {
- ExecCommand *c;
-
- if (!(c = new0(ExecCommand, 1)))
- return NULL;
-
- if (!(c->path = strdup(path))) {
- free(c);
- return NULL;
- }
-
- if (!(c->argv = strv_new(path, arg1, NULL))) {
- free(c->path);
- free(c);
- return NULL;
- }
-
- return c;
-}
-
-static int sysv_exec_commands(Service *s, const bool supports_reload) {
- ExecCommand *c;
-
- assert(s);
- assert(s->is_sysv);
- assert(UNIT(s)->source_path);
-
- c = exec_command_new(UNIT(s)->source_path, "start");
- if (!c)
- return -ENOMEM;
- exec_command_append_list(s->exec_command+SERVICE_EXEC_START, c);
-
- c = exec_command_new(UNIT(s)->source_path, "stop");
- if (!c)
- return -ENOMEM;
- exec_command_append_list(s->exec_command+SERVICE_EXEC_STOP, c);
-
- if (supports_reload) {
- c = exec_command_new(UNIT(s)->source_path, "reload");
- if (!c)
- return -ENOMEM;
- exec_command_append_list(s->exec_command+SERVICE_EXEC_RELOAD, c);
- }
-
- return 0;
-}
-
-static bool usage_contains_reload(const char *line) {
- return (strcasestr(line, "{reload|") ||
- strcasestr(line, "{reload}") ||
- strcasestr(line, "{reload\"") ||
- strcasestr(line, "|reload|") ||
- strcasestr(line, "|reload}") ||
- strcasestr(line, "|reload\""));
-}
-
-static int service_load_sysv_path(Service *s, const char *path) {
- FILE *f;
- Unit *u;
- unsigned line = 0;
- int r;
- enum {
- NORMAL,
- DESCRIPTION,
- LSB,
- LSB_DESCRIPTION,
- USAGE_CONTINUATION
- } state = NORMAL;
- char *short_description = NULL, *long_description = NULL, *chkconfig_description = NULL, *description;
- struct stat st;
- bool supports_reload = false;
-
- assert(s);
- assert(path);
-
- u = UNIT(s);
-
- f = fopen(path, "re");
- if (!f) {
- r = errno == ENOENT ? 0 : -errno;
- goto finish;
- }
-
- if (fstat(fileno(f), &st) < 0) {
- r = -errno;
- goto finish;
- }
-
- free(u->source_path);
- u->source_path = strdup(path);
- if (!u->source_path) {
- r = -ENOMEM;
- goto finish;
- }
- u->source_mtime = timespec_load(&st.st_mtim);
-
- if (null_or_empty(&st)) {
- u->load_state = UNIT_MASKED;
- r = 0;
- goto finish;
- }
-
- s->is_sysv = true;
-
- while (!feof(f)) {
- char l[LINE_MAX], *t;
-
- if (!fgets(l, sizeof(l), f)) {
- if (feof(f))
- break;
-
- r = -errno;
- log_error("Failed to read configuration file '%s': %s", path, strerror(-r));
- goto finish;
- }
-
- line++;
-
- t = strstrip(l);
- if (*t != '#') {
- /* Try to figure out whether this init script supports
- * the reload operation. This heuristic looks for
- * "Usage" lines which include the reload option. */
- if ( state == USAGE_CONTINUATION ||
- (state == NORMAL && strcasestr(t, "usage"))) {
- if (usage_contains_reload(t)) {
- supports_reload = true;
- state = NORMAL;
- } else if (t[strlen(t)-1] == '\\')
- state = USAGE_CONTINUATION;
- else
- state = NORMAL;
- }
-
- continue;
- }
-
- if (state == NORMAL && streq(t, "### BEGIN INIT INFO")) {
- state = LSB;
- s->sysv_has_lsb = true;
- continue;
- }
-
- if ((state == LSB_DESCRIPTION || state == LSB) && streq(t, "### END INIT INFO")) {
- state = NORMAL;
- continue;
- }
-
- t++;
- t += strspn(t, WHITESPACE);
-
- if (state == NORMAL) {
-
- /* Try to parse Red Hat style chkconfig headers */
-
- if (startswith_no_case(t, "chkconfig:")) {
- int start_priority;
- char runlevels[16], *k;
-
- state = NORMAL;
-
- if (sscanf(t+10, "%15s %i %*i",
- runlevels,
- &start_priority) != 2) {
-
- log_warning("[%s:%u] Failed to parse chkconfig line. Ignoring.", path, line);
- continue;
- }
-
- /* A start priority gathered from the
- * symlink farms is preferred over the
- * data from the LSB header. */
- if (start_priority < 0 || start_priority > 99)
- log_warning("[%s:%u] Start priority out of range. Ignoring.", path, line);
- else
- s->sysv_start_priority = start_priority;
-
- char_array_0(runlevels);
- k = delete_chars(runlevels, WHITESPACE "-");
-
- if (k[0]) {
- char *d;
-
- if (!(d = strdup(k))) {
- r = -ENOMEM;
- goto finish;
- }
-
- free(s->sysv_runlevels);
- s->sysv_runlevels = d;
- }
-
- } else if (startswith_no_case(t, "description:")) {
-
- size_t k = strlen(t);
- char *d;
- const char *j;
-
- if (t[k-1] == '\\') {
- state = DESCRIPTION;
- t[k-1] = 0;
- }
-
- if ((j = strstrip(t+12)) && *j) {
- if (!(d = strdup(j))) {
- r = -ENOMEM;
- goto finish;
- }
- } else
- d = NULL;
-
- free(chkconfig_description);
- chkconfig_description = d;
-
- } else if (startswith_no_case(t, "pidfile:")) {
-
- char *fn;
-
- state = NORMAL;
-
- fn = strstrip(t+8);
- if (!path_is_absolute(fn)) {
- log_warning("[%s:%u] PID file not absolute. Ignoring.", path, line);
- continue;
- }
-
- if (!(fn = strdup(fn))) {
- r = -ENOMEM;
- goto finish;
- }
-
- free(s->pid_file);
- s->pid_file = fn;
- }
-
- } else if (state == DESCRIPTION) {
-
- /* Try to parse Red Hat style description
- * continuation */
-
- size_t k = strlen(t);
- char *j;
-
- if (t[k-1] == '\\')
- t[k-1] = 0;
- else
- state = NORMAL;
-
- if ((j = strstrip(t)) && *j) {
- char *d = NULL;
-
- if (chkconfig_description)
- d = strjoin(chkconfig_description, " ", j, NULL);
- else
- d = strdup(j);
-
- if (!d) {
- r = -ENOMEM;
- goto finish;
- }
-
- free(chkconfig_description);
- chkconfig_description = d;
- }
-
- } else if (state == LSB || state == LSB_DESCRIPTION) {
-
- if (startswith_no_case(t, "Provides:")) {
- char *i, *w;
- size_t z;
-
- state = LSB;
-
- FOREACH_WORD_QUOTED(w, z, t+9, i) {
- char *n, *m;
-
- if (!(n = strndup(w, z))) {
- r = -ENOMEM;
- goto finish;
- }
-
- r = sysv_translate_facility(n, path_get_file_name(path), &m);
- free(n);
-
- if (r < 0)
- goto finish;
-
- if (r == 0)
- continue;
-
- if (unit_name_to_type(m) == UNIT_SERVICE)
- r = unit_add_name(u, m);
- else
- /* NB: SysV targets
- * which are provided
- * by a service are
- * pulled in by the
- * services, as an
- * indication that the
- * generic service is
- * now available. This
- * is strictly
- * one-way. The
- * targets do NOT pull
- * in the SysV
- * services! */
- r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_WANTS, m, NULL, true);
-
- if (r < 0)
- log_error("[%s:%u] Failed to add LSB Provides name %s, ignoring: %s", path, line, m, strerror(-r));
-
- free(m);
- }
-
- } else if (startswith_no_case(t, "Required-Start:") ||
- startswith_no_case(t, "Should-Start:") ||
- startswith_no_case(t, "X-Start-Before:") ||
- startswith_no_case(t, "X-Start-After:")) {
- char *i, *w;
- size_t z;
-
- state = LSB;
-
- FOREACH_WORD_QUOTED(w, z, strchr(t, ':')+1, i) {
- char *n, *m;
-
- if (!(n = strndup(w, z))) {
- r = -ENOMEM;
- goto finish;
- }
-
- r = sysv_translate_facility(n, path_get_file_name(path), &m);
-
- if (r < 0) {
- log_error("[%s:%u] Failed to translate LSB dependency %s, ignoring: %s", path, line, n, strerror(-r));
- free(n);
- continue;
- }
-
- free(n);
-
- if (r == 0)
- continue;
-
- r = unit_add_dependency_by_name(u, startswith_no_case(t, "X-Start-Before:") ? UNIT_BEFORE : UNIT_AFTER, m, NULL, true);
-
- if (r < 0)
- log_error("[%s:%u] Failed to add dependency on %s, ignoring: %s", path, line, m, strerror(-r));
-
- free(m);
- }
- } else if (startswith_no_case(t, "Default-Start:")) {
- char *k, *d;
-
- state = LSB;
-
- k = delete_chars(t+14, WHITESPACE "-");
-
- if (k[0] != 0) {
- if (!(d = strdup(k))) {
- r = -ENOMEM;
- goto finish;
- }
-
- free(s->sysv_runlevels);
- s->sysv_runlevels = d;
- }
-
- } else if (startswith_no_case(t, "Description:")) {
- char *d, *j;
-
- state = LSB_DESCRIPTION;
-
- if ((j = strstrip(t+12)) && *j) {
- if (!(d = strdup(j))) {
- r = -ENOMEM;
- goto finish;
- }
- } else
- d = NULL;
-
- free(long_description);
- long_description = d;
-
- } else if (startswith_no_case(t, "Short-Description:")) {
- char *d, *j;
-
- state = LSB;
-
- if ((j = strstrip(t+18)) && *j) {
- if (!(d = strdup(j))) {
- r = -ENOMEM;
- goto finish;
- }
- } else
- d = NULL;
-
- free(short_description);
- short_description = d;
-
- } else if (state == LSB_DESCRIPTION) {
-
- if (startswith(l, "#\t") || startswith(l, "# ")) {
- char *j;
-
- if ((j = strstrip(t)) && *j) {
- char *d = NULL;
-
- if (long_description)
- d = strjoin(long_description, " ", t, NULL);
- else
- d = strdup(j);
-
- if (!d) {
- r = -ENOMEM;
- goto finish;
- }
-
- free(long_description);
- long_description = d;
- }
-
- } else
- state = LSB;
- }
- }
- }
-
- if ((r = sysv_exec_commands(s, supports_reload)) < 0)
- goto finish;
- if (s->sysv_runlevels &&
- chars_intersect(RUNLEVELS_BOOT, s->sysv_runlevels) &&
- chars_intersect(RUNLEVELS_UP, s->sysv_runlevels)) {
- /* Service has both boot and "up" runlevels
- configured. Kill the "up" ones. */
- delete_chars(s->sysv_runlevels, RUNLEVELS_UP);
- }
-
- if (s->sysv_runlevels && !chars_intersect(RUNLEVELS_UP, s->sysv_runlevels)) {
- /* If there a runlevels configured for this service
- * but none of the standard ones, then we assume this
- * is some special kind of service (which might be
- * needed for early boot) and don't create any links
- * to it. */
-
- UNIT(s)->default_dependencies = false;
-
- /* Don't timeout special services during boot (like fsck) */
- s->timeout_start_usec = 0;
- s->timeout_stop_usec = 0;
- } else {
- s->timeout_start_usec = DEFAULT_SYSV_TIMEOUT_USEC;
- s->timeout_stop_usec = DEFAULT_SYSV_TIMEOUT_USEC;
- }
-
- /* Special setting for all SysV services */
- s->type = SERVICE_FORKING;
- s->remain_after_exit = !s->pid_file;
- s->guess_main_pid = false;
- s->restart = SERVICE_RESTART_NO;
- s->exec_context.ignore_sigpipe = false;
- s->kill_context.kill_mode = KILL_PROCESS;
-
- /* We use the long description only if
- * no short description is set. */
-
- if (short_description)
- description = short_description;
- else if (chkconfig_description)
- description = chkconfig_description;
- else if (long_description)
- description = long_description;
- else
- description = NULL;
-
- if (description) {
- char *d;
-
- if (!(d = strappend(s->sysv_has_lsb ? "LSB: " : "SYSV: ", description))) {
- r = -ENOMEM;
- goto finish;
- }
-
- u->description = d;
- }
-
- /* The priority that has been set in /etc/rcN.d/ hierarchies
- * takes precedence over what is stored as default in the LSB
- * header */
- if (s->sysv_start_priority_from_rcnd >= 0)
- s->sysv_start_priority = s->sysv_start_priority_from_rcnd;
-
- u->load_state = UNIT_LOADED;
- r = 0;
-
-finish:
-
- if (f)
- fclose(f);
-
- free(short_description);
- free(long_description);
- free(chkconfig_description);
-
- return r;
-}
-
-static int service_load_sysv_name(Service *s, const char *name) {
- char **p;
-
- assert(s);
- assert(name);
-
- /* For SysV services we strip the boot.*, rc.* and *.sh
- * prefixes/suffixes. */
-#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM)
- if (endswith(name, ".sh.service"))
- return -ENOENT;
-#endif
-
-#ifdef TARGET_SUSE
- if (startswith(name, "boot."))
- return -ENOENT;
-#endif
-
-#ifdef TARGET_FRUGALWARE
- if (startswith(name, "rc."))
- return -ENOENT;
-#endif
-
- STRV_FOREACH(p, UNIT(s)->manager->lookup_paths.sysvinit_path) {
- char *path;
- int r;
-
- path = strjoin(*p, "/", name, NULL);
- if (!path)
- return -ENOMEM;
-
- assert(endswith(path, ".service"));
- path[strlen(path)-8] = 0;
-
- r = service_load_sysv_path(s, path);
-
-#if defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU) || defined(TARGET_ANGSTROM)
- if (r >= 0 && UNIT(s)->load_state == UNIT_STUB) {
- /* Try Debian style *.sh source'able init scripts */
- strcat(path, ".sh");
- r = service_load_sysv_path(s, path);
- }
-#endif
- free(path);
-
-#ifdef TARGET_SUSE
- if (r >= 0 && UNIT(s)->load_state == UNIT_STUB) {
- /* Try SUSE style boot.* init scripts */
-
- path = strjoin(*p, "/boot.", name, NULL);
- if (!path)
- return -ENOMEM;
-
- /* Drop .service suffix */
- path[strlen(path)-8] = 0;
- r = service_load_sysv_path(s, path);
- free(path);
- }
-#endif
-
-#ifdef TARGET_FRUGALWARE
- if (r >= 0 && UNIT(s)->load_state == UNIT_STUB) {
- /* Try Frugalware style rc.* init scripts */
-
- path = strjoin(*p, "/rc.", name, NULL);
- if (!path)
- return -ENOMEM;
-
- /* Drop .service suffix */
- path[strlen(path)-8] = 0;
- r = service_load_sysv_path(s, path);
- free(path);
- }
-#endif
-
- if (r < 0)
- return r;
-
- if ((UNIT(s)->load_state != UNIT_STUB))
- break;
- }
-
- return 0;
-}
-
-static int service_load_sysv(Service *s) {
- const char *t;
- Iterator i;
- int r;
-
- assert(s);
-
- /* Load service data from SysV init scripts, preferably with
- * LSB headers ... */
-
- if (strv_isempty(UNIT(s)->manager->lookup_paths.sysvinit_path))
- return 0;
-
- if ((t = UNIT(s)->id))
- if ((r = service_load_sysv_name(s, t)) < 0)
- return r;
-
- if (UNIT(s)->load_state == UNIT_STUB)
- SET_FOREACH(t, UNIT(s)->names, i) {
- if (t == UNIT(s)->id)
- continue;
-
- if ((r = service_load_sysv_name(s, t)) < 0)
- return r;
-
- if (UNIT(s)->load_state != UNIT_STUB)
- break;
- }
-
- return 0;
-}
-#endif
-
-static int fsck_fix_order(Service *s) {
- Unit *other;
- int r;
-
- assert(s);
-
- if (s->fsck_passno <= 0)
- return 0;
-
- /* For each pair of services where both have an fsck priority
- * we order things based on it. */
-
- LIST_FOREACH(units_by_type, other, UNIT(s)->manager->units_by_type[UNIT_SERVICE]) {
- Service *t;
- UnitDependency d;
-
- t = SERVICE(other);
-
- if (s == t)
- continue;
-
- if (UNIT(t)->load_state != UNIT_LOADED)
- continue;
-
- if (t->fsck_passno <= 0)
- continue;
-
- if (t->fsck_passno < s->fsck_passno)
- d = UNIT_AFTER;
- else if (t->fsck_passno > s->fsck_passno)
- d = UNIT_BEFORE;
- else
- continue;
-
- if ((r = unit_add_dependency(UNIT(s), d, UNIT(t), true)) < 0)
- return r;
- }
-
- 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]) {
- log_error("%s lacks ExecStart setting. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
-
- if (s->type != SERVICE_ONESHOT &&
- s->exec_command[SERVICE_EXEC_START]->command_next) {
- log_error("%s has more than one ExecStart setting, which is only allowed for Type=oneshot services. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
-
- if (s->type == SERVICE_DBUS && !s->bus_name) {
- log_error("%s is of type D-Bus but no D-Bus service name has been specified. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
-
- if (s->bus_name && s->type != SERVICE_DBUS)
- log_warning("%s has a D-Bus service name specified, but is not of type dbus. Ignoring.", UNIT(s)->id);
-
- if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) {
- log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int service_add_default_dependencies(Service *s) {
- int r;
-
- assert(s);
-
- /* Add a number of automatic dependencies useful for the
- * majority of services. */
-
- /* First, pull in base system */
- if (UNIT(s)->manager->running_as == SYSTEMD_SYSTEM) {
-
- if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true)) < 0)
- return r;
-
- } else if (UNIT(s)->manager->running_as == SYSTEMD_USER) {
-
- if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SOCKETS_TARGET, NULL, true)) < 0)
- return r;
- }
-
- /* Second, activate normal shutdown */
- return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
-}
-
-static void service_fix_output(Service *s) {
- assert(s);
-
- /* If nothing has been explicitly configured, patch default
- * output in. If input is socket/tty we avoid this however,
- * since in that case we want output to default to the same
- * place as we read input from. */
-
- if (s->exec_context.std_error == EXEC_OUTPUT_INHERIT &&
- s->exec_context.std_output == EXEC_OUTPUT_INHERIT &&
- s->exec_context.std_input == EXEC_INPUT_NULL)
- s->exec_context.std_error = UNIT(s)->manager->default_std_error;
-
- if (s->exec_context.std_output == EXEC_OUTPUT_INHERIT &&
- s->exec_context.std_input == EXEC_INPUT_NULL)
- s->exec_context.std_output = UNIT(s)->manager->default_std_output;
-}
-
-static int service_load(Unit *u) {
- int r;
- Service *s = SERVICE(u);
-
- assert(s);
-
- /* Load a .service file */
- if ((r = unit_load_fragment(u)) < 0)
- return r;
-
-#ifdef HAVE_SYSV_COMPAT
- /* Load a classic init script as a fallback, if we couldn't find anything */
- if (u->load_state == UNIT_STUB)
- if ((r = service_load_sysv(s)) < 0)
- return r;
-#endif
-
- /* Still nothing found? Then let's give up */
- if (u->load_state == UNIT_STUB)
- return -ENOENT;
-
- /* We were able to load something, then let's add in the
- * dropin directories. */
- if ((r = unit_load_dropin(unit_follow_merge(u))) < 0)
- return r;
-
- /* This is a new unit? Then let's add in some extras */
- if (u->load_state == UNIT_LOADED) {
- if (s->type == _SERVICE_TYPE_INVALID)
- s->type = s->bus_name ? SERVICE_DBUS : SERVICE_SIMPLE;
-
- /* Oneshot services have disabled start timeout by default */
- if (s->type == SERVICE_ONESHOT && !s->start_timeout_defined)
- s->timeout_start_usec = 0;
-
- service_fix_output(s);
-
- if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0)
- return r;
-
- if ((r = unit_add_default_cgroups(u)) < 0)
- return r;
-
-#ifdef HAVE_SYSV_COMPAT
- if ((r = sysv_fix_order(s)) < 0)
- return r;
-#endif
-
- if ((r = fsck_fix_order(s)) < 0)
- return r;
-
- if (s->bus_name)
- if ((r = unit_watch_bus_name(u, s->bus_name)) < 0)
- return r;
-
- if (s->type == SERVICE_NOTIFY && s->notify_access == NOTIFY_NONE)
- s->notify_access = NOTIFY_MAIN;
-
- if (s->watchdog_usec > 0 && s->notify_access == NOTIFY_NONE)
- s->notify_access = NOTIFY_MAIN;
-
- if (s->type == SERVICE_DBUS || s->bus_name)
- if ((r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true)) < 0)
- return r;
-
- if (UNIT(s)->default_dependencies)
- if ((r = service_add_default_dependencies(s)) < 0)
- return r;
-
- r = unit_exec_context_defaults(u, &s->exec_context);
- 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;
- char *p2;
-
- assert(s);
-
- p2 = strappend(prefix, "\t");
- prefix2 = p2 ? p2 : prefix;
-
- 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",
- 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));
-
- if (s->control_pid > 0)
- fprintf(f,
- "%sControl PID: %lu\n",
- prefix, (unsigned long) s->control_pid);
-
- if (s->main_pid > 0)
- fprintf(f,
- "%sMain PID: %lu\n"
- "%sMain PID Known: %s\n"
- "%sMain PID Alien: %s\n",
- prefix, (unsigned long) 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);
- }
-
-#ifdef HAVE_SYSV_COMPAT
- if (s->is_sysv)
- fprintf(f,
- "%sSysV Init Script has LSB Header: %s\n"
- "%sSysVEnabled: %s\n",
- prefix, yes_no(s->sysv_has_lsb),
- prefix, yes_no(s->sysv_enabled));
-
- if (s->sysv_start_priority >= 0)
- fprintf(f,
- "%sSysVStartPriority: %i\n",
- prefix, s->sysv_start_priority);
-
- if (s->sysv_runlevels)
- fprintf(f, "%sSysVRunLevels: %s\n",
- prefix, s->sysv_runlevels);
-#endif
-
- if (s->fsck_passno > 0)
- fprintf(f,
- "%sFsckPassNo: %i\n",
- prefix, s->fsck_passno);
-
- if (s->status_text)
- fprintf(f, "%sStatus Text: %s\n",
- prefix, s->status_text);
-
- free(p2);
-}
-
-static int service_load_pid_file(Service *s, bool may_warn) {
- char *k;
- int r;
- pid_t pid;
-
- assert(s);
-
- if (!s->pid_file)
- return -ENOENT;
-
- if ((r = read_one_line_file(s->pid_file, &k)) < 0) {
- if (may_warn)
- log_info("PID file %s not readable (yet?) after %s.",
- s->pid_file, service_state_to_string(s->state));
- return r;
- }
-
- r = parse_pid(k, &pid);
- free(k);
-
- if (r < 0)
- return r;
-
- if (kill(pid, 0) < 0 && errno != EPERM) {
- if (may_warn)
- log_info("PID %lu read from file %s does not exist.",
- (unsigned long) pid, s->pid_file);
- return -ESRCH;
- }
-
- if (s->main_pid_known) {
- if (pid == s->main_pid)
- return 0;
-
- log_debug("Main PID changing: %lu -> %lu",
- (unsigned long) s->main_pid, (unsigned long) pid);
- service_unwatch_main_pid(s);
- s->main_pid_known = false;
- } else
- log_debug("Main PID loaded: %lu", (unsigned long) pid);
-
- if ((r = service_set_main_pid(s, pid)) < 0)
- return r;
-
- if ((r = unit_watch_pid(UNIT(s), pid)) < 0)
- /* FIXME: we need to do something here */
- return r;
-
- return 0;
-}
-
-static int service_search_main_pid(Service *s) {
- pid_t pid;
- int r;
-
- assert(s);
-
- /* If we know it anyway, don't ever fallback to unreliable
- * heuristics */
- if (s->main_pid_known)
- return 0;
-
- if (!s->guess_main_pid)
- return 0;
-
- assert(s->main_pid <= 0);
-
- if ((pid = cgroup_bonding_search_main_pid_list(UNIT(s)->cgroup_bondings)) <= 0)
- return -ENOENT;
-
- log_debug("Main PID guessed: %lu", (unsigned long) pid);
- if ((r = service_set_main_pid(s, pid)) < 0)
- return r;
-
- if ((r = unit_watch_pid(UNIT(s), pid)) < 0)
- /* FIXME: we need to do something here */
- return r;
-
- return 0;
-}
-
-static void service_notify_sockets_dead(Service *s, bool failed_permanent) {
- Iterator i;
- Unit *u;
-
- assert(s);
-
- /* Notifies all our sockets when we die */
-
- if (s->socket_fd >= 0)
- return;
-
- SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i)
- if (u->type == UNIT_SOCKET)
- socket_notify_service_dead(SOCKET(u), failed_permanent);
-
- return;
-}
-
-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 (state != SERVICE_START_PRE &&
- state != SERVICE_START &&
- state != SERVICE_START_POST &&
- state != SERVICE_RELOAD &&
- state != SERVICE_STOP &&
- state != SERVICE_STOP_SIGTERM &&
- state != SERVICE_STOP_SIGKILL &&
- state != SERVICE_STOP_POST &&
- state != SERVICE_FINAL_SIGTERM &&
- state != SERVICE_FINAL_SIGKILL &&
- state != SERVICE_AUTO_RESTART)
- unit_unwatch_timer(UNIT(s), &s->timer_watch);
-
- if (state != SERVICE_START &&
- state != SERVICE_START_POST &&
- state != SERVICE_RUNNING &&
- state != SERVICE_RELOAD &&
- state != SERVICE_STOP &&
- state != SERVICE_STOP_SIGTERM &&
- state != SERVICE_STOP_SIGKILL) {
- service_unwatch_main_pid(s);
- s->main_command = NULL;
- }
-
- if (state != SERVICE_START_PRE &&
- state != SERVICE_START &&
- state != SERVICE_START_POST &&
- state != SERVICE_RELOAD &&
- state != SERVICE_STOP &&
- state != SERVICE_STOP_SIGTERM &&
- state != SERVICE_STOP_SIGKILL &&
- state != SERVICE_STOP_POST &&
- state != SERVICE_FINAL_SIGTERM &&
- state != SERVICE_FINAL_SIGKILL) {
- service_unwatch_control_pid(s);
- s->control_command = NULL;
- s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
- }
-
- if (state == SERVICE_DEAD ||
- state == SERVICE_STOP ||
- state == SERVICE_STOP_SIGTERM ||
- state == SERVICE_STOP_SIGKILL ||
- state == SERVICE_STOP_POST ||
- state == SERVICE_FINAL_SIGTERM ||
- state == SERVICE_FINAL_SIGKILL ||
- state == SERVICE_FAILED ||
- state == SERVICE_AUTO_RESTART)
- service_notify_sockets_dead(s, false);
-
- if (state != SERVICE_START_PRE &&
- state != SERVICE_START &&
- state != SERVICE_START_POST &&
- state != SERVICE_RUNNING &&
- state != SERVICE_RELOAD &&
- state != SERVICE_STOP &&
- state != SERVICE_STOP_SIGTERM &&
- state != SERVICE_STOP_SIGKILL &&
- state != SERVICE_STOP_POST &&
- state != SERVICE_FINAL_SIGTERM &&
- state != SERVICE_FINAL_SIGKILL &&
- !(state == SERVICE_DEAD && UNIT(s)->job)) {
- service_close_socket_fd(s);
- service_connection_unref(s);
- }
-
- if (state == SERVICE_STOP)
- 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)
- cgroup_bonding_trim_list(UNIT(s)->cgroup_bondings, true);
-
- if (old_state != state)
- log_struct(LOG_DEBUG,
- "UNIT=%s", UNIT(s)->id,
- "MESSAGE=%s changed %s -> %s", UNIT(s)->id,
- service_state_to_string(old_state),
- service_state_to_string(state),
- NULL);
-
- unit_notify(UNIT(s), table[old_state], table[state], s->reload_result == SERVICE_SUCCESS);
- s->reload_result = SERVICE_SUCCESS;
-}
-
-static int service_coldplug(Unit *u) {
- Service *s = SERVICE(u);
- int r;
-
- assert(s);
- assert(s->state == SERVICE_DEAD);
-
- if (s->deserialized_state != s->state) {
-
- if (s->deserialized_state == SERVICE_START_PRE ||
- s->deserialized_state == SERVICE_START ||
- s->deserialized_state == SERVICE_START_POST ||
- s->deserialized_state == SERVICE_RELOAD ||
- s->deserialized_state == SERVICE_STOP ||
- s->deserialized_state == SERVICE_STOP_SIGTERM ||
- s->deserialized_state == SERVICE_STOP_SIGKILL ||
- s->deserialized_state == SERVICE_STOP_POST ||
- s->deserialized_state == SERVICE_FINAL_SIGTERM ||
- s->deserialized_state == SERVICE_FINAL_SIGKILL ||
- s->deserialized_state == SERVICE_AUTO_RESTART) {
- if (s->deserialized_state == SERVICE_AUTO_RESTART || s->timeout_start_usec > 0) {
- usec_t k;
-
- k = s->deserialized_state == SERVICE_AUTO_RESTART ? s->restart_usec : s->timeout_start_usec;
-
- if ((r = unit_watch_timer(UNIT(s), k, &s->timer_watch)) < 0)
- return r;
- }
- }
-
- if ((s->deserialized_state == SERVICE_START &&
- (s->type == SERVICE_FORKING ||
- s->type == SERVICE_DBUS ||
- s->type == SERVICE_ONESHOT ||
- s->type == SERVICE_NOTIFY)) ||
- s->deserialized_state == SERVICE_START_POST ||
- s->deserialized_state == SERVICE_RUNNING ||
- s->deserialized_state == SERVICE_RELOAD ||
- s->deserialized_state == SERVICE_STOP ||
- s->deserialized_state == SERVICE_STOP_SIGTERM ||
- s->deserialized_state == SERVICE_STOP_SIGKILL)
- if (s->main_pid > 0)
- if ((r = unit_watch_pid(UNIT(s), s->main_pid)) < 0)
- return r;
-
- if (s->deserialized_state == SERVICE_START_PRE ||
- s->deserialized_state == SERVICE_START ||
- s->deserialized_state == SERVICE_START_POST ||
- s->deserialized_state == SERVICE_RELOAD ||
- s->deserialized_state == SERVICE_STOP ||
- s->deserialized_state == SERVICE_STOP_SIGTERM ||
- s->deserialized_state == SERVICE_STOP_SIGKILL ||
- s->deserialized_state == SERVICE_STOP_POST ||
- s->deserialized_state == SERVICE_FINAL_SIGTERM ||
- s->deserialized_state == SERVICE_FINAL_SIGKILL)
- if (s->control_pid > 0)
- if ((r = unit_watch_pid(UNIT(s), s->control_pid)) < 0)
- return r;
-
- if (s->deserialized_state == SERVICE_START_POST ||
- s->deserialized_state == SERVICE_RUNNING)
- service_handle_watchdog(s);
-
- service_set_state(s, s->deserialized_state);
- }
- return 0;
-}
-
-static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
- Iterator i;
- int r;
- int *rfds = NULL;
- unsigned rn_fds = 0;
- Unit *u;
-
- assert(s);
- assert(fds);
- assert(n_fds);
-
- if (s->socket_fd >= 0)
- return 0;
-
- SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) {
- int *cfds;
- unsigned cn_fds;
- Socket *sock;
-
- if (u->type != UNIT_SOCKET)
- continue;
-
- sock = SOCKET(u);
-
- if ((r = socket_collect_fds(sock, &cfds, &cn_fds)) < 0)
- goto fail;
-
- if (!cfds)
- continue;
-
- if (!rfds) {
- rfds = cfds;
- rn_fds = cn_fds;
- } else {
- int *t;
-
- if (!(t = new(int, rn_fds+cn_fds))) {
- free(cfds);
- r = -ENOMEM;
- goto fail;
- }
-
- memcpy(t, rfds, rn_fds * sizeof(int));
- memcpy(t+rn_fds, cfds, cn_fds * sizeof(int));
- free(rfds);
- free(cfds);
-
- rfds = t;
- rn_fds = rn_fds+cn_fds;
- }
- }
-
- *fds = rfds;
- *n_fds = rn_fds;
-
- return 0;
-
-fail:
- free(rfds);
-
- return r;
-}
-
-static int service_spawn(
- Service *s,
- ExecCommand *c,
- bool timeout,
- bool pass_fds,
- bool apply_permissions,
- bool apply_chroot,
- bool apply_tty_stdin,
- bool set_notify_socket,
- bool is_control,
- pid_t *_pid) {
-
- pid_t pid;
- int r;
- int *fds = NULL, *fdsbuf = NULL;
- unsigned n_fds = 0, n_env = 0;
- char **argv = NULL, **final_env = NULL, **our_env = NULL;
-
- assert(s);
- assert(c);
- assert(_pid);
-
- if (pass_fds ||
- s->exec_context.std_input == EXEC_INPUT_SOCKET ||
- s->exec_context.std_output == EXEC_OUTPUT_SOCKET ||
- s->exec_context.std_error == EXEC_OUTPUT_SOCKET) {
-
- if (s->socket_fd >= 0) {
- fds = &s->socket_fd;
- n_fds = 1;
- } else {
- if ((r = service_collect_fds(s, &fdsbuf, &n_fds)) < 0)
- goto fail;
-
- fds = fdsbuf;
- }
- }
-
- if (timeout && s->timeout_start_usec) {
- r = unit_watch_timer(UNIT(s), s->timeout_start_usec, &s->timer_watch);
- if (r < 0)
- goto fail;
- } else
- unit_unwatch_timer(UNIT(s), &s->timer_watch);
-
- if (!(argv = unit_full_printf_strv(UNIT(s), c->argv))) {
- r = -ENOMEM;
- goto fail;
- }
-
- our_env = new0(char*, 5);
- if (!our_env) {
- r = -ENOMEM;
- goto fail;
- }
-
- if (set_notify_socket)
- if (asprintf(our_env + n_env++, "NOTIFY_SOCKET=%s", UNIT(s)->manager->notify_socket) < 0) {
- r = -ENOMEM;
- goto fail;
- }
-
- if (s->main_pid > 0)
- if (asprintf(our_env + n_env++, "MAINPID=%lu", (unsigned long) s->main_pid) < 0) {
- r = -ENOMEM;
- goto fail;
- }
-
- if (s->watchdog_usec > 0)
- if (asprintf(our_env + n_env++, "WATCHDOG_USEC=%llu", (unsigned long long) s->watchdog_usec) < 0) {
- r = -ENOMEM;
- goto fail;
- }
-
- if (s->meta.manager->running_as != SYSTEMD_SYSTEM)
- if (asprintf(our_env + n_env++, "MANAGERPID=%lu", (unsigned long) getpid()) < 0) {
- r = -ENOMEM;
- goto fail;
- }
-
- final_env = strv_env_merge(2, UNIT(s)->manager->environment, our_env, NULL);
- if (!final_env) {
- r = -ENOMEM;
- goto fail;
- }
-
- r = exec_spawn(c,
- argv,
- &s->exec_context,
- fds, n_fds,
- final_env,
- apply_permissions,
- apply_chroot,
- apply_tty_stdin,
- UNIT(s)->manager->confirm_spawn,
- UNIT(s)->cgroup_bondings,
- UNIT(s)->cgroup_attributes,
- is_control ? "control" : NULL,
- UNIT(s)->id,
- s->type == SERVICE_IDLE ? UNIT(s)->manager->idle_pipe : NULL,
- &pid);
-
- if (r < 0)
- goto fail;
-
- if ((r = unit_watch_pid(UNIT(s), pid)) < 0)
- /* FIXME: we need to do something here */
- goto fail;
-
- free(fdsbuf);
- strv_free(argv);
- strv_free(our_env);
- strv_free(final_env);
-
- *_pid = pid;
-
- return 0;
-
-fail:
- free(fdsbuf);
- strv_free(argv);
- strv_free(our_env);
- strv_free(final_env);
-
- if (timeout)
- unit_unwatch_timer(UNIT(s), &s->timer_watch);
-
- return r;
-}
-
-static int main_pid_good(Service *s) {
- assert(s);
-
- /* Returns 0 if the pid is dead, 1 if it is good, -1 if we
- * don't know */
-
- /* If we know the pid file, then lets just check if it is
- * still valid */
- if (s->main_pid_known) {
-
- /* If it's an alien child let's check if it is still
- * alive ... */
- if (s->main_pid_alien)
- return kill(s->main_pid, 0) >= 0 || errno != ESRCH;
-
- /* .. 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;
-}
-
-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 ((r = cgroup_bonding_is_empty_list(UNIT(s)->cgroup_bondings)) < 0)
- return r;
-
- return !r;
-}
-
-static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart) {
- int r;
- assert(s);
-
- if (f != SERVICE_SUCCESS)
- s->result = f;
-
- service_set_state(s, s->result != SERVICE_SUCCESS ? SERVICE_FAILED : SERVICE_DEAD);
-
- if (allow_restart &&
- !s->forbid_restart &&
- (s->restart == SERVICE_RESTART_ALWAYS ||
- (s->restart == SERVICE_RESTART_ON_SUCCESS && s->result == SERVICE_SUCCESS) ||
- (s->restart == SERVICE_RESTART_ON_FAILURE && s->result != SERVICE_SUCCESS) ||
- (s->restart == SERVICE_RESTART_ON_ABORT && (s->result == SERVICE_FAILURE_SIGNAL ||
- s->result == SERVICE_FAILURE_CORE_DUMP))) &&
- (s->result != SERVICE_FAILURE_EXIT_CODE ||
- !set_contains(s->restart_ignore_status.code, INT_TO_PTR(s->main_exec_status.status))) &&
- (s->result != SERVICE_FAILURE_SIGNAL ||
- !set_contains(s->restart_ignore_status.signal, INT_TO_PTR(s->main_exec_status.status)))
- ) {
-
- r = unit_watch_timer(UNIT(s), s->restart_usec, &s->timer_watch);
- if (r < 0)
- goto fail;
-
- service_set_state(s, SERVICE_AUTO_RESTART);
- }
-
- s->forbid_restart = false;
-
- return;
-
-fail:
- log_warning("%s failed to run install restart timer: %s", UNIT(s)->id, strerror(-r));
- service_enter_dead(s, SERVICE_FAILURE_RESOURCES, false);
-}
-
-static void service_enter_signal(Service *s, ServiceState state, ServiceResult f);
-
-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);
-
- if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP_POST])) {
- s->control_command_id = SERVICE_EXEC_STOP_POST;
-
- r = service_spawn(s,
- s->control_command,
- true,
- false,
- !s->permissions_start_only,
- !s->root_directory_start_only,
- true,
- false,
- 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_warning("%s failed to run 'stop-post' task: %s", UNIT(s)->id, strerror(-r));
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
-}
-
-static void service_enter_signal(Service *s, ServiceState state, ServiceResult f) {
- int r;
- Set *pid_set = NULL;
- bool wait_for_exit = false;
-
- assert(s);
-
- if (f != SERVICE_SUCCESS)
- s->result = f;
-
- if (s->kill_context.kill_mode != KILL_NONE) {
- int sig = (state == SERVICE_STOP_SIGTERM || state == SERVICE_FINAL_SIGTERM) ? s->kill_context.kill_signal : SIGKILL;
-
- if (s->main_pid > 0) {
- if (kill_and_sigcont(s->main_pid, sig) < 0 && errno != ESRCH)
- log_warning("Failed to kill main process %li: %m", (long) s->main_pid);
- else
- wait_for_exit = !s->main_pid_alien;
- }
-
- if (s->control_pid > 0) {
- if (kill_and_sigcont(s->control_pid, sig) < 0 && errno != ESRCH)
- log_warning("Failed to kill control process %li: %m", (long) s->control_pid);
- else
- wait_for_exit = true;
- }
-
- if (s->kill_context.kill_mode == KILL_CONTROL_GROUP) {
-
- pid_set = set_new(trivial_hash_func, trivial_compare_func);
- if (!pid_set) {
- r = -ENOMEM;
- goto fail;
- }
-
- /* Exclude the main/control pids from being killed via the cgroup */
- if (s->main_pid > 0)
- if ((r = set_put(pid_set, LONG_TO_PTR(s->main_pid))) < 0)
- goto fail;
-
- if (s->control_pid > 0)
- if ((r = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0)
- goto fail;
-
- r = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, sig, true, false, pid_set, NULL);
- if (r < 0) {
- if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
- log_warning("Failed to kill control group: %s", strerror(-r));
- } else if (r > 0)
- wait_for_exit = true;
-
- set_free(pid_set);
- pid_set = NULL;
- }
- }
-
- if (wait_for_exit) {
- if (s->timeout_stop_usec > 0) {
- r = unit_watch_timer(UNIT(s), s->timeout_stop_usec, &s->timer_watch);
- if (r < 0)
- goto fail;
- }
-
- service_set_state(s, state);
- } else if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGKILL)
- service_enter_stop_post(s, SERVICE_SUCCESS);
- else
- service_enter_dead(s, SERVICE_SUCCESS, true);
-
- return;
-
-fail:
- log_warning("%s failed to kill processes: %s", UNIT(s)->id, strerror(-r));
-
- if (state == SERVICE_STOP_SIGTERM || state == SERVICE_STOP_SIGKILL)
- service_enter_stop_post(s, SERVICE_FAILURE_RESOURCES);
- else
- service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
-
- if (pid_set)
- set_free(pid_set);
-}
-
-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);
-
- if ((s->control_command = s->exec_command[SERVICE_EXEC_STOP])) {
- s->control_command_id = SERVICE_EXEC_STOP;
-
- r = service_spawn(s,
- s->control_command,
- true,
- false,
- !s->permissions_start_only,
- !s->root_directory_start_only,
- false,
- 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_warning("%s failed to run 'stop' task: %s", UNIT(s)->id, strerror(-r));
- service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
-}
-
-static void service_enter_running(Service *s, ServiceResult f) {
- int main_pid_ok, cgroup_ok;
- assert(s);
-
- if (f != SERVICE_SUCCESS)
- s->result = f;
-
- main_pid_ok = main_pid_good(s);
- cgroup_ok = cgroup_good(s);
-
- if ((main_pid_ok > 0 || (main_pid_ok < 0 && cgroup_ok != 0)) &&
- (s->bus_name_good || s->type != SERVICE_DBUS))
- service_set_state(s, SERVICE_RUNNING);
- else if (s->remain_after_exit)
- service_set_state(s, SERVICE_EXITED);
- else
- service_enter_stop(s, SERVICE_SUCCESS);
-}
-
-static void service_enter_start_post(Service *s) {
- int r;
- assert(s);
-
- service_unwatch_control_pid(s);
-
- if (s->watchdog_usec > 0)
- service_reset_watchdog(s);
-
- if ((s->control_command = s->exec_command[SERVICE_EXEC_START_POST])) {
- s->control_command_id = SERVICE_EXEC_START_POST;
-
- r = service_spawn(s,
- s->control_command,
- true,
- false,
- !s->permissions_start_only,
- !s->root_directory_start_only,
- false,
- 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_warning("%s failed to run 'start-post' task: %s", UNIT(s)->id, strerror(-r));
- service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
-}
-
-static void service_enter_start(Service *s) {
- pid_t pid;
- int r;
- ExecCommand *c;
-
- assert(s);
-
- assert(s->exec_command[SERVICE_EXEC_START]);
- assert(!s->exec_command[SERVICE_EXEC_START]->command_next || s->type == SERVICE_ONESHOT);
-
- if (s->type == SERVICE_FORKING)
- service_unwatch_control_pid(s);
- else
- 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. */
- cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, SIGKILL, true, true, NULL, "control");
-
- 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];
- }
-
- r = service_spawn(s,
- c,
- s->type == SERVICE_FORKING || s->type == SERVICE_DBUS || s->type == SERVICE_NOTIFY || s->type == SERVICE_ONESHOT,
- true,
- true,
- true,
- true,
- s->notify_access != NOTIFY_NONE,
- false,
- &pid);
- if (r < 0)
- goto fail;
-
- if (s->type == SERVICE_SIMPLE || s->type == SERVICE_IDLE) {
- /* For simple services we immediately start
- * the START_POST binaries. */
-
- service_set_main_pid(s, pid);
- service_enter_start_post(s);
-
- } else if (s->type == SERVICE_FORKING) {
-
- /* For forking services we wait until the start
- * process exited. */
-
- s->control_pid = pid;
- service_set_state(s, SERVICE_START);
-
- } else if (s->type == SERVICE_ONESHOT ||
- s->type == SERVICE_DBUS ||
- s->type == SERVICE_NOTIFY) {
-
- /* For oneshot services we wait until the start
- * process exited, too, but it is our main process. */
-
- /* For D-Bus services we know the main pid right away,
- * but wait for the bus name to appear on the
- * bus. Notify services are similar. */
-
- service_set_main_pid(s, pid);
- service_set_state(s, SERVICE_START);
- } else
- assert_not_reached("Unknown service type");
-
- return;
-
-fail:
- log_warning("%s failed to run 'start' task: %s", UNIT(s)->id, strerror(-r));
- 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);
-
- if ((s->control_command = s->exec_command[SERVICE_EXEC_START_PRE])) {
-
- /* Before we start anything, let's clear up what might
- * be left from previous runs. */
- cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, SIGKILL, true, true, NULL, "control");
-
- s->control_command_id = SERVICE_EXEC_START_PRE;
-
- r = service_spawn(s,
- s->control_command,
- true,
- false,
- !s->permissions_start_only,
- !s->root_directory_start_only,
- true,
- false,
- true,
- &s->control_pid);
- if (r < 0)
- goto fail;
-
- service_set_state(s, SERVICE_START_PRE);
- } else
- service_enter_start(s);
-
- return;
-
-fail:
- log_warning("%s failed to run 'start-pre' task: %s", UNIT(s)->id, strerror(-r));
- service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
-}
-
-static void service_enter_restart(Service *s) {
- int r;
- DBusError error;
-
- assert(s);
- dbus_error_init(&error);
-
- if (UNIT(s)->job && UNIT(s)->job->type == JOB_STOP) {
- /* Don't restart things if we are going down anyway */
- log_info("Stop job pending for unit, delaying automatic restart.");
-
- r = unit_watch_timer(UNIT(s), s->restart_usec, &s->timer_watch);
- if (r < 0)
- goto fail;
-
- return;
- }
-
- /* Any units that are bound to this service must also be
- * restarted. We use JOB_RESTART (instead of the more obvious
- * JOB_START) here so that those dependency jobs will be added
- * as well. */
- r = manager_add_job(UNIT(s)->manager, JOB_RESTART, UNIT(s), JOB_FAIL, false, &error, NULL);
- if (r < 0)
- goto fail;
-
- /* Note that we stay in the SERVICE_AUTO_RESTART state here,
- * it will be canceled as part of the service_stop() call that
- * is executed as part of JOB_RESTART. */
-
- log_debug("%s scheduled restart job.", UNIT(s)->id);
- return;
-
-fail:
- log_warning("%s failed to schedule restart job: %s", UNIT(s)->id, bus_error(&error, -r));
- service_enter_dead(s, SERVICE_FAILURE_RESOURCES, false);
-
- dbus_error_free(&error);
-}
-
-static void service_enter_reload(Service *s) {
- int r;
-
- assert(s);
-
- service_unwatch_control_pid(s);
-
- if ((s->control_command = s->exec_command[SERVICE_EXEC_RELOAD])) {
- s->control_command_id = SERVICE_EXEC_RELOAD;
-
- r = service_spawn(s,
- s->control_command,
- true,
- false,
- !s->permissions_start_only,
- !s->root_directory_start_only,
- false,
- 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_warning("%s failed to run 'reload' task: %s", UNIT(s)->id, strerror(-r));
- s->reload_result = SERVICE_FAILURE_RESOURCES;
- service_enter_running(s, SERVICE_SUCCESS);
-}
-
-static void service_run_next_control(Service *s) {
- int r;
-
- assert(s);
- assert(s->control_command);
- assert(s->control_command->command_next);
-
- assert(s->control_command_id != SERVICE_EXEC_START);
-
- s->control_command = s->control_command->command_next;
- service_unwatch_control_pid(s);
-
- r = service_spawn(s,
- s->control_command,
- true,
- 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,
- false,
- true,
- &s->control_pid);
- if (r < 0)
- goto fail;
-
- return;
-
-fail:
- log_warning("%s failed to run next control task: %s", UNIT(s)->id, strerror(-r));
-
- 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,
- true,
- true,
- true,
- true,
- true,
- s->notify_access != NOTIFY_NONE,
- false,
- &pid);
- if (r < 0)
- goto fail;
-
- service_set_main_pid(s, pid);
-
- return;
-
-fail:
- log_warning("%s failed to run next main task: %s", UNIT(s)->id, strerror(-r));
- service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
-}
-
-static int service_start_limit_test(Service *s) {
- assert(s);
-
- if (ratelimit_test(&s->start_limit))
- return 0;
-
- switch (s->start_limit_action) {
-
- case SERVICE_START_LIMIT_NONE:
- log_warning("%s start request repeated too quickly, refusing to start.", UNIT(s)->id);
- break;
-
- case SERVICE_START_LIMIT_REBOOT: {
- DBusError error;
- int r;
-
- dbus_error_init(&error);
-
- log_warning("%s start request repeated too quickly, rebooting.", UNIT(s)->id);
-
- r = manager_add_job_by_name(UNIT(s)->manager, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE, true, &error, NULL);
- if (r < 0) {
- log_error("Failed to reboot: %s.", bus_error(&error, r));
- dbus_error_free(&error);
- }
-
- break;
- }
-
- case SERVICE_START_LIMIT_REBOOT_FORCE:
- log_warning("%s start request repeated too quickly, forcibly rebooting.", UNIT(s)->id);
- UNIT(s)->manager->exit_code = MANAGER_REBOOT;
- break;
-
- case SERVICE_START_LIMIT_REBOOT_IMMEDIATE:
- log_warning("%s start request repeated too quickly, rebooting immediately.", UNIT(s)->id);
- reboot(RB_AUTOBOOT);
- break;
-
- default:
- log_error("start limit action=%i", s->start_limit_action);
- assert_not_reached("Unknown StartLimitAction.");
- }
-
- return -ECANCELED;
-}
-
-static int service_start(Unit *u) {
- Service *s = SERVICE(u);
- int r;
-
- assert(s);
-
- /* We cannot fulfill this request right now, try again later
- * please! */
- if (s->state == SERVICE_STOP ||
- s->state == SERVICE_STOP_SIGTERM ||
- s->state == SERVICE_STOP_SIGKILL ||
- s->state == SERVICE_STOP_POST ||
- s->state == SERVICE_FINAL_SIGTERM ||
- s->state == SERVICE_FINAL_SIGKILL)
- return -EAGAIN;
-
- /* Already on it! */
- if (s->state == SERVICE_START_PRE ||
- s->state == SERVICE_START ||
- s->state == SERVICE_START_POST)
- return 0;
-
- /* A service that will be restarted must be stopped first to
- * trigger BindsTo and/or OnFailure dependencies. If a user
- * does not want to wait for the holdoff time to elapse, the
- * service should be manually restarted, not started. We
- * simply return EAGAIN here, so that any start jobs stay
- * queued, and assume that the auto restart timer will
- * eventually trigger the restart. */
- if (s->state == SERVICE_AUTO_RESTART)
- return -EAGAIN;
-
- assert(s->state == SERVICE_DEAD || s->state == SERVICE_FAILED);
-
- /* Make sure we don't enter a busy loop of some kind. */
- r = service_start_limit_test(s);
- if (r < 0) {
- service_enter_dead(s, SERVICE_FAILURE_START_LIMIT, false);
- return r;
- }
-
- s->result = SERVICE_SUCCESS;
- s->reload_result = SERVICE_SUCCESS;
- s->main_pid_known = false;
- s->main_pid_alien = false;
- s->forbid_restart = false;
-
- service_enter_start_pre(s);
- return 0;
-}
-
-static int service_stop(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
-
- /* Don't create restart jobs from here. */
- s->forbid_restart = true;
-
- /* Already on it */
- if (s->state == SERVICE_STOP ||
- s->state == SERVICE_STOP_SIGTERM ||
- s->state == SERVICE_STOP_SIGKILL ||
- s->state == SERVICE_STOP_POST ||
- s->state == SERVICE_FINAL_SIGTERM ||
- s->state == SERVICE_FINAL_SIGKILL)
- return 0;
-
- /* A restart will be scheduled or is in progress. */
- if (s->state == SERVICE_AUTO_RESTART) {
- service_set_state(s, SERVICE_DEAD);
- return 0;
- }
-
- /* If there's already something running we go directly into
- * kill mode. */
- if (s->state == SERVICE_START_PRE ||
- s->state == SERVICE_START ||
- s->state == SERVICE_START_POST ||
- s->state == SERVICE_RELOAD) {
- service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_SUCCESS);
- return 0;
- }
-
- assert(s->state == SERVICE_RUNNING ||
- s->state == SERVICE_EXITED);
-
- service_enter_stop(s, SERVICE_SUCCESS);
- return 0;
-}
-
-static int service_reload(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
-
- assert(s->state == SERVICE_RUNNING || s->state == SERVICE_EXITED);
-
- service_enter_reload(s);
- return 0;
-}
-
-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);
-
- 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", "%lu", (unsigned long) s->control_pid);
-
- if (s->main_pid_known && s->main_pid > 0)
- unit_serialize_item_format(u, f, "main-pid", "%lu", (unsigned long) s->main_pid);
-
- unit_serialize_item(u, f, "main-pid-known", yes_no(s->main_pid_known));
-
- if (s->status_text)
- unit_serialize_item(u, f, "status-text", s->status_text);
-
- /* FIXME: There's a minor uncleanliness here: if there are
- * multiple commands attached here, we will start from the
- * first one again */
- if (s->control_command_id >= 0)
- unit_serialize_item(u, f, "control-command", service_exec_command_to_string(s->control_command_id));
-
- if (s->socket_fd >= 0) {
- int copy;
-
- if ((copy = fdset_put_dup(fds, s->socket_fd)) < 0)
- return copy;
-
- unit_serialize_item_format(u, f, "socket-fd", "%i", copy);
- }
-
- if (s->main_exec_status.pid > 0) {
- unit_serialize_item_format(u, f, "main-exec-status-pid", "%lu", (unsigned long) 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);
-
- return 0;
-}
-
-static int service_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Service *s = SERVICE(u);
-
- assert(u);
- assert(key);
- assert(value);
- assert(fds);
-
- if (streq(key, "state")) {
- ServiceState state;
-
- if ((state = service_state_from_string(value)) < 0)
- log_debug("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_debug("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_debug("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_debug("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_debug("Failed to parse main-pid value %s", value);
- else
- service_set_main_pid(s, (pid_t) pid);
- } else if (streq(key, "main-pid-known")) {
- int b;
-
- if ((b = parse_boolean(value)) < 0)
- log_debug("Failed to parse main-pid-known value %s", value);
- else
- s->main_pid_known = b;
- } else if (streq(key, "status-text")) {
- char *t;
-
- if ((t = strdup(value))) {
- free(s->status_text);
- s->status_text = t;
- }
-
- } else if (streq(key, "control-command")) {
- ServiceExecCommand id;
-
- if ((id = service_exec_command_from_string(value)) < 0)
- log_debug("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_debug("Failed to parse socket-fd value %s", value);
- else {
-
- if (s->socket_fd >= 0)
- close_nointr_nofail(s->socket_fd);
- s->socket_fd = fdset_remove(fds, fd);
- }
- } else if (streq(key, "main-exec-status-pid")) {
- pid_t pid;
-
- if (parse_pid(value, &pid) < 0)
- log_debug("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_debug("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_debug("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
- log_debug("Unknown serialization key '%s'", key);
-
- return 0;
-}
-
-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;
-
-#ifdef HAVE_SYSV_COMPAT
- if (s->is_sysv)
- return true;
-#endif
-
- return false;
-}
-
-static bool service_check_snapshot(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
-
- return !s->got_socket_fd;
-}
-
-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_debug("Setting watch for %s's PID file %s", UNIT(s)->id, s->pid_file_pathspec->path);
- r = path_spec_watch(s->pid_file_pathspec, UNIT(s));
- if (r < 0)
- goto fail;
-
- /* the pidfile might have appeared just before we set the watch */
- service_retry_pid_file(s);
-
- return 0;
-fail:
- log_error("Failed to set a watch for %s's PID file %s: %s",
- UNIT(s)->id, s->pid_file_pathspec->path, strerror(-r));
- 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->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 void service_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
- Service *s = SERVICE(u);
-
- 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_debug("inotify event for %s", u->id);
-
- if (path_spec_fd_event(s->pid_file_pathspec, events) < 0)
- goto fail;
-
- if (service_retry_pid_file(s) == 0)
- return;
-
- if (service_watch_pid_file(s) < 0)
- goto fail;
-
- return;
-fail:
- service_unwatch_pid_file(s);
- service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
-}
-
-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 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 */
- if (s->main_command) {
- s->main_command->exec_status = s->main_exec_status;
-
- if (s->main_command->ignore)
- f = SERVICE_SUCCESS;
- }
-
- log_struct(f == SERVICE_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
- "MESSAGE=%s: main process exited, code=%s, status=%i/%s",
- u->id, sigchld_code_to_string(code), status,
- strna(code == CLD_EXITED
- ? exit_status_to_string(status, EXIT_STATUS_FULL)
- : signal_to_string(status)),
- "UNIT=%s", u->id,
- "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_debug("%s running next main command for state %s", u->id, service_state_to_string(s->state));
- service_run_next_main(s);
-
- } else {
-
- /* The service exited, so the service is officially
- * gone. */
- s->main_command = NULL;
-
- switch (s->state) {
-
- case SERVICE_START_POST:
- case SERVICE_RELOAD:
- case SERVICE_STOP:
- /* Need to wait until the operation is
- * done */
- break;
-
- case SERVICE_START:
- if (s->type == SERVICE_ONESHOT) {
- /* This was our main goal, so let's go on */
- if (f == SERVICE_SUCCESS)
- service_enter_start_post(s);
- else
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
- break;
- }
-
- /* Fall through */
-
- case SERVICE_RUNNING:
- service_enter_running(s, f);
- break;
-
- case SERVICE_STOP_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;
-
- 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_full(f == SERVICE_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
- "%s: control process exited, code=%s status=%i", u->id, sigchld_code_to_string(code), status);
-
- if (f != SERVICE_SUCCESS)
- s->result = f;
-
- /* Immediately get rid of the cgroup, so that the
- * kernel doesn't delay the cgroup empty messages for
- * the service cgroup any longer than necessary */
- cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, SIGKILL, true, true, NULL, "control");
-
- if (s->control_command &&
- s->control_command->command_next &&
- f == SERVICE_SUCCESS) {
-
- /* There is another command to *
- * execute, so let's do that. */
-
- log_debug("%s running next control command for state %s", u->id, service_state_to_string(s->state));
- service_run_next_control(s);
-
- } else {
- /* No further commands for this step, so let's
- * figure out what to do next */
-
- s->control_command = NULL;
- s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
-
- log_debug("%s got final SIGCHLD for state %s", u->id, service_state_to_string(s->state));
-
- switch (s->state) {
-
- case SERVICE_START_PRE:
- if (f == SERVICE_SUCCESS)
- service_enter_start(s);
- else
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
- break;
-
- case SERVICE_START:
- if (s->type != SERVICE_FORKING)
- /* Maybe spurious event due to a reload that changed the type? */
- break;
-
- if (f != SERVICE_SUCCESS) {
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, f);
- break;
- }
-
- if (s->pid_file) {
- bool has_start_post;
- int r;
-
- /* Let's try to load the pid file here if we can.
- * The PID file might actually be created by a START_POST
- * script. In that case don't worry if the loading fails. */
-
- has_start_post = !!s->exec_command[SERVICE_EXEC_START_POST];
- r = service_load_pid_file(s, !has_start_post);
- if (!has_start_post && r < 0) {
- r = service_demand_pid_file(s);
- if (r < 0 || !cgroup_good(s))
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
- break;
- }
- } else
- service_search_main_pid(s);
-
- service_enter_start_post(s);
- break;
-
- case SERVICE_START_POST:
- if (f != SERVICE_SUCCESS) {
- service_enter_stop(s, f);
- break;
- }
-
- if (s->pid_file) {
- int r;
-
- r = service_load_pid_file(s, true);
- if (r < 0) {
- r = service_demand_pid_file(s);
- if (r < 0 || !cgroup_good(s))
- service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
- break;
- }
- } else
- service_search_main_pid(s);
-
- service_enter_running(s, SERVICE_SUCCESS);
- break;
-
- case SERVICE_RELOAD:
- if (f == SERVICE_SUCCESS) {
- service_load_pid_file(s, true);
- service_search_main_pid(s);
- }
-
- s->reload_result = f;
- service_enter_running(s, SERVICE_SUCCESS);
- break;
-
- case SERVICE_STOP:
- service_enter_signal(s, SERVICE_STOP_SIGTERM, f);
- break;
-
- case SERVICE_STOP_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:
- 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);
-}
-
-static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) {
- Service *s = SERVICE(u);
-
- assert(s);
- assert(elapsed == 1);
-
- if (w == &s->watchdog_watch) {
- service_handle_watchdog(s);
- return;
- }
-
- assert(w == &s->timer_watch);
-
- switch (s->state) {
-
- case SERVICE_START_PRE:
- case SERVICE_START:
- log_warning("%s operation timed out. Terminating.", u->id);
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT);
- break;
-
- case SERVICE_START_POST:
- log_warning("%s operation timed out. Stopping.", u->id);
- service_enter_stop(s, SERVICE_FAILURE_TIMEOUT);
- break;
-
- case SERVICE_RELOAD:
- log_warning("%s operation timed out. Stopping.", u->id);
- s->reload_result = SERVICE_FAILURE_TIMEOUT;
- service_enter_running(s, SERVICE_SUCCESS);
- break;
-
- case SERVICE_STOP:
- log_warning("%s stopping timed out. Terminating.", u->id);
- service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_TIMEOUT);
- break;
-
- case SERVICE_STOP_SIGTERM:
- if (s->kill_context.send_sigkill) {
- log_warning("%s stopping timed out. Killing.", u->id);
- service_enter_signal(s, SERVICE_STOP_SIGKILL, SERVICE_FAILURE_TIMEOUT);
- } else {
- log_warning("%s stopping timed out. Skipping SIGKILL.", u->id);
- service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT);
- }
-
- break;
-
- case SERVICE_STOP_SIGKILL:
- /* Uh, we sent a SIGKILL and it is still not gone?
- * Must be something we cannot kill, so let's just be
- * weirded out and continue */
-
- log_warning("%s still around after SIGKILL. Ignoring.", u->id);
- service_enter_stop_post(s, SERVICE_FAILURE_TIMEOUT);
- break;
-
- case SERVICE_STOP_POST:
- log_warning("%s stopping timed out (2). Terminating.", u->id);
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_TIMEOUT);
- break;
-
- case SERVICE_FINAL_SIGTERM:
- if (s->kill_context.send_sigkill) {
- log_warning("%s stopping timed out (2). Killing.", u->id);
- service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_FAILURE_TIMEOUT);
- } else {
- log_warning("%s stopping timed out (2). Skipping SIGKILL. Entering failed mode.", u->id);
- service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, false);
- }
-
- break;
-
- case SERVICE_FINAL_SIGKILL:
- log_warning("%s still around after SIGKILL (2). Entering failed mode.", u->id);
- service_enter_dead(s, SERVICE_FAILURE_TIMEOUT, true);
- break;
-
- case SERVICE_AUTO_RESTART:
- log_info("%s holdoff time over, scheduling restart.", u->id);
- service_enter_restart(s);
- break;
-
- default:
- assert_not_reached("Timeout at wrong time.");
- }
-}
-
-static void service_cgroup_notify_event(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(u);
-
- log_debug("%s: cgroup is empty", u->id);
-
- switch (s->state) {
-
- /* Waiting for SIGCHLD is usually more interesting,
- * because it includes return codes/signals. Which is
- * why we ignore the cgroup events for most cases,
- * except when we don't know pid which to expect the
- * SIGCHLD for. */
-
- case SERVICE_START:
- case SERVICE_START_POST:
- /* If we were hoping for the daemon to write its PID file,
- * we can give up now. */
- if (s->pid_file_pathspec) {
- log_warning("%s never wrote its PID file. Failing.", UNIT(s)->id);
- service_unwatch_pid_file(s);
- if (s->state == SERVICE_START)
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
- else
- service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
- }
- break;
-
- case SERVICE_RUNNING:
- /* service_enter_running() will figure out what to do */
- service_enter_running(s, SERVICE_SUCCESS);
- break;
-
- case SERVICE_STOP_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_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_notify_message(Unit *u, pid_t pid, char **tags) {
- Service *s = SERVICE(u);
- const char *e;
-
- assert(u);
-
- if (s->notify_access == NOTIFY_NONE) {
- log_warning("%s: Got notification message from PID %lu, but reception is disabled.",
- u->id, (unsigned long) pid);
- return;
- }
-
- if (s->notify_access == NOTIFY_MAIN && pid != s->main_pid) {
- log_warning("%s: Got notification message from PID %lu, but reception only permitted for PID %lu",
- u->id, (unsigned long) pid, (unsigned long) s->main_pid);
- return;
- }
-
- log_debug("%s: Got message", u->id);
-
- /* Interpret MAINPID= */
- if ((e = strv_find_prefix(tags, "MAINPID=")) &&
- (s->state == SERVICE_START ||
- s->state == SERVICE_START_POST ||
- s->state == SERVICE_RUNNING ||
- s->state == SERVICE_RELOAD)) {
-
- if (parse_pid(e + 8, &pid) < 0)
- log_warning("Failed to parse notification message %s", e);
- else {
- log_debug("%s: got %s", u->id, e);
- service_set_main_pid(s, pid);
- }
- }
-
- /* Interpret READY= */
- if (s->type == SERVICE_NOTIFY &&
- s->state == SERVICE_START &&
- strv_find(tags, "READY=1")) {
- log_debug("%s: got READY=1", u->id);
-
- service_enter_start_post(s);
- }
-
- /* Interpret STATUS= */
- e = strv_find_prefix(tags, "STATUS=");
- if (e) {
- char *t;
-
- if (e[7]) {
-
- if (!utf8_is_valid(e+7)) {
- log_warning("Status message in notification is not UTF-8 clean.");
- return;
- }
-
- t = strdup(e+7);
- if (!t) {
- log_error("Failed to allocate string.");
- return;
- }
-
- log_debug("%s: got %s", u->id, e);
-
- free(s->status_text);
- s->status_text = t;
- } else {
- free(s->status_text);
- s->status_text = NULL;
- }
-
- }
- if (strv_find(tags, "WATCHDOG=1")) {
- log_debug("%s: got WATCHDOG=1", u->id);
- service_reset_watchdog(s);
- }
-
- /* Notify clients about changed status or main pid */
- unit_add_to_dbus_queue(u);
-}
-
-#ifdef HAVE_SYSV_COMPAT
-
-#ifdef TARGET_SUSE
-static void sysv_facility_in_insserv_conf(Manager *mgr) {
- FILE *f=NULL;
- int r;
-
- if (!(f = fopen("/etc/insserv.conf", "re"))) {
- r = errno == ENOENT ? 0 : -errno;
- goto finish;
- }
-
- while (!feof(f)) {
- char l[LINE_MAX], *t;
- char **parsed = NULL;
-
- if (!fgets(l, sizeof(l), f)) {
- if (feof(f))
- break;
-
- r = -errno;
- log_error("Failed to read configuration file '/etc/insserv.conf': %s", strerror(-r));
- goto finish;
- }
-
- t = strstrip(l);
- if (*t != '$' && *t != '<')
- continue;
-
- parsed = strv_split(t,WHITESPACE);
- /* we ignore <interactive>, not used, equivalent to X-Interactive */
- if (parsed && !startswith_no_case (parsed[0], "<interactive>")) {
- char *facility;
- Unit *u;
- if (sysv_translate_facility(parsed[0], NULL, &facility) < 0)
- continue;
- if ((u = manager_get_unit(mgr, facility)) && (u->type == UNIT_TARGET)) {
- UnitDependency e;
- char *dep = NULL, *name, **j;
-
- STRV_FOREACH (j, parsed+1) {
- if (*j[0]=='+') {
- e = UNIT_WANTS;
- name = *j+1;
- }
- else {
- e = UNIT_REQUIRES;
- name = *j;
- }
- if (sysv_translate_facility(name, NULL, &dep) < 0)
- continue;
-
- r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, e, dep, NULL, true);
- free(dep);
- }
- }
- free(facility);
- }
- strv_free(parsed);
- }
-finish:
- if (f)
- fclose(f);
-
-}
-#endif
-
-static int service_enumerate(Manager *m) {
- char **p;
- unsigned i;
- DIR *d = NULL;
- char *path = NULL, *fpath = NULL, *name = NULL;
- Set *runlevel_services[ELEMENTSOF(rcnd_table)], *shutdown_services = NULL;
- Unit *service;
- Iterator j;
- int r;
-
- assert(m);
-
- if (m->running_as != SYSTEMD_SYSTEM)
- return 0;
-
- zero(runlevel_services);
-
- STRV_FOREACH(p, m->lookup_paths.sysvrcnd_path)
- for (i = 0; i < ELEMENTSOF(rcnd_table); i ++) {
- struct dirent *de;
-
- free(path);
- path = strjoin(*p, "/", rcnd_table[i].path, NULL);
- if (!path) {
- r = -ENOMEM;
- goto finish;
- }
-
- if (d)
- closedir(d);
-
- if (!(d = opendir(path))) {
- if (errno != ENOENT)
- log_warning("opendir() failed on %s: %s", path, strerror(errno));
-
- continue;
- }
-
- while ((de = readdir(d))) {
- int a, b;
-
- if (ignore_file(de->d_name))
- continue;
-
- if (de->d_name[0] != 'S' && de->d_name[0] != 'K')
- continue;
-
- if (strlen(de->d_name) < 4)
- continue;
-
- a = undecchar(de->d_name[1]);
- b = undecchar(de->d_name[2]);
-
- if (a < 0 || b < 0)
- continue;
-
- free(fpath);
- fpath = strjoin(path, "/", de->d_name, NULL);
- if (!fpath) {
- r = -ENOMEM;
- goto finish;
- }
-
- if (access(fpath, X_OK) < 0) {
-
- if (errno != ENOENT)
- log_warning("access() failed on %s: %s", fpath, strerror(errno));
-
- continue;
- }
-
- free(name);
- if (!(name = sysv_translate_name(de->d_name + 3))) {
- r = -ENOMEM;
- goto finish;
- }
-
- if ((r = manager_load_unit_prepare(m, name, NULL, NULL, &service)) < 0) {
- log_warning("Failed to prepare unit %s: %s", name, strerror(-r));
- continue;
- }
-
- if (de->d_name[0] == 'S') {
-
- if (rcnd_table[i].type == RUNLEVEL_UP || rcnd_table[i].type == RUNLEVEL_SYSINIT) {
- SERVICE(service)->sysv_start_priority_from_rcnd =
- MAX(a*10 + b, SERVICE(service)->sysv_start_priority_from_rcnd);
-
- SERVICE(service)->sysv_enabled = true;
- }
-
- if ((r = set_ensure_allocated(&runlevel_services[i], trivial_hash_func, trivial_compare_func)) < 0)
- goto finish;
-
- if ((r = set_put(runlevel_services[i], service)) < 0)
- goto finish;
-
- } else if (de->d_name[0] == 'K' &&
- (rcnd_table[i].type == RUNLEVEL_DOWN ||
- rcnd_table[i].type == RUNLEVEL_SYSINIT)) {
-
- if ((r = set_ensure_allocated(&shutdown_services, trivial_hash_func, trivial_compare_func)) < 0)
- goto finish;
-
- if ((r = set_put(shutdown_services, service)) < 0)
- goto finish;
- }
- }
- }
-
- /* Now we loaded all stubs and are aware of the lowest
- start-up priority for all services, not let's actually load
- the services, this will also tell us which services are
- actually native now */
- manager_dispatch_load_queue(m);
-
- /* If this is a native service, rely on native ways to pull in
- * a service, don't pull it in via sysv rcN.d links. */
- for (i = 0; i < ELEMENTSOF(rcnd_table); i ++)
- SET_FOREACH(service, runlevel_services[i], j) {
- service = unit_follow_merge(service);
-
- if (service->fragment_path)
- continue;
-
- if ((r = unit_add_two_dependencies_by_name_inverse(service, UNIT_AFTER, UNIT_WANTS, rcnd_table[i].target, NULL, true)) < 0)
- goto finish;
- }
-
- /* We honour K links only for halt/reboot. For the normal
- * runlevels we assume the stop jobs will be implicitly added
- * by the core logic. Also, we don't really distinguish here
- * between the runlevels 0 and 6 and just add them to the
- * special shutdown target. On SUSE the boot.d/ runlevel is
- * also used for shutdown, so we add links for that too to the
- * shutdown target.*/
- SET_FOREACH(service, shutdown_services, j) {
- service = unit_follow_merge(service);
-
- if (service->fragment_path)
- continue;
-
- if ((r = unit_add_two_dependencies_by_name(service, UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true)) < 0)
- goto finish;
- }
-
- r = 0;
-
-#ifdef TARGET_SUSE
- sysv_facility_in_insserv_conf (m);
-#endif
-
-finish:
- free(path);
- free(fpath);
- free(name);
-
- for (i = 0; i < ELEMENTSOF(rcnd_table); i++)
- set_free(runlevel_services[i]);
- set_free(shutdown_services);
-
- if (d)
- closedir(d);
-
- return r;
-}
-#endif
-
-static void service_bus_name_owner_change(
- Unit *u,
- const char *name,
- const char *old_owner,
- const char *new_owner) {
-
- Service *s = SERVICE(u);
-
- assert(s);
- assert(name);
-
- assert(streq(s->bus_name, name));
- assert(old_owner || new_owner);
-
- if (old_owner && new_owner)
- log_debug("%s's D-Bus name %s changed owner from %s to %s", u->id, name, old_owner, new_owner);
- else if (old_owner)
- log_debug("%s's D-Bus name %s no longer registered by %s", u->id, name, old_owner);
- else
- log_debug("%s's D-Bus name %s now registered by %s", u->id, name, new_owner);
-
- s->bus_name_good = !!new_owner;
-
- if (s->type == SERVICE_DBUS) {
-
- /* service_enter_running() will figure out what to
- * do */
- if (s->state == SERVICE_RUNNING)
- service_enter_running(s, SERVICE_SUCCESS);
- else if (s->state == SERVICE_START && new_owner)
- service_enter_start_post(s);
-
- } else if (new_owner &&
- s->main_pid <= 0 &&
- (s->state == SERVICE_START ||
- s->state == SERVICE_START_POST ||
- s->state == SERVICE_RUNNING ||
- s->state == SERVICE_RELOAD)) {
-
- /* Try to acquire PID from bus service */
- log_debug("Trying to acquire PID from D-Bus name...");
-
- bus_query_pid(u->manager, name);
- }
-}
-
-static void service_bus_query_pid_done(
- Unit *u,
- const char *name,
- pid_t pid) {
-
- Service *s = SERVICE(u);
-
- assert(s);
- assert(name);
-
- log_debug("%s's D-Bus name %s is now owned by process %u", u->id, name, (unsigned) pid);
-
- if (s->main_pid <= 0 &&
- (s->state == SERVICE_START ||
- s->state == SERVICE_START_POST ||
- s->state == SERVICE_RUNNING ||
- s->state == SERVICE_RELOAD))
- service_set_main_pid(s, pid);
-}
-
-int service_set_socket_fd(Service *s, int fd, Socket *sock) {
-
- 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;
-
- s->socket_fd = fd;
- s->got_socket_fd = true;
-
- unit_ref_set(&s->accept_socket, UNIT(sock));
-
- return unit_add_two_dependencies(UNIT(sock), UNIT_BEFORE, UNIT_TRIGGERS, UNIT(s), false);
-}
-
-static void service_reset_failed(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
-
- if (s->state == SERVICE_FAILED)
- service_set_state(s, SERVICE_DEAD);
-
- s->result = SERVICE_SUCCESS;
- s->reload_result = SERVICE_SUCCESS;
-
- RATELIMIT_RESET(s->start_limit);
-}
-
-static int service_kill(Unit *u, KillWho who, int signo, DBusError *error) {
- Service *s = SERVICE(u);
- int r = 0;
- Set *pid_set = NULL;
-
- assert(s);
-
- if (s->main_pid <= 0 && who == KILL_MAIN) {
- dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No main process to kill");
- return -ESRCH;
- }
-
- if (s->control_pid <= 0 && who == KILL_CONTROL) {
- dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
- return -ESRCH;
- }
-
- if (who == KILL_CONTROL || who == KILL_ALL)
- if (s->control_pid > 0)
- if (kill(s->control_pid, signo) < 0)
- r = -errno;
-
- if (who == KILL_MAIN || who == KILL_ALL)
- if (s->main_pid > 0)
- if (kill(s->main_pid, signo) < 0)
- r = -errno;
-
- if (who == KILL_ALL) {
- int q;
-
- pid_set = set_new(trivial_hash_func, trivial_compare_func);
- if (!pid_set)
- return -ENOMEM;
-
- /* Exclude the control/main pid from being killed via the cgroup */
- if (s->control_pid > 0) {
- q = set_put(pid_set, LONG_TO_PTR(s->control_pid));
- if (q < 0) {
- r = q;
- goto finish;
- }
- }
-
- if (s->main_pid > 0) {
- q = set_put(pid_set, LONG_TO_PTR(s->main_pid));
- if (q < 0) {
- r = q;
- goto finish;
- }
- }
-
- q = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, signo, false, false, pid_set, NULL);
- if (q < 0 && q != -EAGAIN && q != -ESRCH && q != -ENOENT)
- r = q;
- }
-
-finish:
- if (pid_set)
- set_free(pid_set);
-
- return r;
-}
-
-static const char* const service_state_table[_SERVICE_STATE_MAX] = {
- [SERVICE_DEAD] = "dead",
- [SERVICE_START_PRE] = "start-pre",
- [SERVICE_START] = "start",
- [SERVICE_START_POST] = "start-post",
- [SERVICE_RUNNING] = "running",
- [SERVICE_EXITED] = "exited",
- [SERVICE_RELOAD] = "reload",
- [SERVICE_STOP] = "stop",
- [SERVICE_STOP_SIGTERM] = "stop-sigterm",
- [SERVICE_STOP_SIGKILL] = "stop-sigkill",
- [SERVICE_STOP_POST] = "stop-post",
- [SERVICE_FINAL_SIGTERM] = "final-sigterm",
- [SERVICE_FINAL_SIGKILL] = "final-sigkill",
- [SERVICE_FAILED] = "failed",
- [SERVICE_AUTO_RESTART] = "auto-restart",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(service_state, ServiceState);
-
-static const char* const service_restart_table[_SERVICE_RESTART_MAX] = {
- [SERVICE_RESTART_NO] = "no",
- [SERVICE_RESTART_ON_SUCCESS] = "on-success",
- [SERVICE_RESTART_ON_FAILURE] = "on-failure",
- [SERVICE_RESTART_ON_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 service_result_table[_SERVICE_RESULT_MAX] = {
- [SERVICE_SUCCESS] = "success",
- [SERVICE_FAILURE_RESOURCES] = "resources",
- [SERVICE_FAILURE_TIMEOUT] = "timeout",
- [SERVICE_FAILURE_EXIT_CODE] = "exit-code",
- [SERVICE_FAILURE_SIGNAL] = "signal",
- [SERVICE_FAILURE_CORE_DUMP] = "core-dump",
- [SERVICE_FAILURE_WATCHDOG] = "watchdog",
- [SERVICE_FAILURE_START_LIMIT] = "start-limit"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(service_result, ServiceResult);
-
-static const char* const start_limit_action_table[_SERVICE_START_LIMIT_MAX] = {
- [SERVICE_START_LIMIT_NONE] = "none",
- [SERVICE_START_LIMIT_REBOOT] = "reboot",
- [SERVICE_START_LIMIT_REBOOT_FORCE] = "reboot-force",
- [SERVICE_START_LIMIT_REBOOT_IMMEDIATE] = "reboot-immediate"
-};
-DEFINE_STRING_TABLE_LOOKUP(start_limit_action, StartLimitAction);
-
-const UnitVTable service_vtable = {
- .object_size = sizeof(Service),
- .exec_context_offset = offsetof(Service, exec_context),
-
- .sections =
- "Unit\0"
- "Service\0"
- "Install\0",
-
- .init = service_init,
- .done = service_done,
- .load = service_load,
-
- .coldplug = service_coldplug,
-
- .dump = service_dump,
-
- .start = service_start,
- .stop = service_stop,
- .reload = service_reload,
-
- .can_reload = service_can_reload,
-
- .kill = service_kill,
-
- .serialize = service_serialize,
- .deserialize_item = service_deserialize_item,
-
- .active_state = service_active_state,
- .sub_state_to_string = service_sub_state_to_string,
-
- .check_gc = service_check_gc,
- .check_snapshot = service_check_snapshot,
-
- .sigchld_event = service_sigchld_event,
- .timer_event = service_timer_event,
- .fd_event = service_fd_event,
-
- .reset_failed = service_reset_failed,
-
- .cgroup_notify_empty = service_cgroup_notify_event,
- .notify_message = service_notify_message,
-
- .bus_name_owner_change = service_bus_name_owner_change,
- .bus_query_pid_done = service_bus_query_pid_done,
-
- .bus_interface = "org.freedesktop.systemd1.Service",
- .bus_message_handler = bus_service_message_handler,
- .bus_invalidating_properties = bus_service_invalidating_properties,
-
-#ifdef HAVE_SYSV_COMPAT
- .enumerate = service_enumerate,
-#endif
- .status_message_formats = {
- .starting_stopping = {
- [0] = "Starting %s...",
- [1] = "Stopping %s...",
- },
- .finished_start_job = {
- [JOB_DONE] = "Started %s.",
- [JOB_FAILED] = "Failed to start %s.",
- [JOB_DEPENDENCY] = "Dependency failed for %s.",
- [JOB_TIMEOUT] = "Timed out starting %s.",
- },
- .finished_stop_job = {
- [JOB_DONE] = "Stopped %s.",
- [JOB_FAILED] = "Stopped (with error) %s.",
- [JOB_TIMEOUT] = "Timed out stopping %s.",
- },
- },
-};
diff --git a/src/core/service.h b/src/core/service.h
deleted file mode 100644
index d1e53bf727..0000000000
--- a/src/core/service.h
+++ /dev/null
@@ -1,225 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct Service Service;
-
-#include "unit.h"
-#include "path.h"
-#include "ratelimit.h"
-#include "service.h"
-#include "kill.h"
-#include "exit-status.h"
-
-typedef enum ServiceState {
- SERVICE_DEAD,
- SERVICE_START_PRE,
- SERVICE_START,
- SERVICE_START_POST,
- SERVICE_RUNNING,
- SERVICE_EXITED, /* Nothing is running anymore, but RemainAfterExit is true hence this is OK */
- SERVICE_RELOAD,
- SERVICE_STOP, /* No STOP_PRE state, instead just register multiple STOP executables */
- SERVICE_STOP_SIGTERM,
- SERVICE_STOP_SIGKILL,
- SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, /* In case the STOP_POST executable hangs, we shoot that down, too */
- SERVICE_FINAL_SIGKILL,
- SERVICE_FAILED,
- SERVICE_AUTO_RESTART,
- _SERVICE_STATE_MAX,
- _SERVICE_STATE_INVALID = -1
-} ServiceState;
-
-typedef enum ServiceRestart {
- SERVICE_RESTART_NO,
- SERVICE_RESTART_ON_SUCCESS,
- SERVICE_RESTART_ON_FAILURE,
- SERVICE_RESTART_ON_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 ServiceResult {
- SERVICE_SUCCESS,
- SERVICE_FAILURE_RESOURCES,
- SERVICE_FAILURE_TIMEOUT,
- SERVICE_FAILURE_EXIT_CODE,
- SERVICE_FAILURE_SIGNAL,
- SERVICE_FAILURE_CORE_DUMP,
- SERVICE_FAILURE_WATCHDOG,
- SERVICE_FAILURE_START_LIMIT,
- _SERVICE_RESULT_MAX,
- _SERVICE_RESULT_INVALID = -1
-} ServiceResult;
-
-typedef enum StartLimitAction {
- SERVICE_START_LIMIT_NONE,
- SERVICE_START_LIMIT_REBOOT,
- SERVICE_START_LIMIT_REBOOT_FORCE,
- SERVICE_START_LIMIT_REBOOT_IMMEDIATE,
- _SERVICE_START_LIMIT_MAX,
- _SERVICE_START_LIMIT_INVALID = -1
-} StartLimitAction;
-
-struct Service {
- Unit meta;
-
- ServiceType type;
- ServiceRestart restart;
- ExitStatusSet restart_ignore_status;
- ExitStatusSet success_status;
-
- /* If set we'll read the main daemon PID from this file */
- char *pid_file;
-
- usec_t restart_usec;
- usec_t timeout_start_usec;
- usec_t timeout_stop_usec;
-
- dual_timestamp watchdog_timestamp;
- usec_t watchdog_usec;
- Watch watchdog_watch;
-
- ExecCommand* exec_command[_SERVICE_EXEC_COMMAND_MAX];
-
- ExecContext exec_context;
- KillContext kill_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;
-
- pid_t main_pid, control_pid;
- int socket_fd;
-
- int fsck_passno;
-
- 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 got_socket_fd:1;
- bool start_timeout_defined:1;
-#ifdef HAVE_SYSV_COMPAT
- bool is_sysv:1;
- bool sysv_has_lsb:1;
- bool sysv_enabled:1;
- int sysv_start_priority_from_rcnd;
- int sysv_start_priority;
-
- char *sysv_runlevels;
-#endif
-
- char *bus_name;
-
- char *status_text;
-
- RateLimit start_limit;
- StartLimitAction start_limit_action;
-
- UnitRef accept_socket;
-
- Watch timer_watch;
- PathSpec *pid_file_pathspec;
-
- NotifyAccess notify_access;
-};
-
-extern const UnitVTable service_vtable;
-
-struct Socket;
-
-int service_set_socket_fd(Service *s, int fd, struct Socket *socket);
-
-const char* service_state_to_string(ServiceState i);
-ServiceState service_state_from_string(const char *s);
-
-const char* service_restart_to_string(ServiceRestart i);
-ServiceRestart service_restart_from_string(const char *s);
-
-const char* service_type_to_string(ServiceType i);
-ServiceType service_type_from_string(const char *s);
-
-const char* service_exec_command_to_string(ServiceExecCommand i);
-ServiceExecCommand service_exec_command_from_string(const char *s);
-
-const char* notify_access_to_string(NotifyAccess i);
-NotifyAccess notify_access_from_string(const char *s);
-
-const char* service_result_to_string(ServiceResult i);
-ServiceResult service_result_from_string(const char *s);
-
-const char* start_limit_action_to_string(StartLimitAction i);
-StartLimitAction start_limit_action_from_string(const char *s);
diff --git a/src/core/shutdown.c b/src/core/shutdown.c
deleted file mode 100644
index cc8c57bd2d..0000000000
--- a/src/core/shutdown.c
+++ /dev/null
@@ -1,316 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 ProFUSION embedded systems
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <sys/reboot.h>
-#include <linux/reboot.h>
-#include <sys/wait.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mount.h>
-#include <sys/syscall.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <errno.h>
-#include <unistd.h>
-#include <signal.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "missing.h"
-#include "log.h"
-#include "umount.h"
-#include "util.h"
-#include "mkdir.h"
-#include "virt.h"
-#include "watchdog.h"
-#include "killall.h"
-
-#define FINALIZE_ATTEMPTS 50
-
-static int prepare_new_root(void) {
- static const char dirs[] =
- "/run/initramfs/oldroot\0"
- "/run/initramfs/proc\0"
- "/run/initramfs/sys\0"
- "/run/initramfs/dev\0"
- "/run/initramfs/run\0";
-
- const char *dir;
-
- if (mount("/run/initramfs", "/run/initramfs", NULL, MS_BIND, NULL) < 0) {
- log_error("Failed to mount bind /run/initramfs on /run/initramfs: %m");
- return -errno;
- }
-
- if (mount(NULL, "/run/initramfs", NULL, MS_PRIVATE, NULL) < 0) {
- log_error("Failed to make /run/initramfs private mount: %m");
- return -errno;
- }
-
- NULSTR_FOREACH(dir, dirs)
- if (mkdir_p_label(dir, 0755) < 0 && errno != EEXIST) {
- log_error("Failed to mkdir %s: %m", dir);
- return -errno;
- }
-
- if (mount("/sys", "/run/initramfs/sys", NULL, MS_BIND, NULL) < 0) {
- log_error("Failed to mount bind /sys on /run/initramfs/sys: %m");
- return -errno;
- }
-
- if (mount("/proc", "/run/initramfs/proc", NULL, MS_BIND, NULL) < 0) {
- log_error("Failed to mount bind /proc on /run/initramfs/proc: %m");
- return -errno;
- }
-
- if (mount("/dev", "/run/initramfs/dev", NULL, MS_BIND, NULL) < 0) {
- log_error("Failed to mount bind /dev on /run/initramfs/dev: %m");
- return -errno;
- }
-
- if (mount("/run", "/run/initramfs/run", NULL, MS_BIND, NULL) < 0) {
- log_error("Failed to mount bind /run on /run/initramfs/run: %m");
- return -errno;
- }
-
- return 0;
-}
-
-static int pivot_to_new_root(void) {
-
- if (chdir("/run/initramfs") < 0) {
- log_error("Failed to change directory to /run/initramfs: %m");
- return -errno;
- }
-
- /* Work-around for a kernel bug: for some reason the kernel
- * refuses switching root if any file systems are mounted
- * MS_SHARED. Hence remount them MS_PRIVATE here as a
- * work-around.
- *
- * https://bugzilla.redhat.com/show_bug.cgi?id=847418 */
- if (mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL) < 0)
- log_warning("Failed to make \"/\" private mount: %m");
-
- if (pivot_root(".", "oldroot") < 0) {
- log_error("pivot failed: %m");
- /* only chroot if pivot root succeeded */
- return -errno;
- }
-
- chroot(".");
-
- setsid();
- make_console_stdio();
-
- log_info("Successfully changed into root pivot.");
-
- return 0;
-}
-
-int main(int argc, char *argv[]) {
- int cmd, r;
- unsigned retries;
- bool need_umount = true, need_swapoff = true, need_loop_detach = true, need_dm_detach = true;
- bool in_container, use_watchdog = false;
- char *arguments[3];
-
- log_parse_environment();
- log_set_target(LOG_TARGET_CONSOLE); /* syslog will die if not gone yet */
- log_open();
-
- umask(0022);
-
- if (getpid() != 1) {
- log_error("Not executed by init (pid 1).");
- r = -EPERM;
- goto error;
- }
-
- if (argc != 2) {
- log_error("Invalid number of arguments.");
- r = -EINVAL;
- goto error;
- }
-
- in_container = detect_container(NULL) > 0;
-
- if (streq(argv[1], "reboot"))
- cmd = RB_AUTOBOOT;
- else if (streq(argv[1], "poweroff"))
- cmd = RB_POWER_OFF;
- else if (streq(argv[1], "halt"))
- cmd = RB_HALT_SYSTEM;
- else if (streq(argv[1], "kexec"))
- cmd = LINUX_REBOOT_CMD_KEXEC;
- else {
- log_error("Unknown action '%s'.", argv[1]);
- r = -EINVAL;
- goto error;
- }
-
- 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);
-
- log_info("Sending SIGKILL to remaining processes...");
- broadcast_signal(SIGKILL, true);
-
- if (in_container) {
- need_swapoff = false;
- need_dm_detach = false;
- need_loop_detach = false;
- }
-
- /* Unmount all mountpoints, swaps, and loopback devices */
- for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) {
- bool changed = false;
-
- if (use_watchdog)
- watchdog_ping();
-
- if (need_umount) {
- log_info("Unmounting file systems.");
- r = umount_all(&changed);
- if (r == 0)
- need_umount = false;
- else if (r > 0)
- log_info("Not all file systems unmounted, %d left.", r);
- else
- log_error("Failed to unmount file systems: %s", strerror(-r));
- }
-
- if (need_swapoff) {
- log_info("Disabling swaps.");
- r = swapoff_all(&changed);
- if (r == 0)
- need_swapoff = false;
- else if (r > 0)
- log_info("Not all swaps are turned off, %d left.", r);
- else
- log_error("Failed to turn off swaps: %s", strerror(-r));
- }
-
- if (need_loop_detach) {
- log_info("Detaching loop devices.");
- r = loopback_detach_all(&changed);
- if (r == 0)
- need_loop_detach = false;
- else if (r > 0)
- log_info("Not all loop devices detached, %d left.", r);
- else
- log_error("Failed to detach loop devices: %s", strerror(-r));
- }
-
- if (need_dm_detach) {
- log_info("Detaching DM devices.");
- r = dm_detach_all(&changed);
- if (r == 0)
- need_dm_detach = false;
- else if (r > 0)
- log_warning("Not all DM devices detached, %d left.", r);
- else
- log_error("Failed to detach DM devices: %s", strerror(-r));
- }
-
- 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 */
- break;
- }
-
- /* If in this iteration we didn't manage to
- * unmount/deactivate anything, we simply give up */
- if (!changed) {
- log_error("Cannot finalize remaining file systems and devices, giving up.");
- break;
- }
-
- log_debug("Couldn't finalize remaining file systems and devices after %u retries, trying again.", retries+1);
- }
-
- if (retries >= FINALIZE_ATTEMPTS)
- log_error("Too many iterations, giving up.");
-
- arguments[0] = NULL;
- arguments[1] = argv[1];
- arguments[2] = NULL;
- execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, arguments);
-
- if (!in_container &&
- access("/run/initramfs/shutdown", X_OK) == 0) {
-
- if (prepare_new_root() >= 0 &&
- pivot_to_new_root() >= 0) {
- execv("/shutdown", argv);
- log_error("Failed to execute shutdown binary: %m");
- }
- }
-
- if (cmd == LINUX_REBOOT_CMD_KEXEC) {
-
- if (!in_container) {
- /* We cheat and exec kexec to avoid doing all its work */
- pid_t pid = fork();
-
- if (pid < 0)
- log_error("Could not fork: %m. Falling back to normal reboot.");
- else if (pid > 0) {
- wait_for_terminate_and_warn("kexec", pid);
- log_warning("kexec failed. Falling back to normal reboot.");
- } else {
- /* Child */
- const char *args[3] = { "/sbin/kexec", "-e", NULL };
- execv(args[0], (char * const *) args);
- return EXIT_FAILURE;
- }
- }
-
- cmd = RB_AUTOBOOT;
- }
-
- 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_error("Exiting container.");
- exit(0);
- }
-
- log_error("Failed to invoke reboot(): %m");
- r = -errno;
-
- error:
- log_error("Critical error while doing system shutdown: %s", strerror(-r));
-
- freeze();
- return EXIT_FAILURE;
-}
diff --git a/src/core/snapshot.c b/src/core/snapshot.c
deleted file mode 100644
index 5c2a319cb6..0000000000
--- a/src/core/snapshot.c
+++ /dev/null
@@ -1,308 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-
-#include "unit.h"
-#include "snapshot.h"
-#include "unit-name.h"
-#include "dbus-snapshot.h"
-#include "bus-errors.h"
-
-static const UnitActiveState state_translation_table[_SNAPSHOT_STATE_MAX] = {
- [SNAPSHOT_DEAD] = UNIT_INACTIVE,
- [SNAPSHOT_ACTIVE] = UNIT_ACTIVE
-};
-
-static void snapshot_init(Unit *u) {
- Snapshot *s = SNAPSHOT(u);
-
- assert(s);
- assert(UNIT(s)->load_state == UNIT_STUB);
-
- UNIT(s)->ignore_on_isolate = true;
- UNIT(s)->ignore_on_snapshot = true;
-}
-
-static void snapshot_set_state(Snapshot *s, SnapshotState state) {
- SnapshotState old_state;
- assert(s);
-
- old_state = s->state;
- s->state = state;
-
- if (state != old_state)
- log_debug("%s changed %s -> %s",
- UNIT(s)->id,
- snapshot_state_to_string(old_state),
- snapshot_state_to_string(state));
-
- unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
-}
-
-static int snapshot_load(Unit *u) {
- Snapshot *s = SNAPSHOT(u);
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
-
- /* Make sure that only snapshots created via snapshot_create()
- * can be loaded */
- if (!s->by_snapshot_create && UNIT(s)->manager->n_reloading <= 0)
- return -ENOENT;
-
- u->load_state = UNIT_LOADED;
- return 0;
-}
-
-static int snapshot_coldplug(Unit *u) {
- Snapshot *s = SNAPSHOT(u);
-
- assert(s);
- assert(s->state == SNAPSHOT_DEAD);
-
- if (s->deserialized_state != s->state)
- snapshot_set_state(s, s->deserialized_state);
-
- return 0;
-}
-
-static void snapshot_dump(Unit *u, FILE *f, const char *prefix) {
- Snapshot *s = SNAPSHOT(u);
-
- assert(s);
- assert(f);
-
- fprintf(f,
- "%sSnapshot State: %s\n"
- "%sClean Up: %s\n",
- prefix, snapshot_state_to_string(s->state),
- prefix, yes_no(s->cleanup));
-}
-
-static int snapshot_start(Unit *u) {
- Snapshot *s = SNAPSHOT(u);
-
- assert(s);
- assert(s->state == SNAPSHOT_DEAD);
-
- snapshot_set_state(s, SNAPSHOT_ACTIVE);
-
- if (s->cleanup)
- unit_add_to_cleanup_queue(u);
-
- return 0;
-}
-
-static int snapshot_stop(Unit *u) {
- Snapshot *s = SNAPSHOT(u);
-
- assert(s);
- assert(s->state == SNAPSHOT_ACTIVE);
-
- snapshot_set_state(s, SNAPSHOT_DEAD);
- return 0;
-}
-
-static int snapshot_serialize(Unit *u, FILE *f, FDSet *fds) {
- Snapshot *s = SNAPSHOT(u);
- Unit *other;
- Iterator i;
-
- assert(s);
- assert(f);
- assert(fds);
-
- unit_serialize_item(u, f, "state", snapshot_state_to_string(s->state));
- unit_serialize_item(u, f, "cleanup", yes_no(s->cleanup));
- SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
- unit_serialize_item(u, f, "wants", other->id);
-
- return 0;
-}
-
-static int snapshot_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Snapshot *s = SNAPSHOT(u);
- int r;
-
- assert(u);
- assert(key);
- assert(value);
- assert(fds);
-
- if (streq(key, "state")) {
- SnapshotState state;
-
- if ((state = snapshot_state_from_string(value)) < 0)
- log_debug("Failed to parse state value %s", value);
- else
- s->deserialized_state = state;
-
- } else if (streq(key, "cleanup")) {
-
- if ((r = parse_boolean(value)) < 0)
- log_debug("Failed to parse cleanup value %s", value);
- else
- s->cleanup = r;
-
- } else if (streq(key, "wants")) {
-
- if ((r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, value, NULL, true)) < 0)
- return r;
- } else
- log_debug("Unknown serialization key '%s'", key);
-
- return 0;
-}
-
-static UnitActiveState snapshot_active_state(Unit *u) {
- assert(u);
-
- return state_translation_table[SNAPSHOT(u)->state];
-}
-
-static const char *snapshot_sub_state_to_string(Unit *u) {
- assert(u);
-
- return snapshot_state_to_string(SNAPSHOT(u)->state);
-}
-
-int snapshot_create(Manager *m, const char *name, bool cleanup, DBusError *e, Snapshot **_s) {
- Iterator i;
- Unit *other, *u = NULL;
- char *n = NULL;
- int r;
- const char *k;
-
- assert(m);
- assert(_s);
-
- if (name) {
- if (!unit_name_is_valid(name, false)) {
- dbus_set_error(e, BUS_ERROR_INVALID_NAME, "Unit name %s is not valid.", name);
- return -EINVAL;
- }
-
- if (unit_name_to_type(name) != UNIT_SNAPSHOT) {
- dbus_set_error(e, BUS_ERROR_UNIT_TYPE_MISMATCH, "Unit name %s lacks snapshot suffix.", name);
- return -EINVAL;
- }
-
- if (manager_get_unit(m, name)) {
- dbus_set_error(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", name);
- return -EEXIST;
- }
-
- } else {
-
- for (;;) {
- if (asprintf(&n, "snapshot-%u.snapshot", ++ m->n_snapshots) < 0)
- return -ENOMEM;
-
- if (!manager_get_unit(m, n))
- break;
-
- free(n);
- }
-
- name = n;
- }
-
- r = manager_load_unit_prepare(m, name, NULL, e, &u);
- free(n);
-
- if (r < 0)
- goto fail;
-
- SNAPSHOT(u)->by_snapshot_create = true;
- manager_dispatch_load_queue(m);
- assert(u->load_state == UNIT_LOADED);
-
- HASHMAP_FOREACH_KEY(other, k, m->units, i) {
-
- if (other->ignore_on_snapshot)
- continue;
-
- if (k != other->id)
- continue;
-
- if (UNIT_VTABLE(other)->check_snapshot)
- if (!UNIT_VTABLE(other)->check_snapshot(other))
- continue;
-
- if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
- continue;
-
- if ((r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, other, true)) < 0)
- goto fail;
- }
-
- SNAPSHOT(u)->cleanup = cleanup;
- *_s = SNAPSHOT(u);
-
- return 0;
-
-fail:
- if (u)
- unit_add_to_cleanup_queue(u);
-
- return r;
-}
-
-void snapshot_remove(Snapshot *s) {
- assert(s);
-
- unit_add_to_cleanup_queue(UNIT(s));
-}
-
-static const char* const snapshot_state_table[_SNAPSHOT_STATE_MAX] = {
- [SNAPSHOT_DEAD] = "dead",
- [SNAPSHOT_ACTIVE] = "active"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(snapshot_state, SnapshotState);
-
-const UnitVTable snapshot_vtable = {
- .object_size = sizeof(Snapshot),
-
- .no_alias = true,
- .no_instances = true,
- .no_gc = true,
-
- .init = snapshot_init,
-
- .load = snapshot_load,
- .coldplug = snapshot_coldplug,
-
- .dump = snapshot_dump,
-
- .start = snapshot_start,
- .stop = snapshot_stop,
-
- .serialize = snapshot_serialize,
- .deserialize_item = snapshot_deserialize_item,
-
- .active_state = snapshot_active_state,
- .sub_state_to_string = snapshot_sub_state_to_string,
-
- .bus_interface = "org.freedesktop.systemd1.Snapshot",
- .bus_message_handler = bus_snapshot_message_handler
-};
diff --git a/src/core/snapshot.h b/src/core/snapshot.h
deleted file mode 100644
index 9662d93164..0000000000
--- a/src/core/snapshot.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct Snapshot Snapshot;
-
-#include "unit.h"
-
-typedef enum SnapshotState {
- SNAPSHOT_DEAD,
- SNAPSHOT_ACTIVE,
- _SNAPSHOT_STATE_MAX,
- _SNAPSHOT_STATE_INVALID = -1
-} SnapshotState;
-
-struct Snapshot {
- Unit meta;
-
- SnapshotState state, deserialized_state;
-
- bool cleanup;
- bool by_snapshot_create:1;
-};
-
-extern const UnitVTable snapshot_vtable;
-
-int snapshot_create(Manager *m, const char *name, bool cleanup, DBusError *e, Snapshot **s);
-void snapshot_remove(Snapshot *s);
-
-const char* snapshot_state_to_string(SnapshotState i);
-SnapshotState snapshot_state_from_string(const char *s);
diff --git a/src/core/socket.c b/src/core/socket.c
deleted file mode 100644
index c0959815c1..0000000000
--- a/src/core/socket.c
+++ /dev/null
@@ -1,2289 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <sys/epoll.h>
-#include <signal.h>
-#include <arpa/inet.h>
-#include <mqueue.h>
-#include <attr/xattr.h>
-
-#include "unit.h"
-#include "socket.h"
-#include "netinet/tcp.h"
-#include "log.h"
-#include "load-dropin.h"
-#include "load-fragment.h"
-#include "strv.h"
-#include "mkdir.h"
-#include "path-util.h"
-#include "unit-name.h"
-#include "unit-printf.h"
-#include "dbus-socket.h"
-#include "missing.h"
-#include "special.h"
-#include "bus-errors.h"
-#include "label.h"
-#include "exit-status.h"
-#include "def.h"
-
-static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = {
- [SOCKET_DEAD] = UNIT_INACTIVE,
- [SOCKET_START_PRE] = 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 void socket_init(Unit *u) {
- Socket *s = SOCKET(u);
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
-
- s->backlog = SOMAXCONN;
- s->timeout_usec = DEFAULT_TIMEOUT_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;
-
- exec_context_init(&s->exec_context);
- s->exec_context.std_output = u->manager->default_std_output;
- s->exec_context.std_error = u->manager->default_std_error;
- kill_context_init(&s->kill_context);
-
- 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_done(Unit *u) {
- Socket *s = SOCKET(u);
- SocketPort *p;
-
- assert(s);
-
- while ((p = s->ports)) {
- LIST_REMOVE(SocketPort, port, s->ports, p);
-
- if (p->fd >= 0) {
- unit_unwatch_fd(UNIT(s), &p->fd_watch);
- close_nointr_nofail(p->fd);
- }
-
- free(p->path);
- free(p);
- }
-
- exec_context_done(&s->exec_context);
- exec_command_free_array(s->exec_command, _SOCKET_EXEC_COMMAND_MAX);
- s->control_command = NULL;
-
- socket_unwatch_control_pid(s);
-
- unit_ref_unset(&s->service);
-
- free(s->tcp_congestion);
- s->tcp_congestion = NULL;
-
- free(s->bind_to_device);
- s->bind_to_device = NULL;
-
- free(s->smack);
- free(s->smack_ip_in);
- free(s->smack_ip_out);
-
- unit_unwatch_timer(u, &s->timer_watch);
-}
-
-static int socket_instantiate_service(Socket *s) {
- char *prefix, *name;
- 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;
-
- assert(s->accept);
-
- if (!(prefix = unit_name_to_prefix(UNIT(s)->id)))
- return -ENOMEM;
-
- r = asprintf(&name, "%s@%u.service", prefix, s->n_accepted);
- free(prefix);
-
- if (r < 0)
- return -ENOMEM;
-
- r = manager_load_unit(UNIT(s)->manager, name, NULL, NULL, &u);
- free(name);
-
- if (r < 0)
- return r;
-
-#ifdef HAVE_SYSV_COMPAT
- if (SERVICE(u)->is_sysv) {
- log_error("Using SysV services for socket activation is not supported. Refusing.");
- return -ENOENT;
- }
-#endif
-
- 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_verify(Socket *s) {
- assert(s);
-
- if (UNIT(s)->load_state != UNIT_LOADED)
- return 0;
-
- if (!s->ports) {
- log_error("%s lacks Listen setting. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
-
- if (s->accept && have_non_accept_socket(s)) {
- log_error("%s configured for accepting sockets, but sockets are non-accepting. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
-
- if (s->accept && s->max_connections <= 0) {
- log_error("%s's MaxConnection setting too small. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
-
- if (s->accept && UNIT_DEREF(s->service)) {
- log_error("Explicit service configuration for accepting sockets not supported on %s. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
-
- if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) {
- log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing.", UNIT(s)->id);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static bool socket_needs_mount(Socket *s, const char *prefix) {
- SocketPort *p;
-
- assert(s);
-
- LIST_FOREACH(port, p, s->ports) {
-
- if (p->type == SOCKET_SOCKET) {
- if (socket_address_needs_mount(&p->address, prefix))
- return true;
- } else if (p->type == SOCKET_FIFO || p->type == SOCKET_SPECIAL) {
- if (path_startswith(p->path, prefix))
- return true;
- }
- }
-
- return false;
-}
-
-int socket_add_one_mount_link(Socket *s, Mount *m) {
- int r;
-
- assert(s);
- assert(m);
-
- if (UNIT(s)->load_state != UNIT_LOADED ||
- UNIT(m)->load_state != UNIT_LOADED)
- return 0;
-
- if (!socket_needs_mount(s, m->where))
- return 0;
-
- r = unit_add_two_dependencies(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-static int socket_add_mount_links(Socket *s) {
- Unit *other;
- int r;
-
- assert(s);
-
- LIST_FOREACH(units_by_type, other, UNIT(s)->manager->units_by_type[UNIT_MOUNT]) {
- r = socket_add_one_mount_link(s, MOUNT(other));
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-static int socket_add_device_link(Socket *s) {
- char *t;
- int r;
-
- assert(s);
-
- if (!s->bind_to_device)
- return 0;
-
- if (asprintf(&t, "/sys/subsystem/net/devices/%s", s->bind_to_device) < 0)
- return -ENOMEM;
-
- r = unit_add_node_link(UNIT(s), t, false);
- free(t);
-
- return r;
-}
-
-static int socket_add_default_dependencies(Socket *s) {
- int r;
- assert(s);
-
- if (UNIT(s)->manager->running_as == SYSTEMD_SYSTEM) {
- if ((r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SOCKETS_TARGET, NULL, true)) < 0)
- return r;
-
- if ((r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true)) < 0)
- return r;
- }
-
- return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
-}
-
-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_load(Unit *u) {
- Socket *s = SOCKET(u);
- int r;
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
-
- if ((r = unit_load_fragment_and_dropin(u)) < 0)
- return r;
-
- /* This is a new unit? Then let's add in some extras */
- if (u->load_state == UNIT_LOADED) {
-
- 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;
- }
-
- if ((r = socket_add_mount_links(s)) < 0)
- return r;
-
- if ((r = socket_add_device_link(s)) < 0)
- return r;
-
- if (socket_has_exec(s))
- if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0)
- return r;
-
- if ((r = unit_add_default_cgroups(u)) < 0)
- return r;
-
- if (UNIT(s)->default_dependencies)
- if ((r = socket_add_default_dependencies(s)) < 0)
- return r;
-
- r = unit_exec_context_defaults(u, &s->exec_context);
- if (r < 0)
- return r;
- }
-
- return socket_verify(s);
-}
-
-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) {
-
- SocketExecCommand c;
- Socket *s = SOCKET(u);
- SocketPort *p;
- const char *prefix2;
- char *p2;
-
- assert(s);
- assert(f);
-
- p2 = strappend(prefix, "\t");
- prefix2 = p2 ? p2 : prefix;
-
- fprintf(f,
- "%sSocket State: %s\n"
- "%sResult: %s\n"
- "%sBindIPv6Only: %s\n"
- "%sBacklog: %u\n"
- "%sSocketMode: %04o\n"
- "%sDirectoryMode: %04o\n"
- "%sKeepAlive: %s\n"
- "%sFreeBind: %s\n"
- "%sTransparent: %s\n"
- "%sBroadcast: %s\n"
- "%sPassCredentials: %s\n"
- "%sPassSecurity: %s\n"
- "%sTCPCongestion: %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->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));
-
- if (s->control_pid > 0)
- fprintf(f,
- "%sControl PID: %lu\n",
- prefix, (unsigned long) 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->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);
-
- LIST_FOREACH(port, p, s->ports) {
-
- if (p->type == SOCKET_SOCKET) {
- const char *t;
- int r;
- char *k = NULL;
-
- if ((r = socket_address_print(&p->address, &k)) < 0)
- t = strerror(-r);
- else
- t = k;
-
- fprintf(f, "%s%s: %s\n", prefix, listen_lookup(socket_address_family(&p->address), p->address.type), t);
- free(k);
- } else if (p->type == SOCKET_SPECIAL)
- fprintf(f, "%sListenSpecial: %s\n", prefix, p->path);
- else if (p->type == SOCKET_MQUEUE)
- fprintf(f, "%sListenMessageQueue: %s\n", prefix, p->path);
- else
- fprintf(f, "%sListenFIFO: %s\n", prefix, p->path);
- }
-
- exec_context_dump(&s->exec_context, f, prefix);
- kill_context_dump(&s->kill_context, f, prefix);
-
- for (c = 0; c < _SOCKET_EXEC_COMMAND_MAX; c++) {
- if (!s->exec_command[c])
- continue;
-
- fprintf(f, "%s-> %s:\n",
- prefix, socket_exec_command_to_string(c));
-
- exec_command_dump_list(s->exec_command[c], f, prefix2);
- }
-
- free(p2);
-}
-
-static int instance_from_socket(int fd, unsigned nr, char **instance) {
- socklen_t l;
- char *r;
- union {
- struct sockaddr sa;
- struct sockaddr_un un;
- struct sockaddr_in in;
- struct sockaddr_in6 in6;
- struct sockaddr_storage storage;
- } 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;
-
- l = sizeof(ucred);
- if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l) < 0)
- return -errno;
-
- if (asprintf(&r,
- "%u-%lu-%lu",
- nr,
- (unsigned long) ucred.pid,
- (unsigned long) ucred.uid) < 0)
- return -ENOMEM;
-
- break;
- }
-
- default:
- assert_not_reached("Unhandled socket type.");
- }
-
- *instance = r;
- return 0;
-}
-
-static void socket_close_fds(Socket *s) {
- SocketPort *p;
-
- assert(s);
-
- LIST_FOREACH(port, p, s->ports) {
- if (p->fd < 0)
- continue;
-
- unit_unwatch_fd(UNIT(s), &p->fd_watch);
- close_nointr_nofail(p->fd);
-
- /* One little note: we should never 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! */
-
- p->fd = -1;
- }
-}
-
-static void socket_apply_socket_options(Socket *s, int fd) {
- 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_warning("SO_KEEPALIVE failed: %m");
- }
-
- if (s->broadcast) {
- int one = 1;
- if (setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &one, sizeof(one)) < 0)
- log_warning("SO_BROADCAST failed: %m");
- }
-
- if (s->pass_cred) {
- int one = 1;
- if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0)
- log_warning("SO_PASSCRED failed: %m");
- }
-
- if (s->pass_sec) {
- int one = 1;
- if (setsockopt(fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one)) < 0)
- log_warning("SO_PASSSEC failed: %m");
- }
-
- if (s->priority >= 0)
- if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, &s->priority, sizeof(s->priority)) < 0)
- log_warning("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_warning("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_warning("SO_SNDBUF failed: %m");
- }
-
- if (s->mark >= 0)
- if (setsockopt(fd, SOL_SOCKET, SO_MARK, &s->mark, sizeof(s->mark)) < 0)
- log_warning("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_warning("IP_TOS failed: %m");
-
- if (s->ip_ttl >= 0) {
- int r, 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_warning("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_warning("TCP_CONGESTION failed: %m");
-
- if (s->smack_ip_in)
- if (fsetxattr(fd, "security.SMACK64IPIN", s->smack_ip_in, strlen(s->smack_ip_in), 0) < 0)
- log_error("fsetxattr(\"security.SMACK64IPIN\"): %m");
-
- if (s->smack_ip_out)
- if (fsetxattr(fd, "security.SMACK64IPOUT", s->smack_ip_out, strlen(s->smack_ip_out), 0) < 0)
- log_error("fsetxattr(\"security.SMACK64IPOUT\"): %m");
-}
-
-static void socket_apply_fifo_options(Socket *s, int fd) {
- assert(s);
- assert(fd >= 0);
-
- if (s->pipe_size > 0)
- if (fcntl(fd, F_SETPIPE_SZ, s->pipe_size) < 0)
- log_warning("F_SETPIPE_SZ: %m");
-
- if (s->smack)
- if (fsetxattr(fd, "security.SMACK64", s->smack, strlen(s->smack), 0) < 0)
- log_error("fsetxattr(\"security.SMACK64\"): %m");
-}
-
-static int fifo_address_create(
- const char *path,
- mode_t directory_mode,
- mode_t socket_mode,
- int *_fd) {
-
- int fd = -1, r = 0;
- struct stat st;
- mode_t old_mask;
-
- assert(path);
- assert(_fd);
-
- mkdir_parents_label(path, directory_mode);
-
- r = label_context_set(path, S_IFIFO);
- if (r < 0)
- goto fail;
-
- /* Enforce the right access mode for the fifo */
- old_mask = umask(~ socket_mode);
-
- /* Include the original umask in our mask */
- umask(~socket_mode | old_mask);
-
- r = mkfifo(path, socket_mode);
- umask(old_mask);
-
- if (r < 0 && errno != EEXIST) {
- r = -errno;
- goto fail;
- }
-
- if ((fd = open(path, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW)) < 0) {
- r = -errno;
- goto fail;
- }
-
- label_context_clear();
-
- if (fstat(fd, &st) < 0) {
- r = -errno;
- goto fail;
- }
-
- if (!S_ISFIFO(st.st_mode) ||
- (st.st_mode & 0777) != (socket_mode & ~old_mask) ||
- st.st_uid != getuid() ||
- st.st_gid != getgid()) {
-
- r = -EEXIST;
- goto fail;
- }
-
- *_fd = fd;
- return 0;
-
-fail:
- label_context_clear();
-
- if (fd >= 0)
- close_nointr_nofail(fd);
-
- return r;
-}
-
-static int special_address_create(
- const char *path,
- int *_fd) {
-
- int fd = -1, r = 0;
- struct stat st;
-
- assert(path);
- assert(_fd);
-
- if ((fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW)) < 0) {
- r = -errno;
- goto fail;
- }
-
- if (fstat(fd, &st) < 0) {
- r = -errno;
- goto fail;
- }
-
- /* Check whether this is a /proc, /sys or /dev file or char device */
- if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) {
- r = -EEXIST;
- goto fail;
- }
-
- *_fd = fd;
- return 0;
-
-fail:
- if (fd >= 0)
- close_nointr_nofail(fd);
-
- return r;
-}
-
-static int mq_address_create(
- const char *path,
- mode_t mq_mode,
- long maxmsg,
- long msgsize,
- int *_fd) {
-
- int fd = -1, r = 0;
- struct stat st;
- mode_t old_mask;
- struct mq_attr _attr, *attr = NULL;
-
- assert(path);
- assert(_fd);
-
- if (maxmsg > 0 && msgsize > 0) {
- zero(_attr);
- _attr.mq_flags = O_NONBLOCK;
- _attr.mq_maxmsg = maxmsg;
- _attr.mq_msgsize = msgsize;
- attr = &_attr;
- }
-
- /* Enforce the right access mode for the mq */
- old_mask = umask(~ mq_mode);
-
- /* Include the original umask in our mask */
- umask(~mq_mode | old_mask);
-
- fd = mq_open(path, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_CREAT, mq_mode, attr);
- umask(old_mask);
-
- if (fd < 0) {
- r = -errno;
- goto fail;
- }
-
- if (fstat(fd, &st) < 0) {
- r = -errno;
- goto fail;
- }
-
- if ((st.st_mode & 0777) != (mq_mode & ~old_mask) ||
- st.st_uid != getuid() ||
- st.st_gid != getgid()) {
-
- r = -EEXIST;
- goto fail;
- }
-
- *_fd = fd;
- return 0;
-
-fail:
- if (fd >= 0)
- close_nointr_nofail(fd);
-
- return r;
-}
-
-static int socket_open_fds(Socket *s) {
- SocketPort *p;
- int r;
- char *label = NULL;
- bool know_label = false;
-
- assert(s);
-
- LIST_FOREACH(port, p, s->ports) {
-
- if (p->fd >= 0)
- continue;
-
- if (p->type == SOCKET_SOCKET) {
-
- if (!know_label) {
-
- if ((r = socket_instantiate_service(s)) < 0)
- return r;
-
- if (UNIT_DEREF(s->service) &&
- SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]) {
- r = label_get_create_label_from_exe(SERVICE(UNIT_DEREF(s->service))->exec_command[SERVICE_EXEC_START]->path, &label);
-
- if (r < 0) {
- if (r != -EPERM)
- return r;
- }
- }
-
- know_label = true;
- }
-
- if ((r = socket_address_listen(
- &p->address,
- s->backlog,
- s->bind_ipv6_only,
- s->bind_to_device,
- s->free_bind,
- s->transparent,
- s->directory_mode,
- s->socket_mode,
- label,
- &p->fd)) < 0)
- goto rollback;
-
- socket_apply_socket_options(s, p->fd);
-
- } else if (p->type == SOCKET_SPECIAL) {
-
- if ((r = special_address_create(
- p->path,
- &p->fd)) < 0)
- goto rollback;
-
- } else if (p->type == SOCKET_FIFO) {
-
- if ((r = fifo_address_create(
- p->path,
- s->directory_mode,
- s->socket_mode,
- &p->fd)) < 0)
- goto rollback;
-
- socket_apply_fifo_options(s, p->fd);
- } else if (p->type == SOCKET_MQUEUE) {
-
- if ((r = mq_address_create(
- p->path,
- s->socket_mode,
- s->mq_maxmsg,
- s->mq_msgsize,
- &p->fd)) < 0)
- goto rollback;
- } else
- assert_not_reached("Unknown port type");
- }
-
- label_free(label);
- return 0;
-
-rollback:
- socket_close_fds(s);
- label_free(label);
- return r;
-}
-
-static void socket_unwatch_fds(Socket *s) {
- SocketPort *p;
-
- assert(s);
-
- LIST_FOREACH(port, p, s->ports) {
- if (p->fd < 0)
- continue;
-
- unit_unwatch_fd(UNIT(s), &p->fd_watch);
- }
-}
-
-static int socket_watch_fds(Socket *s) {
- SocketPort *p;
- int r;
-
- assert(s);
-
- LIST_FOREACH(port, p, s->ports) {
- if (p->fd < 0)
- continue;
-
- p->fd_watch.socket_accept =
- s->accept &&
- p->type == SOCKET_SOCKET &&
- socket_address_can_accept(&p->address);
-
- if ((r = unit_watch_fd(UNIT(s), p->fd, EPOLLIN, &p->fd_watch)) < 0)
- goto fail;
- }
-
- return 0;
-
-fail:
- socket_unwatch_fds(s);
- return r;
-}
-
-static void socket_set_state(Socket *s, SocketState state) {
- SocketState old_state;
- assert(s);
-
- old_state = s->state;
- s->state = state;
-
- if (state != SOCKET_START_PRE &&
- state != SOCKET_START_POST &&
- state != SOCKET_STOP_PRE &&
- state != SOCKET_STOP_PRE_SIGTERM &&
- state != SOCKET_STOP_PRE_SIGKILL &&
- state != SOCKET_STOP_POST &&
- state != SOCKET_FINAL_SIGTERM &&
- state != SOCKET_FINAL_SIGKILL) {
- unit_unwatch_timer(UNIT(s), &s->timer_watch);
- 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 (state != SOCKET_START_POST &&
- state != SOCKET_LISTENING &&
- state != SOCKET_RUNNING &&
- state != SOCKET_STOP_PRE &&
- state != SOCKET_STOP_PRE_SIGTERM &&
- state != SOCKET_STOP_PRE_SIGKILL)
- socket_close_fds(s);
-
- if (state != old_state)
- log_debug("%s changed %s -> %s",
- UNIT(s)->id,
- socket_state_to_string(old_state),
- socket_state_to_string(state));
-
- unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
-}
-
-static int socket_coldplug(Unit *u) {
- Socket *s = SOCKET(u);
- int r;
-
- assert(s);
- assert(s->state == SOCKET_DEAD);
-
- if (s->deserialized_state != s->state) {
-
- if (s->deserialized_state == SOCKET_START_PRE ||
- s->deserialized_state == SOCKET_START_POST ||
- s->deserialized_state == SOCKET_STOP_PRE ||
- s->deserialized_state == SOCKET_STOP_PRE_SIGTERM ||
- s->deserialized_state == SOCKET_STOP_PRE_SIGKILL ||
- s->deserialized_state == SOCKET_STOP_POST ||
- s->deserialized_state == SOCKET_FINAL_SIGTERM ||
- s->deserialized_state == SOCKET_FINAL_SIGKILL) {
-
- if (s->control_pid <= 0)
- return -EBADMSG;
-
- if ((r = unit_watch_pid(UNIT(s), s->control_pid)) < 0)
- return r;
-
- if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
- return r;
- }
-
- if (s->deserialized_state == SOCKET_START_POST ||
- s->deserialized_state == SOCKET_LISTENING ||
- s->deserialized_state == SOCKET_RUNNING ||
- s->deserialized_state == SOCKET_STOP_PRE ||
- s->deserialized_state == SOCKET_STOP_PRE_SIGTERM ||
- s->deserialized_state == SOCKET_STOP_PRE_SIGKILL)
- if ((r = socket_open_fds(s)) < 0)
- return r;
-
- if (s->deserialized_state == SOCKET_LISTENING)
- if ((r = socket_watch_fds(s)) < 0)
- return r;
-
- socket_set_state(s, s->deserialized_state);
- }
-
- return 0;
-}
-
-static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
- pid_t pid;
- int r;
- char **argv;
-
- assert(s);
- assert(c);
- assert(_pid);
-
- if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
- goto fail;
-
- if (!(argv = unit_full_printf_strv(UNIT(s), c->argv))) {
- r = -ENOMEM;
- goto fail;
- }
-
- r = exec_spawn(c,
- argv,
- &s->exec_context,
- NULL, 0,
- UNIT(s)->manager->environment,
- true,
- true,
- true,
- UNIT(s)->manager->confirm_spawn,
- UNIT(s)->cgroup_bondings,
- UNIT(s)->cgroup_attributes,
- NULL,
- UNIT(s)->id,
- NULL,
- &pid);
-
- strv_free(argv);
- if (r < 0)
- goto fail;
-
- if ((r = unit_watch_pid(UNIT(s), pid)) < 0)
- /* FIXME: we need to do something here */
- goto fail;
-
- *_pid = pid;
-
- return 0;
-
-fail:
- unit_unwatch_timer(UNIT(s), &s->timer_watch);
-
- return r;
-}
-
-static void socket_enter_dead(Socket *s, SocketResult f) {
- assert(s);
-
- if (f != SOCKET_SUCCESS)
- s->result = f;
-
- 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;
-
- if ((s->control_command = s->exec_command[SOCKET_EXEC_STOP_POST])) {
- if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0)
- goto fail;
-
- socket_set_state(s, SOCKET_STOP_POST);
- } else
- socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_SUCCESS);
-
- return;
-
-fail:
- log_warning("%s failed to run 'stop-post' task: %s", UNIT(s)->id, strerror(-r));
- socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_RESOURCES);
-}
-
-static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
- int r;
- Set *pid_set = NULL;
- bool wait_for_exit = false;
-
- assert(s);
-
- if (f != SOCKET_SUCCESS)
- s->result = f;
-
- if (s->kill_context.kill_mode != KILL_NONE) {
- int sig = (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_FINAL_SIGTERM) ? s->kill_context.kill_signal : SIGKILL;
-
- if (s->control_pid > 0) {
- if (kill_and_sigcont(s->control_pid, sig) < 0 && errno != ESRCH)
-
- log_warning("Failed to kill control process %li: %m", (long) s->control_pid);
- else
- wait_for_exit = true;
- }
-
- if (s->kill_context.kill_mode == KILL_CONTROL_GROUP) {
-
- if (!(pid_set = set_new(trivial_hash_func, trivial_compare_func))) {
- r = -ENOMEM;
- goto fail;
- }
-
- /* Exclude the control pid from being killed via the cgroup */
- if (s->control_pid > 0)
- if ((r = set_put(pid_set, LONG_TO_PTR(s->control_pid))) < 0)
- goto fail;
-
- r = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, sig, true, false, pid_set, NULL);
- if (r < 0) {
- if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
- log_warning("Failed to kill control group: %s", strerror(-r));
- } else if (r > 0)
- wait_for_exit = true;
-
- set_free(pid_set);
- pid_set = NULL;
- }
- }
-
- if (wait_for_exit) {
- if ((r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch)) < 0)
- goto fail;
-
- socket_set_state(s, state);
- } else if (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_STOP_PRE_SIGKILL)
- socket_enter_stop_post(s, SOCKET_SUCCESS);
- else
- socket_enter_dead(s, SOCKET_SUCCESS);
-
- return;
-
-fail:
- log_warning("%s failed to kill processes: %s", UNIT(s)->id, strerror(-r));
-
- 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);
-
- if (pid_set)
- set_free(pid_set);
-}
-
-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;
-
- if ((s->control_command = s->exec_command[SOCKET_EXEC_STOP_PRE])) {
- if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0)
- goto fail;
-
- socket_set_state(s, SOCKET_STOP_PRE);
- } else
- socket_enter_stop_post(s, SOCKET_SUCCESS);
-
- return;
-
-fail:
- log_warning("%s failed to run 'stop-pre' task: %s", UNIT(s)->id, strerror(-r));
- 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_warning("%s failed to watch sockets: %s", UNIT(s)->id, strerror(-r));
- 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);
-
- r = socket_open_fds(s);
- if (r < 0) {
- log_warning("%s failed to listen on sockets: %s", UNIT(s)->id, strerror(-r));
- goto fail;
- }
-
- socket_unwatch_control_pid(s);
-
- s->control_command_id = SOCKET_EXEC_START_POST;
-
- if ((s->control_command = s->exec_command[SOCKET_EXEC_START_POST])) {
- r = socket_spawn(s, s->control_command, &s->control_pid);
- if (r < 0) {
- log_warning("%s failed to run 'start-post' task: %s", UNIT(s)->id, strerror(-r));
- 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_pre(Socket *s) {
- int r;
- assert(s);
-
- socket_unwatch_control_pid(s);
-
- s->control_command_id = SOCKET_EXEC_START_PRE;
-
- if ((s->control_command = s->exec_command[SOCKET_EXEC_START_PRE])) {
- if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0)
- goto fail;
-
- socket_set_state(s, SOCKET_START_PRE);
- } else
- socket_enter_start_post(s);
-
- return;
-
-fail:
- log_warning("%s failed to run 'start-pre' task: %s", UNIT(s)->id, strerror(-r));
- socket_enter_dead(s, SOCKET_FAILURE_RESOURCES);
-}
-
-static void socket_enter_running(Socket *s, int cfd) {
- int r;
- DBusError error;
-
- assert(s);
- dbus_error_init(&error);
-
- /* We don't take connections anymore if we are supposed to
- * shut down anyway */
- if (unit_pending_inactive(UNIT(s))) {
- log_debug("Suppressing connection request on %s since unit stop is scheduled.", UNIT(s)->id);
-
- if (cfd >= 0)
- close_nointr_nofail(cfd);
- else {
- /* Flush all sockets by closing and reopening them */
- socket_close_fds(s);
-
- r = socket_watch_fds(s);
- if (r < 0) {
- log_warning("%s failed to watch sockets: %s", UNIT(s)->id, strerror(-r));
- socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
- }
- }
-
- return;
- }
-
- if (cfd < 0) {
- Iterator i;
- Unit *u;
- bool pending = false;
-
- /* If there's already a start pending don't bother to
- * do anything */
- SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERS], i)
- if (unit_pending_active(u)) {
- pending = true;
- break;
- }
-
- if (!pending) {
- r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT_DEREF(s->service), JOB_REPLACE, true, &error, NULL);
- if (r < 0)
- goto fail;
- }
-
- socket_set_state(s, SOCKET_RUNNING);
- } else {
- char *prefix, *instance = NULL, *name;
- Service *service;
-
- if (s->n_connections >= s->max_connections) {
- log_warning("Too many incoming connections (%u)", s->n_connections);
- close_nointr_nofail(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. */
- close_nointr_nofail(cfd);
- return;
- }
-
- prefix = unit_name_to_prefix(UNIT(s)->id);
- if (!prefix) {
- free(instance);
- r = -ENOMEM;
- goto fail;
- }
-
- name = unit_name_build(prefix, instance, ".service");
- free(prefix);
- free(instance);
-
- if (!name) {
- r = -ENOMEM;
- goto fail;
- }
-
- r = unit_add_name(UNIT_DEREF(s->service), name);
- if (r < 0) {
- free(name);
- 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);
- free(name);
-
- r = service_set_socket_fd(service, cfd, s);
- if (r < 0)
- goto fail;
-
- cfd = -1;
- s->n_connections ++;
-
- r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, true, &error, NULL);
- if (r < 0)
- goto fail;
-
- /* Notify clients about changed counters */
- unit_add_to_dbus_queue(UNIT(s));
- }
-
- return;
-
-fail:
- log_warning("%s failed to queue socket startup job: %s", UNIT(s)->id, bus_error(&error, r));
- socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
-
- if (cfd >= 0)
- close_nointr_nofail(cfd);
-
- dbus_error_free(&error);
-}
-
-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;
-
- if ((r = socket_spawn(s, s->control_command, &s->control_pid)) < 0)
- goto fail;
-
- return;
-
-fail:
- log_warning("%s failed to run next task: %s", UNIT(s)->id, strerror(-r));
-
- 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 (s->state == SOCKET_STOP_PRE ||
- s->state == SOCKET_STOP_PRE_SIGKILL ||
- s->state == SOCKET_STOP_PRE_SIGTERM ||
- s->state == SOCKET_STOP_POST ||
- s->state == SOCKET_FINAL_SIGTERM ||
- s->state == SOCKET_FINAL_SIGKILL)
- return -EAGAIN;
-
- if (s->state == SOCKET_START_PRE ||
- s->state == SOCKET_START_POST)
- return 0;
-
- /* Cannot run this without the service being around */
- if (UNIT_DEREF(s->service)) {
- Service *service;
-
- service = SERVICE(UNIT_DEREF(s->service));
-
- if (UNIT(service)->load_state != UNIT_LOADED) {
- log_error("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_error("Socket service %s already active, refusing.", UNIT(service)->id);
- return -EBUSY;
- }
-
-#ifdef HAVE_SYSV_COMPAT
- if (service->is_sysv) {
- log_error("Using SysV services for socket activation is not supported. Refusing.");
- return -ENOENT;
- }
-#endif
- }
-
- assert(s->state == SOCKET_DEAD || s->state == SOCKET_FAILED);
-
- s->result = SOCKET_SUCCESS;
- socket_enter_start_pre(s);
- return 0;
-}
-
-static int socket_stop(Unit *u) {
- Socket *s = SOCKET(u);
-
- assert(s);
-
- /* Already on it */
- if (s->state == SOCKET_STOP_PRE ||
- s->state == SOCKET_STOP_PRE_SIGTERM ||
- s->state == SOCKET_STOP_PRE_SIGKILL ||
- s->state == SOCKET_STOP_POST ||
- s->state == SOCKET_FINAL_SIGTERM ||
- s->state == SOCKET_FINAL_SIGKILL)
- return 0;
-
- /* If there's already something running we go directly into
- * kill mode. */
- if (s->state == SOCKET_START_PRE ||
- s->state == 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 0;
-}
-
-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", "%lu", (unsigned long) 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;
-
- if ((copy = fdset_put_dup(fds, p->fd)) < 0)
- return copy;
-
- if (p->type == SOCKET_SOCKET) {
- char *t;
-
- if ((r = socket_address_print(&p->address, &t)) < 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);
- free(t);
- } else if (p->type == SOCKET_SPECIAL)
- unit_serialize_item_format(u, f, "special", "%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);
- assert(fds);
-
- if (streq(key, "state")) {
- SocketState state;
-
- if ((state = socket_state_from_string(value)) < 0)
- log_debug("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_debug("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_debug("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_debug("Failed to parse control-pid value %s", value);
- else
- s->control_pid = pid;
- } else if (streq(key, "control-command")) {
- SocketExecCommand id;
-
- if ((id = socket_exec_command_from_string(value)) < 0)
- log_debug("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_debug("Failed to parse fifo value %s", value);
- else {
-
- LIST_FOREACH(port, p, s->ports)
- if (p->type == SOCKET_FIFO &&
- streq_ptr(p->path, value+skip))
- break;
-
- if (p) {
- if (p->fd >= 0)
- close_nointr_nofail(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_debug("Failed to parse special value %s", value);
- else {
-
- LIST_FOREACH(port, p, s->ports)
- if (p->type == SOCKET_SPECIAL &&
- streq_ptr(p->path, value+skip))
- break;
-
- if (p) {
- if (p->fd >= 0)
- close_nointr_nofail(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_debug("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) {
- if (p->fd >= 0)
- close_nointr_nofail(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_debug("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) {
- if (p->fd >= 0)
- close_nointr_nofail(p->fd);
- p->fd = fdset_remove(fds, fd);
- }
- }
-
- } else
- log_debug("Unknown serialization key '%s'", key);
-
- return 0;
-}
-
-static UnitActiveState socket_active_state(Unit *u) {
- assert(u);
-
- return state_translation_table[SOCKET(u)->state];
-}
-
-static const char *socket_sub_state_to_string(Unit *u) {
- assert(u);
-
- return socket_state_to_string(SOCKET(u)->state);
-}
-
-static bool socket_check_gc(Unit *u) {
- Socket *s = SOCKET(u);
-
- assert(u);
-
- return s->n_connections > 0;
-}
-
-static void socket_fd_event(Unit *u, int fd, uint32_t events, Watch *w) {
- Socket *s = SOCKET(u);
- int cfd = -1;
-
- assert(s);
- assert(fd >= 0);
-
- if (s->state != SOCKET_LISTENING)
- return;
-
- log_debug("Incoming traffic on %s", u->id);
-
- if (events != EPOLLIN) {
-
- if (events & EPOLLHUP)
- log_error("%s: Got POLLHUP on a listening socket. The service probably invoked shutdown() on it, and should better not do that.", u->id);
- else
- log_error("%s: Got unexpected poll event (0x%x) on socket.", u->id, events);
-
- goto fail;
- }
-
- if (w->socket_accept) {
- for (;;) {
-
- cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK);
- if (cfd < 0) {
-
- if (errno == EINTR)
- continue;
-
- log_error("Failed to accept socket: %m");
- goto fail;
- }
-
- break;
- }
-
- socket_apply_socket_options(s, cfd);
- }
-
- socket_enter_running(s, cfd);
- return;
-
-fail:
- socket_enter_stop_pre(s, SOCKET_FAILURE_RESOURCES);
-}
-
-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 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_full(f == SOCKET_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
- "%s control process exited, code=%s status=%i", u->id, sigchld_code_to_string(code), status);
-
- if (f != SOCKET_SUCCESS)
- s->result = f;
-
- if (s->control_command &&
- s->control_command->command_next &&
- f == SOCKET_SUCCESS) {
-
- log_debug("%s running next command for state %s", u->id, socket_state_to_string(s->state));
- socket_run_next(s);
- } else {
- s->control_command = NULL;
- s->control_command_id = _SOCKET_EXEC_COMMAND_INVALID;
-
- /* No further commands for this step, so let's figure
- * out what to do next */
-
- log_debug("%s got final SIGCHLD for state %s", u->id, socket_state_to_string(s->state));
-
- switch (s->state) {
-
- case SOCKET_START_PRE:
- if (f == SOCKET_SUCCESS)
- socket_enter_start_post(s);
- else
- socket_enter_signal(s, SOCKET_FINAL_SIGTERM, 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 void socket_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
- Socket *s = SOCKET(u);
-
- assert(s);
- assert(elapsed == 1);
- assert(w == &s->timer_watch);
-
- switch (s->state) {
-
- case SOCKET_START_PRE:
- log_warning("%s starting timed out. Terminating.", u->id);
- socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_TIMEOUT);
- break;
-
- case SOCKET_START_POST:
- log_warning("%s starting timed out. Stopping.", u->id);
- socket_enter_stop_pre(s, SOCKET_FAILURE_TIMEOUT);
- break;
-
- case SOCKET_STOP_PRE:
- log_warning("%s stopping timed out. Terminating.", u->id);
- socket_enter_signal(s, SOCKET_STOP_PRE_SIGTERM, SOCKET_FAILURE_TIMEOUT);
- break;
-
- case SOCKET_STOP_PRE_SIGTERM:
- if (s->kill_context.send_sigkill) {
- log_warning("%s stopping timed out. Killing.", u->id);
- socket_enter_signal(s, SOCKET_STOP_PRE_SIGKILL, SOCKET_FAILURE_TIMEOUT);
- } else {
- log_warning("%s stopping timed out. Skipping SIGKILL. Ignoring.", u->id);
- socket_enter_stop_post(s, SOCKET_FAILURE_TIMEOUT);
- }
- break;
-
- case SOCKET_STOP_PRE_SIGKILL:
- log_warning("%s still around after SIGKILL. Ignoring.", u->id);
- socket_enter_stop_post(s, SOCKET_FAILURE_TIMEOUT);
- break;
-
- case SOCKET_STOP_POST:
- log_warning("%s stopping timed out (2). Terminating.", u->id);
- socket_enter_signal(s, SOCKET_FINAL_SIGTERM, SOCKET_FAILURE_TIMEOUT);
- break;
-
- case SOCKET_FINAL_SIGTERM:
- if (s->kill_context.send_sigkill) {
- log_warning("%s stopping timed out (2). Killing.", u->id);
- socket_enter_signal(s, SOCKET_FINAL_SIGKILL, SOCKET_FAILURE_TIMEOUT);
- } else {
- log_warning("%s stopping timed out (2). Skipping SIGKILL. Ignoring.", u->id);
- socket_enter_dead(s, SOCKET_FAILURE_TIMEOUT);
- }
- break;
-
- case SOCKET_FINAL_SIGKILL:
- log_warning("%s still around after SIGKILL (2). Entering failed mode.", u->id);
- socket_enter_dead(s, SOCKET_FAILURE_TIMEOUT);
- break;
-
- default:
- assert_not_reached("Timeout at wrong time.");
- }
-}
-
-int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds) {
- int *rfds;
- unsigned rn_fds, k;
- SocketPort *p;
-
- assert(s);
- assert(fds);
- assert(n_fds);
-
- /* Called from the service code for requesting our fds */
-
- rn_fds = 0;
- LIST_FOREACH(port, p, s->ports)
- if (p->fd >= 0)
- rn_fds++;
-
- if (rn_fds <= 0) {
- *fds = NULL;
- *n_fds = 0;
- return 0;
- }
-
- if (!(rfds = new(int, rn_fds)))
- return -ENOMEM;
-
- k = 0;
- LIST_FOREACH(port, p, s->ports)
- if (p->fd >= 0)
- rfds[k++] = p->fd;
-
- assert(k == rn_fds);
-
- *fds = rfds;
- *n_fds = rn_fds;
-
- return 0;
-}
-
-void socket_notify_service_dead(Socket *s, bool failed_permanent) {
- assert(s);
-
- /* The service is dead. Dang!
- *
- * This is strictly for one-instance-for-all-connections
- * services. */
-
- if (s->state == SOCKET_RUNNING) {
- log_debug("%s got notified about service death (failed permanently: %s)", UNIT(s)->id, yes_no(failed_permanent));
- if (failed_permanent)
- socket_enter_stop_pre(s, SOCKET_FAILURE_SERVICE_FAILED_PERMANENT);
- else
- socket_enter_listening(s);
- }
-}
-
-void socket_connection_unref(Socket *s) {
- assert(s);
-
- /* The service is dead. Yay!
- *
- * This is strictly for one-instance-per-connection
- * services. */
-
- assert(s->n_connections > 0);
- s->n_connections--;
-
- log_debug("%s: One connection closed, %u left.", UNIT(s)->id, s->n_connections);
-}
-
-static void socket_reset_failed(Unit *u) {
- Socket *s = SOCKET(u);
-
- assert(s);
-
- if (s->state == SOCKET_FAILED)
- socket_set_state(s, SOCKET_DEAD);
-
- s->result = SOCKET_SUCCESS;
-}
-
-static int socket_kill(Unit *u, KillWho who, int signo, DBusError *error) {
- Socket *s = SOCKET(u);
- int r = 0;
- Set *pid_set = NULL;
-
- assert(s);
-
- if (who == KILL_MAIN) {
- dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "Socket units have no main processes");
- return -ESRCH;
- }
-
- if (s->control_pid <= 0 && who == KILL_CONTROL) {
- dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
- return -ESRCH;
- }
-
- if (who == KILL_CONTROL || who == KILL_ALL)
- if (s->control_pid > 0)
- if (kill(s->control_pid, signo) < 0)
- r = -errno;
-
- if (who == KILL_ALL) {
- int q;
-
- pid_set = set_new(trivial_hash_func, trivial_compare_func);
- if (!pid_set)
- return -ENOMEM;
-
- /* Exclude the control pid from being killed via the cgroup */
- if (s->control_pid > 0) {
- q = set_put(pid_set, LONG_TO_PTR(s->control_pid));
- if (q < 0) {
- r = q;
- goto finish;
- }
- }
-
- q = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, signo, false, false, pid_set, NULL);
- if (q < 0 && q != -EAGAIN && q != -ESRCH && q != -ENOENT)
- r = q;
- }
-
-finish:
- if (pid_set)
- set_free(pid_set);
-
- return r;
-}
-
-static const char* const socket_state_table[_SOCKET_STATE_MAX] = {
- [SOCKET_DEAD] = "dead",
- [SOCKET_START_PRE] = "start-pre",
- [SOCKET_START_POST] = "start-post",
- [SOCKET_LISTENING] = "listening",
- [SOCKET_RUNNING] = "running",
- [SOCKET_STOP_PRE] = "stop-pre",
- [SOCKET_STOP_PRE_SIGTERM] = "stop-pre-sigterm",
- [SOCKET_STOP_PRE_SIGKILL] = "stop-pre-sigkill",
- [SOCKET_STOP_POST] = "stop-post",
- [SOCKET_FINAL_SIGTERM] = "final-sigterm",
- [SOCKET_FINAL_SIGKILL] = "final-sigkill",
- [SOCKET_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(socket_state, SocketState);
-
-static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = {
- [SOCKET_EXEC_START_PRE] = "StartPre",
- [SOCKET_EXEC_START_POST] = "StartPost",
- [SOCKET_EXEC_STOP_PRE] = "StopPre",
- [SOCKET_EXEC_STOP_POST] = "StopPost"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(socket_exec_command, SocketExecCommand);
-
-static const char* const socket_result_table[_SOCKET_RESULT_MAX] = {
- [SOCKET_SUCCESS] = "success",
- [SOCKET_FAILURE_RESOURCES] = "resources",
- [SOCKET_FAILURE_TIMEOUT] = "timeout",
- [SOCKET_FAILURE_EXIT_CODE] = "exit-code",
- [SOCKET_FAILURE_SIGNAL] = "signal",
- [SOCKET_FAILURE_CORE_DUMP] = "core-dump",
- [SOCKET_FAILURE_SERVICE_FAILED_PERMANENT] = "service-failed-permanent"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(socket_result, SocketResult);
-
-const UnitVTable socket_vtable = {
- .object_size = sizeof(Socket),
- .exec_context_offset = offsetof(Socket, exec_context),
-
- .sections =
- "Unit\0"
- "Socket\0"
- "Install\0",
-
- .init = socket_init,
- .done = socket_done,
- .load = socket_load,
-
- .kill = socket_kill,
-
- .coldplug = socket_coldplug,
-
- .dump = socket_dump,
-
- .start = socket_start,
- .stop = socket_stop,
-
- .serialize = socket_serialize,
- .deserialize_item = socket_deserialize_item,
-
- .active_state = socket_active_state,
- .sub_state_to_string = socket_sub_state_to_string,
-
- .check_gc = socket_check_gc,
-
- .fd_event = socket_fd_event,
- .sigchld_event = socket_sigchld_event,
- .timer_event = socket_timer_event,
-
- .reset_failed = socket_reset_failed,
-
- .bus_interface = "org.freedesktop.systemd1.Socket",
- .bus_message_handler = bus_socket_message_handler,
- .bus_invalidating_properties = bus_socket_invalidating_properties,
-
- .status_message_formats = {
- /*.starting_stopping = {
- [0] = "Starting socket %s...",
- [1] = "Stopping socket %s...",
- },*/
- .finished_start_job = {
- [JOB_DONE] = "Listening on %s.",
- [JOB_FAILED] = "Failed to listen on %s.",
- [JOB_DEPENDENCY] = "Dependency failed for %s.",
- [JOB_TIMEOUT] = "Timed out starting %s.",
- },
- .finished_stop_job = {
- [JOB_DONE] = "Closed %s.",
- [JOB_FAILED] = "Failed stopping %s.",
- [JOB_TIMEOUT] = "Timed out stopping %s.",
- },
- },
-};
diff --git a/src/core/socket.h b/src/core/socket.h
deleted file mode 100644
index f099520dce..0000000000
--- a/src/core/socket.h
+++ /dev/null
@@ -1,175 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct Socket Socket;
-
-#include "manager.h"
-#include "unit.h"
-#include "socket-util.h"
-#include "mount.h"
-#include "service.h"
-
-typedef enum SocketState {
- SOCKET_DEAD,
- SOCKET_START_PRE,
- SOCKET_START_POST,
- SOCKET_LISTENING,
- SOCKET_RUNNING,
- SOCKET_STOP_PRE,
- SOCKET_STOP_PRE_SIGTERM,
- SOCKET_STOP_PRE_SIGKILL,
- SOCKET_STOP_POST,
- SOCKET_FINAL_SIGTERM,
- SOCKET_FINAL_SIGKILL,
- SOCKET_FAILED,
- _SOCKET_STATE_MAX,
- _SOCKET_STATE_INVALID = -1
-} SocketState;
-
-typedef enum SocketExecCommand {
- SOCKET_EXEC_START_PRE,
- SOCKET_EXEC_START_POST,
- SOCKET_EXEC_STOP_PRE,
- SOCKET_EXEC_STOP_POST,
- _SOCKET_EXEC_COMMAND_MAX,
- _SOCKET_EXEC_COMMAND_INVALID = -1
-} SocketExecCommand;
-
-typedef enum SocketType {
- SOCKET_SOCKET,
- SOCKET_FIFO,
- SOCKET_SPECIAL,
- SOCKET_MQUEUE,
- _SOCKET_FIFO_MAX,
- _SOCKET_FIFO_INVALID = -1
-} SocketType;
-
-typedef enum SocketResult {
- SOCKET_SUCCESS,
- SOCKET_FAILURE_RESOURCES,
- SOCKET_FAILURE_TIMEOUT,
- SOCKET_FAILURE_EXIT_CODE,
- SOCKET_FAILURE_SIGNAL,
- SOCKET_FAILURE_CORE_DUMP,
- SOCKET_FAILURE_SERVICE_FAILED_PERMANENT,
- _SOCKET_RESULT_MAX,
- _SOCKET_RESULT_INVALID = -1
-} SocketResult;
-
-typedef struct SocketPort {
- SocketType type;
- int fd;
-
- SocketAddress address;
- char *path;
- Watch fd_watch;
-
- 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;
- usec_t timeout_usec;
-
- ExecCommand* exec_command[_SOCKET_EXEC_COMMAND_MAX];
- ExecContext exec_context;
- KillContext kill_context;
-
- /* 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;
-
- Watch timer_watch;
-
- ExecCommand* control_command;
- SocketExecCommand control_command_id;
- pid_t control_pid;
-
- mode_t directory_mode;
- mode_t socket_mode;
-
- SocketResult result;
-
- bool accept;
-
- /* Socket options */
- bool keep_alive;
- bool free_bind;
- bool transparent;
- bool broadcast;
- bool pass_cred;
- bool pass_sec;
- 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;
- long mq_maxmsg;
- long mq_msgsize;
-
- /* Only for INET6 sockets: issue IPV6_V6ONLY sockopt */
- SocketAddressBindIPv6Only bind_ipv6_only;
-
- char *smack;
- char *smack_ip_in;
- char *smack_ip_out;
-};
-
-/* Called from the service code when collecting fds */
-int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds);
-
-/* Called from the service when it shut down */
-void socket_notify_service_dead(Socket *s, bool failed_permanent);
-
-/* Called from the mount code figure out if a mount is a dependency of
- * any of the sockets of this socket */
-int socket_add_one_mount_link(Socket *s, Mount *m);
-
-/* Called from the service code when a per-connection service ended */
-void socket_connection_unref(Socket *s);
-
-extern const UnitVTable socket_vtable;
-
-const char* socket_state_to_string(SocketState i);
-SocketState socket_state_from_string(const char *s);
-
-const char* socket_exec_command_to_string(SocketExecCommand i);
-SocketExecCommand socket_exec_command_from_string(const char *s);
-
-const char* socket_result_to_string(SocketResult i);
-SocketResult socket_result_from_string(const char *s);
diff --git a/src/core/special.h b/src/core/special.h
deleted file mode 100644
index ef72260ecd..0000000000
--- a/src/core/special.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#define SPECIAL_DEFAULT_TARGET "default.target"
-
-/* Shutdown targets */
-#define SPECIAL_UMOUNT_TARGET "umount.target"
-/* This is not really intended to be started by directly. This is
- * mostly so that other targets (reboot/halt/poweroff) can depend on
- * it to bring all services down that want to be brought down on
- * system shutdown. */
-#define SPECIAL_SHUTDOWN_TARGET "shutdown.target"
-#define SPECIAL_HALT_TARGET "halt.target"
-#define SPECIAL_POWEROFF_TARGET "poweroff.target"
-#define SPECIAL_REBOOT_TARGET "reboot.target"
-#define SPECIAL_KEXEC_TARGET "kexec.target"
-#define SPECIAL_EXIT_TARGET "exit.target"
-#define SPECIAL_SUSPEND_TARGET "suspend.target"
-#define SPECIAL_HIBERNATE_TARGET "hibernate.target"
-#define SPECIAL_HYBRID_SLEEP_TARGET "hybrid-sleep.target"
-
-/* Special boot targets */
-#define SPECIAL_RESCUE_TARGET "rescue.target"
-#define SPECIAL_EMERGENCY_TARGET "emergency.target"
-
-/* Early boot targets */
-#define SPECIAL_SYSINIT_TARGET "sysinit.target"
-#define SPECIAL_SOCKETS_TARGET "sockets.target"
-#define SPECIAL_LOCAL_FS_TARGET "local-fs.target" /* LSB's $local_fs */
-#define SPECIAL_LOCAL_FS_PRE_TARGET "local-fs-pre.target"
-#define SPECIAL_REMOTE_FS_TARGET "remote-fs.target" /* LSB's $remote_fs */
-#define SPECIAL_REMOTE_FS_PRE_TARGET "remote-fs-pre.target"
-#define SPECIAL_SWAP_TARGET "swap.target"
-#define SPECIAL_BASIC_TARGET "basic.target"
-
-/* LSB compatibility */
-#define SPECIAL_NETWORK_TARGET "network.target" /* LSB's $network */
-#define SPECIAL_NSS_LOOKUP_TARGET "nss-lookup.target" /* LSB's $named */
-#define SPECIAL_RPCBIND_TARGET "rpcbind.target" /* LSB's $portmap */
-#define SPECIAL_SYSLOG_TARGET "syslog.target" /* LSB's $syslog */
-#define SPECIAL_TIME_SYNC_TARGET "time-sync.target" /* LSB's $time */
-#define SPECIAL_DISPLAY_MANAGER_SERVICE "display-manager.service" /* Common extension of LSB */
-#define SPECIAL_MAIL_TRANSFER_AGENT_TARGET "mail-transfer-agent.target" /* Common extension of LSB */
-
-/*
- * Rules regarding adding further high level targets like the above:
- *
- * - Be conservative, only add more of these when we really need
- * them. We need strong usecases for further additions.
- *
- * - When there can be multiple implementations running side-by-side,
- * it needs to be a .target unit which can pull in all
- * implementations.
- *
- * - If something can be implemented with socket activation, and
- * without, it needs to be a .target unit, so that it can pull in
- * the appropriate unit.
- *
- * - Otherwise, it should be a .service unit.
- *
- * - In some cases it is OK to have both a .service and a .target
- * unit, i.e. if there can be multiple parallel implementations, but
- * only one is the "system" one. Example: syslog.
- *
- * Or to put this in other words: .service symlinks can be used to
- * arbitrate between multiple implementations if there can be only one
- * of a kind. .target units can be used to support multiple
- * implementations that can run side-by-side.
- */
-
-/* Magic early boot services */
-#define SPECIAL_FSCK_SERVICE "systemd-fsck@.service"
-#define SPECIAL_QUOTACHECK_SERVICE "systemd-quotacheck.service"
-#define SPECIAL_QUOTAON_SERVICE "quotaon.service"
-#define SPECIAL_REMOUNT_FS_SERVICE "systemd-remount-fs.service"
-
-/* Services systemd relies on */
-#define SPECIAL_DBUS_SERVICE "dbus.service"
-#define SPECIAL_DBUS_SOCKET "dbus.socket"
-#define SPECIAL_JOURNALD_SOCKET "systemd-journald.socket"
-#define SPECIAL_JOURNALD_SERVICE "systemd-journald.service"
-
-/* Magic init signals */
-#define SPECIAL_KBREQUEST_TARGET "kbrequest.target"
-#define SPECIAL_SIGPWR_TARGET "sigpwr.target"
-#define SPECIAL_CTRL_ALT_DEL_TARGET "ctrl-alt-del.target"
-
-/* For SysV compatibility. Usually an alias for a saner target. On
- * SysV-free systems this doesn't exist. */
-#define SPECIAL_RUNLEVEL2_TARGET "runlevel2.target"
-#define SPECIAL_RUNLEVEL3_TARGET "runlevel3.target"
-#define SPECIAL_RUNLEVEL4_TARGET "runlevel4.target"
-#define SPECIAL_RUNLEVEL5_TARGET "runlevel5.target"
diff --git a/src/core/swap.c b/src/core/swap.c
deleted file mode 100644
index 97145a9974..0000000000
--- a/src/core/swap.c
+++ /dev/null
@@ -1,1433 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <limits.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <sys/epoll.h>
-#include <sys/stat.h>
-#include <sys/swap.h>
-#include <libudev.h>
-
-#include "unit.h"
-#include "swap.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
-#include "unit-name.h"
-#include "dbus-swap.h"
-#include "special.h"
-#include "bus-errors.h"
-#include "exit-status.h"
-#include "def.h"
-#include "path-util.h"
-#include "virt.h"
-
-static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = {
- [SWAP_DEAD] = UNIT_INACTIVE,
- [SWAP_ACTIVATING] = UNIT_ACTIVATING,
- [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 void swap_unset_proc_swaps(Swap *s) {
- Swap *first;
- Hashmap *swaps;
-
- assert(s);
-
- if (!s->parameters_proc_swaps.what)
- return;
-
- /* Remove this unit from the chain of swaps which share the
- * same kernel swap device. */
- swaps = UNIT(s)->manager->swaps_by_proc_swaps;
- first = hashmap_get(swaps, s->parameters_proc_swaps.what);
- LIST_REMOVE(Swap, same_proc_swaps, first, s);
-
- if (first)
- hashmap_remove_and_replace(swaps,
- s->parameters_proc_swaps.what,
- first->parameters_proc_swaps.what,
- first);
- else
- hashmap_remove(swaps, s->parameters_proc_swaps.what);
-
- free(s->parameters_proc_swaps.what);
- s->parameters_proc_swaps.what = NULL;
-}
-
-static void swap_init(Unit *u) {
- Swap *s = SWAP(u);
-
- assert(s);
- assert(UNIT(s)->load_state == UNIT_STUB);
-
- s->timeout_usec = DEFAULT_TIMEOUT_USEC;
-
- exec_context_init(&s->exec_context);
- s->exec_context.std_output = u->manager->default_std_output;
- s->exec_context.std_error = u->manager->default_std_error;
- kill_context_init(&s->kill_context);
-
- s->parameters_proc_swaps.priority = s->parameters_fragment.priority = -1;
-
- s->timer_watch.type = WATCH_INVALID;
-
- s->control_command_id = _SWAP_EXEC_COMMAND_INVALID;
-
- UNIT(s)->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);
-
- free(s->what);
- s->what = NULL;
-
- free(s->parameters_fragment.what);
- s->parameters_fragment.what = NULL;
-
- exec_context_done(&s->exec_context);
- exec_command_done_array(s->exec_command, _SWAP_EXEC_COMMAND_MAX);
- s->control_command = NULL;
-
- swap_unwatch_control_pid(s);
-
- unit_unwatch_timer(u, &s->timer_watch);
-}
-
-int swap_add_one_mount_link(Swap *s, Mount *m) {
- int r;
-
- assert(s);
- assert(m);
-
- if (UNIT(s)->load_state != UNIT_LOADED ||
- UNIT(m)->load_state != UNIT_LOADED)
- return 0;
-
- if (is_device_path(s->what))
- return 0;
-
- if (!path_startswith(s->what, m->where))
- return 0;
-
- r = unit_add_two_dependencies(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-static int swap_add_mount_links(Swap *s) {
- Unit *other;
- int r;
-
- assert(s);
-
- LIST_FOREACH(units_by_type, other, UNIT(s)->manager->units_by_type[UNIT_MOUNT])
- if ((r = swap_add_one_mount_link(s, MOUNT(other))) < 0)
- return r;
-
- return 0;
-}
-
-static int swap_add_device_links(Swap *s) {
- SwapParameters *p;
-
- assert(s);
-
- if (!s->what)
- return 0;
-
- if (s->from_fragment)
- p = &s->parameters_fragment;
- else
- return 0;
-
- if (is_device_path(s->what))
- return unit_add_node_link(UNIT(s), s->what,
- !p->noauto && p->nofail &&
- UNIT(s)->manager->running_as == SYSTEMD_SYSTEM);
- else
- /* File based swap devices need to be ordered after
- * systemd-remount-fs.service, since they might need a
- * writable file system. */
- return unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_REMOUNT_FS_SERVICE, NULL, true);
-}
-
-static int swap_add_default_dependencies(Swap *s) {
- int r;
-
- assert(s);
-
- if (UNIT(s)->manager->running_as != SYSTEMD_SYSTEM)
- return 0;
-
- if (detect_container(NULL) > 0)
- return 0;
-
- r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
- if (r < 0)
- return r;
-
- return 0;
-}
-
-static int swap_verify(Swap *s) {
- bool b;
- char _cleanup_free_ *e = NULL;
-
- if (UNIT(s)->load_state != UNIT_LOADED)
- return 0;
-
- e = unit_name_from_path(s->what, ".swap");
- if (e == NULL)
- return log_oom();
-
- b = unit_has_name(UNIT(s), e);
- if (!b) {
- log_error("%s: Value of \"What\" and unit name do not match, not loading.", UNIT(s)->id);
- return -EINVAL;
- }
-
- if (s->exec_context.pam_name && s->kill_context.kill_mode != KILL_CONTROL_GROUP) {
- log_error("%s has PAM enabled. Kill mode must be set to 'control-group'. Refusing to load.", UNIT(s)->id);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int swap_load(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) {
- r = unit_add_exec_dependencies(u, &s->exec_context);
- if (r < 0)
- return r;
-
- if (UNIT(s)->fragment_path)
- s->from_fragment = true;
-
- if (!s->what) {
- if (s->parameters_fragment.what)
- s->what = strdup(s->parameters_fragment.what);
- else if (s->parameters_proc_swaps.what)
- s->what = strdup(s->parameters_proc_swaps.what);
- else
- s->what = unit_name_to_path(u->id);
-
- if (!s->what)
- return -ENOMEM;
- }
-
- path_kill_slashes(s->what);
-
- if (!UNIT(s)->description)
- if ((r = unit_set_description(u, s->what)) < 0)
- return r;
-
- r = swap_add_device_links(s);
- if (r < 0)
- return r;
-
- r = swap_add_mount_links(s);
- if (r < 0)
- return r;
-
- r = unit_add_default_cgroups(u);
- if (r < 0)
- return r;
-
- if (UNIT(s)->default_dependencies) {
- r = swap_add_default_dependencies(s);
- if (r < 0)
- return r;
- }
-
- r = unit_exec_context_defaults(u, &s->exec_context);
- if (r < 0)
- return r;
- }
-
- return swap_verify(s);
-}
-
-static int swap_add_one(
- Manager *m,
- const char *what,
- const char *what_proc_swaps,
- int priority,
- bool noauto,
- bool nofail,
- bool set_flags) {
-
- Unit *u = NULL;
- char _cleanup_free_ *e = NULL;
- char *wp = NULL;
- bool delete = false;
- int r;
- SwapParameters *p;
- Swap *first;
-
- assert(m);
- assert(what);
- assert(what_proc_swaps);
-
- e = unit_name_from_path(what, ".swap");
- if (!e)
- return log_oom();
-
- u = manager_get_unit(m, e);
-
- if (u &&
- SWAP(u)->from_proc_swaps &&
- !path_equal(SWAP(u)->parameters_proc_swaps.what, what_proc_swaps))
- 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 = log_oom();
- goto fail;
- }
-
- unit_add_to_load_queue(u);
- } else
- delete = false;
-
- p = &SWAP(u)->parameters_proc_swaps;
-
- if (!p->what) {
- wp = strdup(what_proc_swaps);
- if (!wp) {
- r = log_oom();
- goto fail;
- }
-
- if (!m->swaps_by_proc_swaps) {
- m->swaps_by_proc_swaps = hashmap_new(string_hash_func, string_compare_func);
- if (!m->swaps_by_proc_swaps) {
- r = log_oom();
- goto fail;
- }
- }
-
- free(p->what);
- p->what = wp;
-
- first = hashmap_get(m->swaps_by_proc_swaps, wp);
- LIST_PREPEND(Swap, same_proc_swaps, first, SWAP(u));
-
- r = hashmap_replace(m->swaps_by_proc_swaps, wp, first);
- if (r < 0)
- 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;
- p->noauto = noauto;
- p->nofail = nofail;
-
- unit_add_to_dbus_queue(u);
-
- return 0;
-
-fail:
- log_warning("Failed to load swap unit: %s", strerror(-r));
-
- free(wp);
-
- if (delete && u)
- unit_free(u);
-
- return r;
-}
-
-static int swap_process_new_swap(Manager *m, const char *device, int prio, bool set_flags) {
- struct stat st;
- int r = 0, k;
-
- assert(m);
-
- if (stat(device, &st) >= 0 && S_ISBLK(st.st_mode)) {
- struct udev_device *d;
- const char *dn;
- struct udev_list_entry *item = NULL, *first = NULL;
-
- /* So this is a proper swap device. Create swap units
- * for all names this swap device is known under */
-
- d = udev_device_new_from_devnum(m->udev, 'b', st.st_rdev);
- if (!d)
- return log_oom();
-
- dn = udev_device_get_devnode(d);
- /* Skip dn==device, since that case will be handled below */
- if (dn && !streq(dn, device))
- r = swap_add_one(m, dn, device, prio, false, false, 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 (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;
-
- k = swap_add_one(m, p, device, prio, false, false, set_flags);
- if (k < 0)
- r = k;
- }
-
- udev_device_unref(d);
- }
-
- k = swap_add_one(m, device, device, prio, false, false, set_flags);
- if (k < 0)
- r = k;
-
- return r;
-}
-
-static void swap_set_state(Swap *s, SwapState state) {
- SwapState old_state;
-
- assert(s);
-
- old_state = s->state;
- s->state = state;
-
- if (state != SWAP_ACTIVATING &&
- state != SWAP_ACTIVATING_SIGTERM &&
- state != SWAP_ACTIVATING_SIGKILL &&
- state != SWAP_DEACTIVATING &&
- state != SWAP_DEACTIVATING_SIGTERM &&
- state != SWAP_DEACTIVATING_SIGKILL) {
- unit_unwatch_timer(UNIT(s), &s->timer_watch);
- swap_unwatch_control_pid(s);
- s->control_command = NULL;
- s->control_command_id = _SWAP_EXEC_COMMAND_INVALID;
- }
-
- if (state != old_state)
- log_debug("%s changed %s -> %s",
- UNIT(s)->id,
- swap_state_to_string(old_state),
- swap_state_to_string(state));
-
- unit_notify(UNIT(s), state_translation_table[old_state],
- state_translation_table[state], true);
-}
-
-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) {
-
- if (new_state == SWAP_ACTIVATING ||
- new_state == SWAP_ACTIVATING_SIGTERM ||
- new_state == SWAP_ACTIVATING_SIGKILL ||
- new_state == SWAP_DEACTIVATING ||
- new_state == SWAP_DEACTIVATING_SIGTERM ||
- new_state == SWAP_DEACTIVATING_SIGKILL) {
-
- if (s->control_pid <= 0)
- return -EBADMSG;
-
- r = unit_watch_pid(UNIT(s), s->control_pid);
- if (r < 0)
- return r;
-
- r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch);
- 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 (p)
- fprintf(f,
- "%sPriority: %i\n"
- "%sNoAuto: %s\n"
- "%sNoFail: %s\n",
- prefix, p->priority,
- prefix, yes_no(p->noauto),
- prefix, yes_no(p->nofail));
-
- if (s->control_pid > 0)
- fprintf(f,
- "%sControl PID: %lu\n",
- prefix, (unsigned long) 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;
-
- assert(s);
- assert(c);
- assert(_pid);
-
- r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch);
- if (r < 0)
- goto fail;
-
- r = exec_spawn(c,
- NULL,
- &s->exec_context,
- NULL, 0,
- UNIT(s)->manager->environment,
- true,
- true,
- true,
- UNIT(s)->manager->confirm_spawn,
- UNIT(s)->cgroup_bondings,
- UNIT(s)->cgroup_attributes,
- NULL,
- UNIT(s)->id,
- NULL,
- &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:
- unit_unwatch_timer(UNIT(s), &s->timer_watch);
-
- return r;
-}
-
-static void swap_enter_dead(Swap *s, SwapResult f) {
- assert(s);
-
- if (f != SWAP_SUCCESS)
- s->result = f;
-
- 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;
- Set *pid_set = NULL;
- bool wait_for_exit = false;
-
- assert(s);
-
- if (f != SWAP_SUCCESS)
- s->result = f;
-
- if (s->kill_context.kill_mode != KILL_NONE) {
- int sig = (state == SWAP_ACTIVATING_SIGTERM ||
- state == SWAP_DEACTIVATING_SIGTERM) ? s->kill_context.kill_signal : SIGKILL;
-
- if (s->control_pid > 0) {
- if (kill_and_sigcont(s->control_pid, sig) < 0 && errno != ESRCH)
-
- log_warning("Failed to kill control process %li: %m", (long) s->control_pid);
- else
- wait_for_exit = true;
- }
-
- if (s->kill_context.kill_mode == KILL_CONTROL_GROUP) {
-
- pid_set = set_new(trivial_hash_func, trivial_compare_func);
- if (!pid_set) {
- r = log_oom();
- goto fail;
- }
-
- /* Exclude the control pid from being killed via the cgroup */
- if (s->control_pid > 0) {
- r = set_put(pid_set, LONG_TO_PTR(s->control_pid));
- if (r < 0)
- goto fail;
- }
-
- r = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, sig, true, false, pid_set, NULL);
- if (r < 0) {
- if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
- log_warning("Failed to kill control group: %s", strerror(-r));
- } else if (r > 0)
- wait_for_exit = true;
-
- set_free(pid_set);
- pid_set = NULL;
- }
- }
-
- if (wait_for_exit) {
- r = unit_watch_timer(UNIT(s), s->timeout_usec, &s->timer_watch);
- if (r < 0)
- goto fail;
-
- swap_set_state(s, state);
- } else
- swap_enter_dead(s, SWAP_SUCCESS);
-
- return;
-
-fail:
- log_warning("%s failed to kill processes: %s", UNIT(s)->id, strerror(-r));
-
- swap_enter_dead(s, SWAP_FAILURE_RESOURCES);
-
- if (pid_set)
- set_free(pid_set);
-}
-
-static void swap_enter_activating(Swap *s) {
- int r, priority;
-
- assert(s);
-
- s->control_command_id = SWAP_EXEC_ACTIVATE;
- s->control_command = s->exec_command + SWAP_EXEC_ACTIVATE;
-
- if (s->from_fragment)
- priority = s->parameters_fragment.priority;
- else
- priority = -1;
-
- if (priority >= 0) {
- char p[LINE_MAX];
-
- snprintf(p, sizeof(p), "%i", priority);
- char_array_0(p);
-
- r = exec_command_set(
- s->control_command,
- "/sbin/swapon",
- "-p",
- p,
- s->what,
- NULL);
- } else
- r = exec_command_set(
- s->control_command,
- "/sbin/swapon",
- 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_warning("%s failed to run 'swapon' task: %s", UNIT(s)->id, strerror(-r));
- 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_warning("%s failed to run 'swapoff' task: %s", UNIT(s)->id, strerror(-r));
- swap_enter_active(s, SWAP_FAILURE_RESOURCES);
-}
-
-static int swap_start(Unit *u) {
- Swap *s = SWAP(u);
-
- assert(s);
-
- /* We cannot fulfill this request right now, try again later
- * please! */
-
- if (s->state == SWAP_DEACTIVATING ||
- s->state == SWAP_DEACTIVATING_SIGTERM ||
- s->state == SWAP_DEACTIVATING_SIGKILL ||
- s->state == SWAP_ACTIVATING_SIGTERM ||
- s->state == SWAP_ACTIVATING_SIGKILL)
- return -EAGAIN;
-
- if (s->state == SWAP_ACTIVATING)
- return 0;
-
- assert(s->state == SWAP_DEAD || s->state == SWAP_FAILED);
-
- if (detect_container(NULL) > 0)
- return -EPERM;
-
- s->result = SWAP_SUCCESS;
- swap_enter_activating(s);
- return 0;
-}
-
-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_ACTIVE);
-
- if (detect_container(NULL) > 0)
- return -EPERM;
-
- swap_enter_deactivating(s);
- return 0;
-}
-
-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", "%lu", (unsigned long) 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_debug("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_debug("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_debug("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_debug("Failed to parse exec-command value %s", value);
- else {
- s->control_command_id = id;
- s->control_command = s->exec_command + id;
- }
-
- } else
- log_debug("Unknown serialization key '%s'", key);
-
- return 0;
-}
-
-static UnitActiveState swap_active_state(Unit *u) {
- assert(u);
-
- return state_translation_table[SWAP(u)->state];
-}
-
-static const char *swap_sub_state_to_string(Unit *u) {
- assert(u);
-
- return swap_state_to_string(SWAP(u)->state);
-}
-
-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_full(f == SWAP_SUCCESS ? LOG_DEBUG : LOG_NOTICE,
- "%s swap process exited, code=%s status=%i", u->id, sigchld_code_to_string(code), status);
-
- switch (s->state) {
-
- case SWAP_ACTIVATING:
- case SWAP_ACTIVATING_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:
-
- if (f == SWAP_SUCCESS)
- swap_enter_dead(s, f);
- else
- 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);
-
- /* Request a reload of /proc/swaps, so that following units
- * can follow our state change */
- u->manager->request_reload = true;
-}
-
-static void swap_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
- Swap *s = SWAP(u);
-
- assert(s);
- assert(elapsed == 1);
- assert(w == &s->timer_watch);
-
- switch (s->state) {
-
- case SWAP_ACTIVATING:
- log_warning("%s activation timed out. Stopping.", u->id);
- swap_enter_signal(s, SWAP_ACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT);
- break;
-
- case SWAP_DEACTIVATING:
- log_warning("%s deactivation timed out. Stopping.", u->id);
- swap_enter_signal(s, SWAP_DEACTIVATING_SIGTERM, SWAP_FAILURE_TIMEOUT);
- break;
-
- case SWAP_ACTIVATING_SIGTERM:
- if (s->kill_context.send_sigkill) {
- log_warning("%s activation timed out. Killing.", u->id);
- swap_enter_signal(s, SWAP_ACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT);
- } else {
- log_warning("%s activation timed out. Skipping SIGKILL. Ignoring.", u->id);
- swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
- }
- break;
-
- case SWAP_DEACTIVATING_SIGTERM:
- if (s->kill_context.send_sigkill) {
- log_warning("%s deactivation timed out. Killing.", u->id);
- swap_enter_signal(s, SWAP_DEACTIVATING_SIGKILL, SWAP_FAILURE_TIMEOUT);
- } else {
- log_warning("%s deactivation timed out. Skipping SIGKILL. Ignoring.", u->id);
- swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
- }
- break;
-
- case SWAP_ACTIVATING_SIGKILL:
- case SWAP_DEACTIVATING_SIGKILL:
- log_warning("%s swap process still around after SIGKILL. Ignoring.", u->id);
- swap_enter_dead(s, SWAP_FAILURE_TIMEOUT);
- break;
-
- default:
- assert_not_reached("Timeout at wrong time.");
- }
-}
-
-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++) {
- char *dev = NULL, *d;
- 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);
- free(dev);
- continue;
- }
-
- d = cunescape(dev);
- free(dev);
-
- if (!d)
- return -ENOMEM;
-
- k = swap_process_new_swap(m, d, prio, set_flags);
- free(d);
-
- if (k < 0)
- r = k;
- }
-
- return r;
-}
-
-int swap_dispatch_reload(Manager *m) {
- /* This function should go as soon as the kernel properly notifies us */
-
- if (_likely_(!m->request_reload))
- return 0;
-
- m->request_reload = false;
-
- return swap_fd_event(m, EPOLLPRI);
-}
-
-int swap_fd_event(Manager *m, int events) {
- Unit *u;
- int r;
-
- assert(m);
- assert(events & EPOLLPRI);
-
- r = swap_load_proc_swaps(m, true);
- if (r < 0) {
- log_error("Failed to reread /proc/swaps: %s", strerror(-r));
-
- /* 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->from_proc_swaps = false;
- swap_unset_proc_swaps(swap);
-
- switch (swap->state) {
-
- case SWAP_ACTIVE:
- swap_enter_dead(swap, SWAP_SUCCESS);
- break;
-
- default:
- swap_set_state(swap, swap->state);
- break;
- }
-
- } else if (swap->just_activated) {
-
- /* New swap entry */
-
- switch (swap->state) {
-
- case SWAP_DEAD:
- case SWAP_FAILED:
- swap_enter_active(swap, SWAP_SUCCESS);
- 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 (streq_ptr(s->what, s->parameters_proc_swaps.what))
- return NULL;
-
- /* Make everybody follow the unit that's named after the swap
- * device in the kernel */
-
- LIST_FOREACH_AFTER(same_proc_swaps, other, s)
- if (streq_ptr(other->what, other->parameters_proc_swaps.what))
- return UNIT(other);
-
- LIST_FOREACH_BEFORE(same_proc_swaps, other, s) {
- if (streq_ptr(other->what, other->parameters_proc_swaps.what))
- return UNIT(other);
-
- first = other;
- }
-
- return UNIT(first);
-}
-
-static int swap_following_set(Unit *u, Set **_set) {
- Swap *s = SWAP(u);
- Swap *other;
- Set *set;
- int r;
-
- assert(s);
- assert(_set);
-
- if (LIST_JUST_US(same_proc_swaps, s)) {
- *_set = NULL;
- return 0;
- }
-
- if (!(set = set_new(NULL, NULL)))
- return -ENOMEM;
-
- LIST_FOREACH_AFTER(same_proc_swaps, other, s)
- if ((r = set_put(set, other)) < 0)
- goto fail;
-
- LIST_FOREACH_BEFORE(same_proc_swaps, other, s)
- if ((r = set_put(set, other)) < 0)
- goto fail;
-
- *_set = set;
- return 1;
-
-fail:
- set_free(set);
- return r;
-}
-
-static void swap_shutdown(Manager *m) {
- assert(m);
-
- if (m->proc_swaps) {
- fclose(m->proc_swaps);
- m->proc_swaps = NULL;
- }
-
- hashmap_free(m->swaps_by_proc_swaps);
- m->swaps_by_proc_swaps = NULL;
-}
-
-static int swap_enumerate(Manager *m) {
- int r;
- struct epoll_event ev;
- assert(m);
-
- if (!m->proc_swaps) {
- m->proc_swaps = fopen("/proc/swaps", "re");
- if (!m->proc_swaps)
- return (errno == ENOENT) ? 0 : -errno;
-
- m->swap_watch.type = WATCH_SWAP;
- m->swap_watch.fd = fileno(m->proc_swaps);
-
- zero(ev);
- ev.events = EPOLLPRI;
- ev.data.ptr = &m->swap_watch;
-
- if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->swap_watch.fd, &ev) < 0)
- return -errno;
- }
-
- r = swap_load_proc_swaps(m, false);
- if (r < 0)
- swap_shutdown(m);
-
- 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, DBusError *error) {
- Swap *s = SWAP(u);
- int r = 0;
- Set *pid_set = NULL;
-
- assert(s);
-
- if (who == KILL_MAIN) {
- dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "Swap units have no main processes");
- return -ESRCH;
- }
-
- if (s->control_pid <= 0 && who == KILL_CONTROL) {
- dbus_set_error(error, BUS_ERROR_NO_SUCH_PROCESS, "No control process to kill");
- return -ESRCH;
- }
-
- if (who == KILL_CONTROL || who == KILL_ALL)
- if (s->control_pid > 0)
- if (kill(s->control_pid, signo) < 0)
- r = -errno;
-
- if (who == KILL_ALL) {
- int q;
-
- pid_set = set_new(trivial_hash_func, trivial_compare_func);
- if (!pid_set)
- return -ENOMEM;
-
- /* Exclude the control pid from being killed via the cgroup */
- if (s->control_pid > 0) {
- q = set_put(pid_set, LONG_TO_PTR(s->control_pid));
- if (q < 0) {
- r = q;
- goto finish;
- }
- }
-
- q = cgroup_bonding_kill_list(UNIT(s)->cgroup_bondings, signo, false, false, pid_set, NULL);
- if (q < 0 && q != -EAGAIN && q != -ESRCH && q != -ENOENT)
- r = q;
- }
-
-finish:
- if (pid_set)
- set_free(pid_set);
-
- return r;
-}
-
-static const char* const swap_state_table[_SWAP_STATE_MAX] = {
- [SWAP_DEAD] = "dead",
- [SWAP_ACTIVATING] = "activating",
- [SWAP_ACTIVE] = "active",
- [SWAP_DEACTIVATING] = "deactivating",
- [SWAP_ACTIVATING_SIGTERM] = "activating-sigterm",
- [SWAP_ACTIVATING_SIGKILL] = "activating-sigkill",
- [SWAP_DEACTIVATING_SIGTERM] = "deactivating-sigterm",
- [SWAP_DEACTIVATING_SIGKILL] = "deactivating-sigkill",
- [SWAP_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(swap_state, SwapState);
-
-static const char* const swap_exec_command_table[_SWAP_EXEC_COMMAND_MAX] = {
- [SWAP_EXEC_ACTIVATE] = "ExecActivate",
- [SWAP_EXEC_DEACTIVATE] = "ExecDeactivate",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(swap_exec_command, SwapExecCommand);
-
-static const char* const swap_result_table[_SWAP_RESULT_MAX] = {
- [SWAP_SUCCESS] = "success",
- [SWAP_FAILURE_RESOURCES] = "resources",
- [SWAP_FAILURE_TIMEOUT] = "timeout",
- [SWAP_FAILURE_EXIT_CODE] = "exit-code",
- [SWAP_FAILURE_SIGNAL] = "signal",
- [SWAP_FAILURE_CORE_DUMP] = "core-dump"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(swap_result, SwapResult);
-
-const UnitVTable swap_vtable = {
- .object_size = sizeof(Swap),
- .exec_context_offset = offsetof(Swap, exec_context),
-
- .sections =
- "Unit\0"
- "Swap\0"
- "Install\0",
-
- .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,
-
- .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,
- .timer_event = swap_timer_event,
-
- .reset_failed = swap_reset_failed,
-
- .bus_interface = "org.freedesktop.systemd1.Swap",
- .bus_message_handler = bus_swap_message_handler,
- .bus_invalidating_properties = bus_swap_invalidating_properties,
-
- .following = swap_following,
- .following_set = swap_following_set,
-
- .enumerate = swap_enumerate,
- .shutdown = swap_shutdown,
-
- .status_message_formats = {
- .starting_stopping = {
- [0] = "Activating swap %s...",
- [1] = "Deactivating swap %s...",
- },
- .finished_start_job = {
- [JOB_DONE] = "Activated swap %s.",
- [JOB_FAILED] = "Failed to activate swap %s.",
- [JOB_DEPENDENCY] = "Dependency failed for %s.",
- [JOB_TIMEOUT] = "Timed out activating swap %s.",
- },
- .finished_stop_job = {
- [JOB_DONE] = "Deactivated swap %s.",
- [JOB_FAILED] = "Failed deactivating swap %s.",
- [JOB_TIMEOUT] = "Timed out deactivating swap %s.",
- },
- },
-};
diff --git a/src/core/swap.h b/src/core/swap.h
deleted file mode 100644
index 35d47fd46f..0000000000
--- a/src/core/swap.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
- Copyright 2010 Maarten Lankhorst
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct Swap Swap;
-
-#include "unit.h"
-
-typedef enum SwapState {
- SWAP_DEAD,
- SWAP_ACTIVATING,
- SWAP_ACTIVE,
- SWAP_DEACTIVATING,
- SWAP_ACTIVATING_SIGTERM,
- SWAP_ACTIVATING_SIGKILL,
- SWAP_DEACTIVATING_SIGTERM,
- SWAP_DEACTIVATING_SIGKILL,
- SWAP_FAILED,
- _SWAP_STATE_MAX,
- _SWAP_STATE_INVALID = -1
-} SwapState;
-
-typedef enum SwapExecCommand {
- SWAP_EXEC_ACTIVATE,
- SWAP_EXEC_DEACTIVATE,
- _SWAP_EXEC_COMMAND_MAX,
- _SWAP_EXEC_COMMAND_INVALID = -1
-} SwapExecCommand;
-
-typedef struct SwapParameters {
- char *what;
- int priority;
- bool noauto:1;
- bool nofail:1;
-} SwapParameters;
-
-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;
-
-struct Swap {
- Unit meta;
-
- char *what;
-
- 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;
-
- SwapResult result;
-
- usec_t timeout_usec;
-
- ExecCommand exec_command[_SWAP_EXEC_COMMAND_MAX];
- ExecContext exec_context;
- KillContext kill_context;
-
- SwapState state, deserialized_state;
-
- ExecCommand* control_command;
- SwapExecCommand control_command_id;
- pid_t control_pid;
-
- Watch timer_watch;
-
- /* 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_proc_swaps);
-};
-
-extern const UnitVTable swap_vtable;
-
-int swap_add_one_mount_link(Swap *s, Mount *m);
-
-int swap_dispatch_reload(Manager *m);
-int swap_fd_event(Manager *m, int events);
-
-const char* swap_state_to_string(SwapState i);
-SwapState swap_state_from_string(const char *s);
-
-const char* swap_exec_command_to_string(SwapExecCommand i);
-SwapExecCommand swap_exec_command_from_string(const char *s);
-
-const char* swap_result_to_string(SwapResult i);
-SwapResult swap_result_from_string(const char *s);
diff --git a/src/core/switch-root.c b/src/core/switch-root.c
deleted file mode 100644
index 150332a858..0000000000
--- a/src/core/switch-root.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2012 Harald Hoyer, Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/stat.h>
-#include <stdbool.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/mount.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include "util.h"
-#include "path-util.h"
-#include "switch-root.h"
-
-int switch_root(const char *new_root) {
-
- /* Don't try to unmount/move the old "/", there's no way to do it. */
- static const char move_mounts[] =
- "/dev\0"
- "/proc\0"
- "/sys\0"
- "/run\0";
-
- int r, old_root_fd = -1;
- struct stat new_root_stat;
- bool old_root_remove;
- const char *i;
-
- if (path_equal(new_root, "/"))
- return 0;
-
- old_root_remove = in_initrd();
-
- if (stat(new_root, &new_root_stat) < 0) {
- r = -errno;
- log_error("Failed to stat directory %s: %m", new_root);
- goto fail;
- }
-
- /* Work-around for a kernel bug: for some reason the kernel
- * refuses switching root if any file systems are mounted
- * MS_SHARED. Hence remount them MS_PRIVATE here as a
- * work-around.
- *
- * https://bugzilla.redhat.com/show_bug.cgi?id=847418 */
- if (mount(NULL, "/", NULL, MS_REC|MS_PRIVATE, NULL) < 0)
- log_warning("Failed to make \"/\" private mount: %m");
-
- NULSTR_FOREACH(i, move_mounts) {
- char new_mount[PATH_MAX];
- struct stat sb;
-
- snprintf(new_mount, sizeof(new_mount), "%s%s", new_root, i);
- char_array_0(new_mount);
-
- if ((stat(new_mount, &sb) < 0) ||
- sb.st_dev != new_root_stat.st_dev) {
-
- /* Mount point seems to be mounted already or
- * stat failed. Unmount the old mount
- * point. */
- if (umount2(i, MNT_DETACH) < 0)
- log_warning("Failed to unmount %s: %m", i);
- continue;
- }
-
- if (mount(i, new_mount, NULL, MS_MOVE, NULL) < 0) {
- log_error("Failed to move mount %s to %s, forcing unmount: %m", i, new_mount);
-
- if (umount2(i, MNT_FORCE) < 0)
- log_warning("Failed to unmount %s: %m", i);
- }
- }
-
- if (chdir(new_root) < 0) {
- r = -errno;
- log_error("Failed to change directory to %s: %m", new_root);
- goto fail;
- }
-
- if (old_root_remove) {
- old_root_fd = open("/", O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY|O_DIRECTORY);
- if (old_root_fd < 0)
- log_warning("Failed to open root directory: %m");
- }
-
- if (mount(new_root, "/", NULL, MS_MOVE, NULL) < 0) {
- r = -errno;
- log_error("Failed to mount moving %s to /: %m", new_root);
- goto fail;
- }
-
- if (chroot(".") < 0) {
- r = -errno;
- log_error("Failed to change root: %m");
- goto fail;
- }
-
- if (chdir("/") < 0) {
- r = -errno;
- log_error("Failed to change directory: %m");
- goto fail;
- }
-
- if (old_root_fd >= 0) {
- struct stat rb;
-
- if (fstat(old_root_fd, &rb) < 0)
- log_warning("Failed to stat old root directory, leaving: %m");
- else {
- rm_rf_children(old_root_fd, false, false, &rb);
- old_root_fd = -1;
- }
- }
-
- r = 0;
-
-fail:
- if (old_root_fd >= 0)
- close_nointr_nofail(old_root_fd);
-
- return r;
-}
diff --git a/src/core/switch-root.h b/src/core/switch-root.h
deleted file mode 100644
index 0c4cd1e403..0000000000
--- a/src/core/switch-root.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef fooswitchroothfoo
-#define fooswitchroothfoo
-
-/***
- This file is part of systemd.
-
- Copyright 2012 Harald Hoyer, Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- 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 switch_root(const char *switch_root);
-
-#endif
diff --git a/src/core/syscall-list.c b/src/core/syscall-list.c
deleted file mode 100644
index 05fad3e158..0000000000
--- a/src/core/syscall-list.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2012 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/syscall.h>
-#include <string.h>
-
-#include "util.h"
-
-#include "syscall-list.h"
-
-const struct syscall_name *lookup_syscall(register const char *str, register unsigned int len);
-
-#include "syscall-to-name.h"
-#include "syscall-from-name.h"
-
-const char *syscall_to_name(int id) {
- if (id < 0 || id >= (int) ELEMENTSOF(syscall_names))
- return NULL;
-
- return syscall_names[id];
-}
-
-int syscall_from_name(const char *name) {
- const struct syscall_name *sc;
-
- assert(name);
-
- sc = lookup_syscall(name, strlen(name));
- if (!sc)
- return -1;
-
- return sc->id;
-}
-
-int syscall_max(void) {
- return ELEMENTSOF(syscall_names);
-}
diff --git a/src/core/syscall-list.h b/src/core/syscall-list.h
deleted file mode 100644
index 0fc6859605..0000000000
--- a/src/core/syscall-list.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef foosyscalllisthfoo
-#define foosyscalllisthfoo
-
-/***
- 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/>.
-***/
-
-const char *syscall_to_name(int id);
-int syscall_from_name(const char *name);
-
-int syscall_max(void);
-
-#endif
diff --git a/src/core/sysfs-show.h b/src/core/sysfs-show.h
deleted file mode 100644
index 9ffd129c48..0000000000
--- a/src/core/sysfs-show.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2011 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- 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 show_sysfs(const char *seat, const char *prefix, unsigned columns);
diff --git a/src/core/system.conf b/src/core/system.conf
deleted file mode 100644
index 68076d9735..0000000000
--- a/src/core/system.conf
+++ /dev/null
@@ -1,43 +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.
-#
-# See systemd.conf(5) for details
-
-[Manager]
-#LogLevel=info
-#LogTarget=journal-or-kmsg
-#LogColor=yes
-#LogLocation=no
-#DumpCore=yes
-#CrashShell=no
-#ShowStatus=yes
-#CrashChVT=1
-#CPUAffinity=1 2
-#DefaultControllers=cpu
-#DefaultStandardOutput=journal
-#DefaultStandardError=inherit
-#JoinControllers=cpu,cpuacct,cpuset net_cls,net_prio
-#RuntimeWatchdogSec=0
-#ShutdownWatchdogSec=10min
-#CapabilityBoundingSet=
-#TimerSlackNSec=
-#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 2f49d5df52..0000000000
--- a/src/core/systemd.pc.in
+++ /dev/null
@@ -1,23 +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@
-exec_prefix=@exec_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
-
-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 981424132b..0000000000
--- a/src/core/target.c
+++ /dev/null
@@ -1,239 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <signal.h>
-#include <unistd.h>
-
-#include "unit.h"
-#include "target.h"
-#include "load-fragment.h"
-#include "log.h"
-#include "dbus-target.h"
-#include "special.h"
-#include "unit-name.h"
-
-static const UnitActiveState state_translation_table[_TARGET_STATE_MAX] = {
- [TARGET_DEAD] = UNIT_INACTIVE,
- [TARGET_ACTIVE] = UNIT_ACTIVE
-};
-
-static void target_set_state(Target *t, TargetState state) {
- TargetState old_state;
- assert(t);
-
- old_state = t->state;
- t->state = state;
-
- if (state != old_state)
- log_debug("%s changed %s -> %s",
- UNIT(t)->id,
- target_state_to_string(old_state),
- target_state_to_string(state));
-
- unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
-}
-
-static int target_add_default_dependencies(Target *t) {
-
- static const UnitDependency deps[] = {
- UNIT_REQUIRES,
- UNIT_REQUIRES_OVERRIDABLE,
- UNIT_REQUISITE,
- UNIT_REQUISITE_OVERRIDABLE,
- UNIT_WANTS,
- UNIT_BINDS_TO,
- UNIT_PART_OF
- };
-
- Iterator i;
- Unit *other;
- int r;
- unsigned k;
-
- assert(t);
-
- /* Imply ordering for requirement dependencies on target
- * units. Note that when the user created a contradicting
- * ordering manually we won't add anything in here to make
- * sure we don't create a loop. */
-
- for (k = 0; k < ELEMENTSOF(deps); k++)
- SET_FOREACH(other, UNIT(t)->dependencies[deps[k]], i) {
- r = unit_add_default_target_dependency(other, UNIT(t));
- if (r < 0)
- return r;
- }
-
- /* Make sure targets are unloaded on shutdown */
- return unit_add_dependency_by_name(UNIT(t), UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
-}
-
-static int target_load(Unit *u) {
- Target *t = TARGET(u);
- int r;
-
- assert(t);
-
- r = unit_load_fragment_and_dropin(u);
- if (r < 0)
- return r;
-
- /* This is a new unit? Then let's add in some extras */
- if (u->load_state == UNIT_LOADED && u->default_dependencies) {
- r = target_add_default_dependencies(t);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-static int target_coldplug(Unit *u) {
- 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 0;
-}
-
-static int target_stop(Unit *u) {
- Target *t = TARGET(u);
-
- assert(t);
- assert(t->state == TARGET_ACTIVE);
-
- target_set_state(t, TARGET_DEAD);
- return 0;
-}
-
-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;
-}
-
-static UnitActiveState target_active_state(Unit *u) {
- assert(u);
-
- return state_translation_table[TARGET(u)->state];
-}
-
-static const char *target_sub_state_to_string(Unit *u) {
- assert(u);
-
- return target_state_to_string(TARGET(u)->state);
-}
-
-static const char* const target_state_table[_TARGET_STATE_MAX] = {
- [TARGET_DEAD] = "dead",
- [TARGET_ACTIVE] = "active"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(target_state, TargetState);
-
-const UnitVTable target_vtable = {
- .object_size = sizeof(Target),
- .sections =
- "Unit\0"
- "Target\0"
- "Install\0",
-
- .load = target_load,
- .coldplug = target_coldplug,
-
- .dump = target_dump,
-
- .start = target_start,
- .stop = target_stop,
-
- .serialize = target_serialize,
- .deserialize_item = target_deserialize_item,
-
- .active_state = target_active_state,
- .sub_state_to_string = target_sub_state_to_string,
-
- .bus_interface = "org.freedesktop.systemd1.Target",
- .bus_message_handler = bus_target_message_handler,
-
- .status_message_formats = {
- .finished_start_job = {
- [JOB_DONE] = "Reached target %s.",
- [JOB_DEPENDENCY] = "Dependency failed for %s.",
- },
- .finished_stop_job = {
- [JOB_DONE] = "Stopped target %s.",
- },
- },
-};
diff --git a/src/core/target.h b/src/core/target.h
deleted file mode 100644
index 1676553add..0000000000
--- a/src/core/target.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 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;
-
-#include "unit.h"
-
-typedef enum TargetState {
- TARGET_DEAD,
- TARGET_ACTIVE,
- _TARGET_STATE_MAX,
- _TARGET_STATE_INVALID = -1
-} TargetState;
-
-struct Target {
- Unit meta;
-
- TargetState state, deserialized_state;
-};
-
-extern const UnitVTable target_vtable;
-
-const char* target_state_to_string(TargetState i);
-TargetState target_state_from_string(const char *s);
diff --git a/src/core/tcpwrap.c b/src/core/tcpwrap.c
deleted file mode 100644
index 6c630fac60..0000000000
--- a/src/core/tcpwrap.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <arpa/inet.h>
-#include <netinet/in.h>
-
-#ifdef HAVE_LIBWRAP
-#include <tcpd.h>
-#endif
-
-#include "tcpwrap.h"
-#include "log.h"
-
-bool socket_tcpwrap(int fd, const char *name) {
-#ifdef HAVE_LIBWRAP
- struct request_info req;
- union {
- struct sockaddr sa;
- struct sockaddr_in in;
- struct sockaddr_in6 in6;
- struct sockaddr_un un;
- struct sockaddr_storage storage;
- } sa_union;
- socklen_t l = sizeof(sa_union);
-
- if (getsockname(fd, &sa_union.sa, &l) < 0)
- return true;
-
- if (sa_union.sa.sa_family != AF_INET &&
- sa_union.sa.sa_family != AF_INET6)
- return true;
-
- request_init(&req,
- RQ_DAEMON, name,
- RQ_FILE, fd,
- NULL);
-
- fromhost(&req);
-
- if (!hosts_access(&req)) {
- log_warning("Connection refused by tcpwrap.");
- return false;
- }
-
- log_debug("Connection accepted by tcpwrap.");
-#endif
- return true;
-}
diff --git a/src/core/tcpwrap.h b/src/core/tcpwrap.h
deleted file mode 100644
index 3353b6596e..0000000000
--- a/src/core/tcpwrap.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-
-bool socket_tcpwrap(int fd, const char *name);
diff --git a/src/core/timer.c b/src/core/timer.c
deleted file mode 100644
index 7080b32c6b..0000000000
--- a/src/core/timer.c
+++ /dev/null
@@ -1,519 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-
-#include "unit.h"
-#include "unit-name.h"
-#include "timer.h"
-#include "dbus-timer.h"
-#include "special.h"
-#include "bus-errors.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 void timer_init(Unit *u) {
- Timer *t = TIMER(u);
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
-
- t->next_elapse = (usec_t) -1;
-}
-
-static void timer_done(Unit *u) {
- Timer *t = TIMER(u);
- TimerValue *v;
-
- assert(t);
-
- while ((v = t->values)) {
- LIST_REMOVE(TimerValue, value, t->values, v);
- free(v);
- }
-
- unit_unwatch_timer(u, &t->timer_watch);
-
- unit_ref_unset(&t->unit);
-}
-
-static int timer_verify(Timer *t) {
- assert(t);
-
- if (UNIT(t)->load_state != UNIT_LOADED)
- return 0;
-
- if (!t->values) {
- log_error("%s lacks value setting. Refusing.", UNIT(t)->id);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int timer_add_default_dependencies(Timer *t) {
- int r;
-
- assert(t);
-
- if (UNIT(t)->manager->running_as == SYSTEMD_SYSTEM) {
- if ((r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_BASIC_TARGET, NULL, true)) < 0)
- return r;
-
- if ((r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true)) < 0)
- return r;
- }
-
- return unit_add_two_dependencies_by_name(UNIT(t), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
-}
-
-static int timer_load(Unit *u) {
- Timer *t = TIMER(u);
- int r;
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
-
- if ((r = unit_load_fragment_and_dropin(u)) < 0)
- return r;
-
- if (u->load_state == UNIT_LOADED) {
-
- if (!UNIT_DEREF(t->unit)) {
- Unit *x;
-
- r = unit_load_related_unit(u, ".service", &x);
- if (r < 0)
- return r;
-
- unit_ref_set(&t->unit, x);
- }
-
- r = unit_add_two_dependencies(u, UNIT_BEFORE, UNIT_TRIGGERS, UNIT_DEREF(t->unit), true);
- if (r < 0)
- return r;
-
- if (UNIT(t)->default_dependencies)
- if ((r = timer_add_default_dependencies(t)) < 0)
- return r;
- }
-
- return timer_verify(t);
-}
-
-static void timer_dump(Unit *u, FILE *f, const char *prefix) {
- Timer *t = TIMER(u);
- TimerValue *v;
- char
- timespan1[FORMAT_TIMESPAN_MAX];
-
- fprintf(f,
- "%sTimer State: %s\n"
- "%sResult: %s\n"
- "%sUnit: %s\n",
- prefix, timer_state_to_string(t->state),
- prefix, timer_result_to_string(t->result),
- prefix, UNIT_DEREF(t->unit)->id);
-
- LIST_FOREACH(value, v, t->values)
- fprintf(f,
- "%s%s: %s\n",
- prefix,
- timer_base_to_string(v->base),
- strna(format_timespan(timespan1, sizeof(timespan1), v->value)));
-}
-
-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)
- unit_unwatch_timer(UNIT(t), &t->timer_watch);
-
- if (state != old_state)
- log_debug("%s changed %s -> %s",
- UNIT(t)->id,
- timer_state_to_string(old_state),
- timer_state_to_string(state));
-
- unit_notify(UNIT(t), state_translation_table[old_state], state_translation_table[state], true);
-}
-
-static void timer_enter_waiting(Timer *t, bool initial);
-
-static int timer_coldplug(Unit *u) {
- Timer *t = TIMER(u);
-
- assert(t);
- assert(t->state == TIMER_DEAD);
-
- if (t->deserialized_state != t->state) {
-
- 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_waiting(Timer *t, bool initial) {
- TimerValue *v;
- usec_t base = 0, delay, n;
- bool found = false;
- int r;
-
- n = now(CLOCK_MONOTONIC);
-
- LIST_FOREACH(value, v, t->values) {
-
- if (v->disabled)
- continue;
-
- switch (v->base) {
-
- case TIMER_ACTIVE:
- if (state_translation_table[t->state] == UNIT_ACTIVE)
- base = UNIT(t)->inactive_exit_timestamp.monotonic;
- else
- base = n;
- break;
-
- case TIMER_BOOT:
- /* CLOCK_MONOTONIC equals the uptime on Linux */
- base = 0;
- break;
-
- case TIMER_STARTUP:
- base = UNIT(t)->manager->userspace_timestamp.monotonic;
- break;
-
- case TIMER_UNIT_ACTIVE:
-
- if (UNIT_DEREF(t->unit)->inactive_exit_timestamp.monotonic <= 0)
- continue;
-
- base = UNIT_DEREF(t->unit)->inactive_exit_timestamp.monotonic;
- break;
-
- case TIMER_UNIT_INACTIVE:
-
- if (UNIT_DEREF(t->unit)->inactive_enter_timestamp.monotonic <= 0)
- continue;
-
- base = UNIT_DEREF(t->unit)->inactive_enter_timestamp.monotonic;
- break;
-
- default:
- assert_not_reached("Unknown timer base");
- }
-
- v->next_elapse = base + v->value;
-
- if (!initial && v->next_elapse < n) {
- v->disabled = true;
- continue;
- }
-
- if (!found)
- t->next_elapse = v->next_elapse;
- else
- t->next_elapse = MIN(t->next_elapse, v->next_elapse);
-
- found = true;
- }
-
- if (!found) {
- timer_set_state(t, TIMER_ELAPSED);
- return;
- }
-
- delay = n < t->next_elapse ? t->next_elapse - n : 0;
-
- if ((r = unit_watch_timer(UNIT(t), delay, &t->timer_watch)) < 0)
- goto fail;
-
- timer_set_state(t, TIMER_WAITING);
- return;
-
-fail:
- log_warning("%s failed to enter waiting state: %s", UNIT(t)->id, strerror(-r));
- timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
-}
-
-static void timer_enter_running(Timer *t) {
- DBusError error;
- int r;
-
- assert(t);
- dbus_error_init(&error);
-
- /* Don't start job if we are supposed to go down */
- if (UNIT(t)->job && UNIT(t)->job->type == JOB_STOP)
- return;
-
- if ((r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_DEREF(t->unit), JOB_REPLACE, true, &error, NULL)) < 0)
- goto fail;
-
- timer_set_state(t, TIMER_RUNNING);
- return;
-
-fail:
- log_warning("%s failed to queue unit startup job: %s", UNIT(t)->id, bus_error(&error, r));
- timer_enter_dead(t, TIMER_FAILURE_RESOURCES);
-
- dbus_error_free(&error);
-}
-
-static int timer_start(Unit *u) {
- Timer *t = TIMER(u);
-
- assert(t);
- assert(t->state == TIMER_DEAD || t->state == TIMER_FAILED);
-
- if (UNIT_DEREF(t->unit)->load_state != UNIT_LOADED)
- return -ENOENT;
-
- t->result = TIMER_SUCCESS;
- timer_enter_waiting(t, true);
- return 0;
-}
-
-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 0;
-}
-
-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));
-
- return 0;
-}
-
-static int timer_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Timer *t = TIMER(u);
-
- assert(u);
- assert(key);
- assert(value);
- assert(fds);
-
- if (streq(key, "state")) {
- TimerState state;
-
- if ((state = timer_state_from_string(value)) < 0)
- log_debug("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_debug("Failed to parse result value %s", value);
- else if (f != TIMER_SUCCESS)
- t->result = f;
-
- } else
- log_debug("Unknown serialization key '%s'", key);
-
- return 0;
-}
-
-static UnitActiveState timer_active_state(Unit *u) {
- assert(u);
-
- return state_translation_table[TIMER(u)->state];
-}
-
-static const char *timer_sub_state_to_string(Unit *u) {
- assert(u);
-
- return timer_state_to_string(TIMER(u)->state);
-}
-
-static void timer_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
- Timer *t = TIMER(u);
-
- assert(t);
- assert(elapsed == 1);
-
- if (t->state != TIMER_WAITING)
- return;
-
- log_debug("Timer elapsed on %s", u->id);
- timer_enter_running(t);
-}
-
-void timer_unit_notify(Unit *u, UnitActiveState new_state) {
- Iterator i;
- Unit *k;
-
- if (u->type == UNIT_TIMER)
- return;
-
- SET_FOREACH(k, u->dependencies[UNIT_TRIGGERED_BY], i) {
- Timer *t;
- TimerValue *v;
-
- if (k->type != UNIT_TIMER)
- continue;
-
- if (k->load_state != UNIT_LOADED)
- continue;
-
- t = TIMER(k);
-
- /* 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(new_state)) {
- log_debug("%s got notified about unit deactivation.", UNIT(t)->id);
- timer_enter_waiting(t, false);
- }
-
- break;
-
- case TIMER_DEAD:
- case TIMER_FAILED:
- break;
-
- default:
- assert_not_reached("Unknown timer state");
- }
- }
-}
-
-static void timer_reset_failed(Unit *u) {
- Timer *t = TIMER(u);
-
- assert(t);
-
- if (t->state == TIMER_FAILED)
- timer_set_state(t, TIMER_DEAD);
-
- t->result = TIMER_SUCCESS;
-}
-
-static const char* const timer_state_table[_TIMER_STATE_MAX] = {
- [TIMER_DEAD] = "dead",
- [TIMER_WAITING] = "waiting",
- [TIMER_RUNNING] = "running",
- [TIMER_ELAPSED] = "elapsed",
- [TIMER_FAILED] = "failed"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(timer_state, TimerState);
-
-static const char* const timer_base_table[_TIMER_BASE_MAX] = {
- [TIMER_ACTIVE] = "OnActiveSec",
- [TIMER_BOOT] = "OnBootSec",
- [TIMER_STARTUP] = "OnStartupSec",
- [TIMER_UNIT_ACTIVE] = "OnUnitActiveSec",
- [TIMER_UNIT_INACTIVE] = "OnUnitInactiveSec"
-};
-
-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",
-
- .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,
-
- .timer_event = timer_timer_event,
-
- .reset_failed = timer_reset_failed,
-
- .bus_interface = "org.freedesktop.systemd1.Timer",
- .bus_message_handler = bus_timer_message_handler,
- .bus_invalidating_properties = bus_timer_invalidating_properties
-};
diff --git a/src/core/timer.h b/src/core/timer.h
deleted file mode 100644
index c6d1d42e44..0000000000
--- a/src/core/timer.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct Timer Timer;
-
-#include "unit.h"
-
-typedef enum TimerState {
- TIMER_DEAD,
- TIMER_WAITING,
- TIMER_RUNNING,
- TIMER_ELAPSED,
- TIMER_FAILED,
- _TIMER_STATE_MAX,
- _TIMER_STATE_INVALID = -1
-} TimerState;
-
-typedef enum TimerBase {
- TIMER_ACTIVE,
- TIMER_BOOT,
- TIMER_STARTUP,
- TIMER_UNIT_ACTIVE,
- TIMER_UNIT_INACTIVE,
- _TIMER_BASE_MAX,
- _TIMER_BASE_INVALID = -1
-} TimerBase;
-
-typedef struct TimerValue {
- usec_t value;
- usec_t next_elapse;
-
- LIST_FIELDS(struct TimerValue, value);
-
- TimerBase base;
- bool disabled;
-} TimerValue;
-
-typedef enum TimerResult {
- TIMER_SUCCESS,
- TIMER_FAILURE_RESOURCES,
- _TIMER_RESULT_MAX,
- _TIMER_RESULT_INVALID = -1
-} TimerResult;
-
-struct Timer {
- Unit meta;
-
- LIST_HEAD(TimerValue, values);
- usec_t next_elapse;
-
- TimerState state, deserialized_state;
- UnitRef unit;
-
- Watch timer_watch;
-
- TimerResult result;
-};
-
-void timer_unit_notify(Unit *u, UnitActiveState new_state);
-
-extern const UnitVTable timer_vtable;
-
-const char *timer_state_to_string(TimerState i);
-TimerState timer_state_from_string(const char *s);
-
-const char *timer_base_to_string(TimerBase i);
-TimerBase timer_base_from_string(const char *s);
-
-const char* timer_result_to_string(TimerResult i);
-TimerResult timer_result_from_string(const char *s);
diff --git a/src/core/transaction.c b/src/core/transaction.c
deleted file mode 100644
index 4bce942012..0000000000
--- a/src/core/transaction.c
+++ /dev/null
@@ -1,1087 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <unistd.h>
-#include <fcntl.h>
-
-#include "transaction.h"
-#include "bus-errors.h"
-
-static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies);
-
-static void transaction_delete_job(Transaction *tr, Job *j, bool delete_dependencies) {
- assert(tr);
- assert(j);
-
- /* Deletes one job from the transaction */
-
- transaction_unlink_job(tr, j, delete_dependencies);
-
- job_free(j);
-}
-
-static void transaction_delete_unit(Transaction *tr, Unit *u) {
- Job *j;
-
- /* Deletes all jobs associated with a certain unit from the
- * transaction */
-
- while ((j = hashmap_get(tr->jobs, u)))
- transaction_delete_job(tr, j, true);
-}
-
-void transaction_abort(Transaction *tr) {
- Job *j;
-
- assert(tr);
-
- while ((j = hashmap_first(tr->jobs)))
- transaction_delete_job(tr, j, false);
-
- assert(hashmap_isempty(tr->jobs));
-}
-
-static void transaction_find_jobs_that_matter_to_anchor(Job *j, unsigned generation) {
- JobDependency *l;
-
- /* A recursive sweep through the graph that marks all units
- * that matter to the anchor job, i.e. are directly or
- * indirectly a dependency of the anchor job via paths that
- * are fully marked as mattering. */
-
- j->matters_to_anchor = true;
- j->generation = generation;
-
- LIST_FOREACH(subject, l, j->subject_list) {
-
- /* This link does not matter */
- if (!l->matters)
- continue;
-
- /* This unit has already been marked */
- if (l->object->generation == generation)
- continue;
-
- transaction_find_jobs_that_matter_to_anchor(l->object, generation);
- }
-}
-
-static void transaction_merge_and_delete_job(Transaction *tr, Job *j, Job *other, JobType t) {
- JobDependency *l, *last;
-
- assert(j);
- assert(other);
- assert(j->unit == other->unit);
- assert(!j->installed);
-
- /* Merges 'other' into 'j' and then deletes 'other'. */
-
- j->type = t;
- j->state = JOB_WAITING;
- j->override = j->override || other->override;
-
- j->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);
-}
-
-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_debug("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_debug("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_debug("Fixing conflicting jobs by deleting job %s/%s", 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, DBusError *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 */
- dbus_set_error(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);
- return r;
- }
- }
-
- /* 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:;
- }
-}
-
-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, DBusError *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 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_warning("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)) {
-
- log_info("Walked on cycle path to %s/%s", k->unit->id, job_type_to_string(k->type));
-
- if (!delete &&
- !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) {
- log_warning("Breaking ordering cycle by deleting job %s/%s", delete->unit->id, job_type_to_string(delete->type));
- transaction_delete_unit(tr, delete->unit);
- return -EAGAIN;
- }
-
- log_error("Unable to break cycle");
-
- dbus_set_error(e, BUS_ERROR_TRANSACTION_ORDER_IS_CYCLIC, "Transaction order is cyclic. See system logs for details.");
- return -ENOEXEC;
- }
-
- /* 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, DBusError *e) {
- Job *j;
- int r;
- Iterator i;
- unsigned g;
-
- assert(tr);
- assert(generation);
-
- /* Check if the ordering graph is cyclic. If it is, try to fix
- * that up by dropping one of the jobs. */
-
- g = (*generation)++;
-
- HASHMAP_FOREACH(j, tr->jobs, i)
- if ((r = transaction_verify_order_one(tr, j, NULL, g, e)) < 0)
- return r;
-
- return 0;
-}
-
-static void transaction_collect_garbage(Transaction *tr) {
- Iterator i;
- Job *j;
-
- assert(tr);
-
- /* Drop jobs that are not required by any other job */
-
-rescan:
- HASHMAP_FOREACH(j, tr->jobs, i) {
- if (tr->anchor_job == j || j->object_list) {
- /* log_debug("Keeping job %s/%s because of %s/%s", */
- /* j->unit->id, job_type_to_string(j->type), */
- /* j->object_list->subject ? j->object_list->subject->unit->id : "root", */
- /* j->object_list->subject ? job_type_to_string(j->object_list->subject->type) : "root"); */
- continue;
- }
-
- /* log_debug("Garbage collecting job %s/%s", j->unit->id, job_type_to_string(j->type)); */
- transaction_delete_job(tr, j, true);
- goto rescan;
- }
-}
-
-static int transaction_is_destructive(Transaction *tr, DBusError *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 &&
- !job_type_is_superset(j->type, j->unit->job->type)) {
-
- dbus_set_error(e, BUS_ERROR_TRANSACTION_IS_DESTRUCTIVE, "Transaction is destructive.");
- return -EEXIST;
- }
- }
-
- 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_debug("%s/%s would stop a running service.", j->unit->id, job_type_to_string(j->type));
-
- if (changes_existing_job)
- log_debug("%s/%s would change existing job.", j->unit->id, job_type_to_string(j->type));
-
- /* Ok, let's get rid of this */
- log_debug("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) {
-
- /* 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);
- }
-
- 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, DBusError *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(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(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 */
- if (mode == JOB_FAIL) {
- r = transaction_is_destructive(tr, e);
- if (r < 0) {
- log_notice("Requested transaction contradicts existing jobs: %s", bus_error(e, r));
- return r;
- }
- }
-
- /* Tenth step: apply changes */
- r = transaction_apply(tr, m, mode);
- if (r < 0) {
- log_warning("Failed to apply transaction: %s", strerror(-r));
- return r;
- }
-
- 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)
- pipe2(m->idle_pipe, O_NONBLOCK|O_CLOEXEC);
- }
-
- return 0;
-}
-
-static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, bool override, bool *is_new) {
- Job *j, *f;
-
- assert(tr);
- assert(unit);
-
- /* Looks for an existing prospective job and returns that. If
- * it doesn't exist it is created and added to the prospective
- * jobs list. */
-
- f = hashmap_get(tr->jobs, unit);
-
- LIST_FOREACH(transaction, j, f) {
- assert(j->unit == unit);
-
- if (j->type == type) {
- if (is_new)
- *is_new = false;
- return j;
- }
- }
-
- j = job_new(unit, type);
- if (!j)
- return NULL;
-
- j->generation = 0;
- j->marker = NULL;
- j->matters_to_anchor = false;
- j->override = override;
-
- LIST_PREPEND(Job, transaction, f, j);
-
- if (hashmap_replace(tr->jobs, unit, f) < 0) {
- LIST_REMOVE(Job, 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_debug("Deleting job %s/%s as dependency of job %s/%s",
- other->unit->id, job_type_to_string(other->type),
- j->unit->id, job_type_to_string(j->type));
- transaction_delete_job(tr, other, delete_dependencies);
- }
- }
-}
-
-int transaction_add_job_and_dependencies(
- Transaction *tr,
- JobType type,
- Unit *unit,
- Job *by,
- bool matters,
- bool override,
- bool conflicts,
- bool ignore_requirements,
- bool ignore_order,
- DBusError *e) {
- Job *ret;
- Iterator i;
- Unit *dep;
- int r;
- bool is_new;
-
- assert(tr);
- assert(type < _JOB_TYPE_MAX);
- assert(type < _JOB_TYPE_MAX_IN_TRANSACTION);
- assert(unit);
-
- /* log_debug("Pulling in %s/%s from %s/%s", */
- /* unit->id, job_type_to_string(type), */
- /* by ? by->unit->id : "NA", */
- /* by ? job_type_to_string(by->type) : "NA"); */
-
- if (unit->load_state != UNIT_LOADED &&
- unit->load_state != UNIT_ERROR &&
- unit->load_state != UNIT_MASKED) {
- dbus_set_error(e, BUS_ERROR_LOAD_FAILED, "Unit %s is not loaded properly.", unit->id);
- return -EINVAL;
- }
-
- if (type != JOB_STOP && unit->load_state == UNIT_ERROR) {
- dbus_set_error(e, BUS_ERROR_LOAD_FAILED,
- "Unit %s failed to load: %s. "
- "See system logs and 'systemctl status %s' for details.",
- unit->id,
- strerror(-unit->load_error),
- unit->id);
- return -EINVAL;
- }
-
- if (type != JOB_STOP && unit->load_state == UNIT_MASKED) {
- dbus_set_error(e, BUS_ERROR_MASKED, "Unit %s is masked.", unit->id);
- return -EADDRNOTAVAIL;
- }
-
- if (!unit_job_is_applicable(unit, type)) {
- dbus_set_error(e, BUS_ERROR_JOB_TYPE_NOT_APPLICABLE, "Job type %s is not applicable for unit %s.", job_type_to_string(type), unit->id);
- return -EBADR;
- }
-
- /* First add the job. */
- ret = transaction_add_one_job(tr, type, unit, override, &is_new);
- if (!ret)
- return -ENOMEM;
-
- ret->ignore_order = ret->ignore_order || ignore_order;
-
- /* Then, add a link to the job. */
- if (by) {
- if (!job_dependency_new(by, ret, matters, conflicts))
- return -ENOMEM;
- } else {
- /* If the job has no parent job, it is the anchor job. */
- assert(!tr->anchor_job);
- tr->anchor_job = ret;
- }
-
- if (is_new && !ignore_requirements && type != JOB_NOP) {
- Set *following;
-
- /* If we are following some other unit, make sure we
- * add all dependencies of everybody following. */
- if (unit_following_set(ret->unit, &following) > 0) {
- SET_FOREACH(dep, following, i) {
- r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, override, false, false, ignore_order, e);
- if (r < 0) {
- log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r));
-
- if (e)
- dbus_error_free(e);
- }
- }
-
- set_free(following);
- }
-
- /* Finally, recursively add in all dependencies. */
- if (type == JOB_START || type == JOB_RESTART) {
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) {
- r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e);
- if (r < 0) {
- if (r != -EBADR)
- goto fail;
-
- if (e)
- dbus_error_free(e);
- }
- }
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_BINDS_TO], i) {
- r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e);
- if (r < 0) {
- if (r != -EBADR)
- goto fail;
-
- if (e)
- dbus_error_free(e);
- }
- }
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) {
- r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, !override, override, false, false, ignore_order, e);
- if (r < 0) {
- log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING,
- "Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r));
-
- if (e)
- dbus_error_free(e);
- }
- }
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) {
- r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, false, ignore_order, e);
- if (r < 0) {
- log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING,
- "Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r));
-
- if (e)
- dbus_error_free(e);
- }
- }
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i) {
- r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e);
- if (r < 0) {
- if (r != -EBADR)
- goto fail;
-
- if (e)
- dbus_error_free(e);
- }
- }
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) {
- r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e);
- if (r < 0) {
- log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING,
- "Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r));
-
- if (e)
- dbus_error_free(e);
- }
- }
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i) {
- r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e);
- if (r < 0) {
- if (r != -EBADR)
- goto fail;
-
- if (e)
- dbus_error_free(e);
- }
- }
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) {
- r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e);
- if (r < 0) {
- log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->id, bus_error(e, r));
-
- if (e)
- dbus_error_free(e);
- }
- }
-
- }
-
- if (type == JOB_STOP || type == JOB_RESTART) {
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRED_BY], i) {
- r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
- if (r < 0) {
- if (r != -EBADR)
- goto fail;
-
- if (e)
- dbus_error_free(e);
- }
- }
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_BOUND_BY], i) {
- r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
- if (r < 0) {
- if (r != -EBADR)
- goto fail;
-
- if (e)
- dbus_error_free(e);
- }
- }
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONSISTS_OF], i) {
- r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
- if (r < 0) {
- if (r != -EBADR)
- goto fail;
-
- if (e)
- dbus_error_free(e);
- }
- }
-
- }
-
- if (type == JOB_RELOAD) {
-
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) {
- r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e);
- if (r < 0) {
- log_warning("Cannot add dependency reload job for unit %s, ignoring: %s", dep->id, bus_error(e, r));
-
- if (e)
- dbus_error_free(e);
- }
- }
- }
-
- /* JOB_VERIFY_STARTED require no dependency handling */
- }
-
- return 0;
-
-fail:
- return r;
-}
-
-int transaction_add_isolate_jobs(Transaction *tr, Manager *m) {
- Iterator i;
- Unit *u;
- char *k;
- int r;
-
- assert(tr);
- assert(m);
-
- HASHMAP_FOREACH_KEY(u, k, m->units, i) {
-
- /* ignore aliases */
- if (u->id != k)
- continue;
-
- if (u->ignore_on_isolate)
- continue;
-
- /* No need to stop inactive jobs */
- if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(u)) && !u->job)
- continue;
-
- /* Is there already something listed for this? */
- if (hashmap_get(tr->jobs, u))
- continue;
-
- r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, tr->anchor_job, true, false, false, false, false, NULL);
- if (r < 0)
- log_warning("Cannot add isolate job for unit %s, ignoring: %s", u->id, strerror(-r));
- }
-
- return 0;
-}
-
-Transaction *transaction_new(void) {
- Transaction *tr;
-
- tr = new0(Transaction, 1);
- if (!tr)
- return NULL;
-
- tr->jobs = hashmap_new(trivial_hash_func, trivial_compare_func);
- if (!tr->jobs) {
- free(tr);
- return NULL;
- }
-
- 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 67ace4da0b..0000000000
--- a/src/core/transaction.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#ifndef footransactionhfoo
-#define footransactionhfoo
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-typedef struct Transaction Transaction;
-
-#include "unit.h"
-#include "manager.h"
-#include "job.h"
-#include "hashmap.h"
-
-struct Transaction {
- /* Jobs to be added */
- Hashmap *jobs; /* Unit object => Job object list 1:1 */
- Job *anchor_job; /* the job the user asked for */
-};
-
-Transaction *transaction_new(void);
-void transaction_free(Transaction *tr);
-
-int transaction_add_job_and_dependencies(
- Transaction *tr,
- JobType type,
- Unit *unit,
- Job *by,
- bool matters,
- bool override,
- bool conflicts,
- bool ignore_requirements,
- bool ignore_order,
- DBusError *e);
-int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e);
-int transaction_add_isolate_jobs(Transaction *tr, Manager *m);
-void transaction_abort(Transaction *tr);
-
-#endif
diff --git a/src/core/umount.c b/src/core/umount.c
deleted file mode 100644
index 83c9de3e82..0000000000
--- a/src/core/umount.c
+++ /dev/null
@@ -1,639 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 ProFUSION embedded systems
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <sys/mount.h>
-#include <sys/swap.h>
-#include <unistd.h>
-#include <linux/loop.h>
-#include <linux/dm-ioctl.h>
-#include <libudev.h>
-
-#include "list.h"
-#include "mount-setup.h"
-#include "umount.h"
-#include "path-util.h"
-#include "util.h"
-#include "virt.h"
-
-typedef struct MountPoint {
- char *path;
- dev_t devnum;
- LIST_FIELDS (struct MountPoint, mount_point);
-} MountPoint;
-
-static void mount_point_free(MountPoint **head, MountPoint *m) {
- assert(head);
- assert(m);
-
- LIST_REMOVE(MountPoint, 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) {
- FILE *proc_self_mountinfo;
- char *path, *p;
- unsigned int i;
- int r;
-
- assert(head);
-
- if (!(proc_self_mountinfo = fopen("/proc/self/mountinfo", "re")))
- return -errno;
-
- for (i = 1;; i++) {
- int k;
- MountPoint *m;
-
- path = p = NULL;
-
- if ((k = fscanf(proc_self_mountinfo,
- "%*s " /* (1) mount id */
- "%*s " /* (2) parent id */
- "%*s " /* (3) major:minor */
- "%*s " /* (4) root */
- "%ms " /* (5) mount point */
- "%*s" /* (6) mount options */
- "%*[^-]" /* (7) optional fields */
- "- " /* (8) separator */
- "%*s " /* (9) file system type */
- "%*s" /* (10) mount source */
- "%*s" /* (11) mount options 2 */
- "%*[^\n]", /* some rubbish at the end */
- &path)) != 1) {
- if (k == EOF)
- break;
-
- log_warning("Failed to parse /proc/self/mountinfo:%u.", i);
-
- free(path);
- continue;
- }
-
- p = cunescape(path);
- free(path);
-
- if (!p) {
- r = -ENOMEM;
- goto finish;
- }
-
- /* Ignore mount points we can't unmount because they
- * are API or because we are keeping them open (like
- * /dev/console) */
- if (mount_point_is_api(p) ||
- mount_point_ignore(p) ||
- path_equal(p, "/dev/console")) {
- free(p);
- continue;
- }
-
- if (!(m = new0(MountPoint, 1))) {
- free(p);
- r = -ENOMEM;
- goto finish;
- }
-
- m->path = p;
- LIST_PREPEND(MountPoint, mount_point, *head, m);
- }
-
- r = 0;
-
-finish:
- fclose(proc_self_mountinfo);
-
- return r;
-}
-
-static int swap_list_get(MountPoint **head) {
- FILE *proc_swaps;
- unsigned int i;
- int r;
-
- assert(head);
-
- if (!(proc_swaps = fopen("/proc/swaps", "re")))
- return (errno == ENOENT) ? 0 : -errno;
-
- (void) fscanf(proc_swaps, "%*s %*s %*s %*s %*s\n");
-
- for (i = 2;; i++) {
- MountPoint *swap;
- char *dev = NULL, *d;
- int k;
-
- if ((k = fscanf(proc_swaps,
- "%ms " /* device/file */
- "%*s " /* type of swap */
- "%*s " /* swap size */
- "%*s " /* used */
- "%*s\n", /* priority */
- &dev)) != 1) {
-
- if (k == EOF)
- break;
-
- log_warning("Failed to parse /proc/swaps:%u.", i);
-
- free(dev);
- continue;
- }
-
- if (endswith(dev, "(deleted)")) {
- free(dev);
- continue;
- }
-
- d = cunescape(dev);
- free(dev);
-
- if (!d) {
- r = -ENOMEM;
- goto finish;
- }
-
- if (!(swap = new0(MountPoint, 1))) {
- free(d);
- r = -ENOMEM;
- goto finish;
- }
-
- swap->path = d;
- LIST_PREPEND(MountPoint, mount_point, *head, swap);
- }
-
- r = 0;
-
-finish:
- fclose(proc_swaps);
-
- return r;
-}
-
-static int loopback_list_get(MountPoint **head) {
- int r;
- struct udev *udev;
- struct udev_enumerate *e = NULL;
- struct udev_list_entry *item = NULL, *first = NULL;
-
- assert(head);
-
- if (!(udev = udev_new())) {
- r = -ENOMEM;
- goto finish;
- }
-
- if (!(e = udev_enumerate_new(udev))) {
- r = -ENOMEM;
- goto finish;
- }
-
- if (udev_enumerate_add_match_subsystem(e, "block") < 0 ||
- udev_enumerate_add_match_sysname(e, "loop*") < 0) {
- r = -EIO;
- goto finish;
- }
-
- if (udev_enumerate_scan_devices(e) < 0) {
- r = -EIO;
- goto finish;
- }
-
- first = udev_enumerate_get_list_entry(e);
- udev_list_entry_foreach(item, first) {
- MountPoint *lb;
- struct udev_device *d;
- char *loop;
- const char *dn;
-
- if (!(d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)))) {
- r = -ENOMEM;
- goto finish;
- }
-
- if (!(dn = udev_device_get_devnode(d))) {
- udev_device_unref(d);
- continue;
- }
-
- loop = strdup(dn);
- udev_device_unref(d);
-
- if (!loop) {
- r = -ENOMEM;
- goto finish;
- }
-
- if (!(lb = new0(MountPoint, 1))) {
- free(loop);
- r = -ENOMEM;
- goto finish;
- }
-
- lb->path = loop;
- LIST_PREPEND(MountPoint, mount_point, *head, lb);
- }
-
- r = 0;
-
-finish:
- if (e)
- udev_enumerate_unref(e);
-
- if (udev)
- udev_unref(udev);
-
- return r;
-}
-
-static int dm_list_get(MountPoint **head) {
- int r;
- struct udev *udev;
- struct udev_enumerate *e = NULL;
- struct udev_list_entry *item = NULL, *first = NULL;
-
- assert(head);
-
- if (!(udev = udev_new())) {
- r = -ENOMEM;
- goto finish;
- }
-
- if (!(e = udev_enumerate_new(udev))) {
- r = -ENOMEM;
- goto finish;
- }
-
- if (udev_enumerate_add_match_subsystem(e, "block") < 0 ||
- udev_enumerate_add_match_sysname(e, "dm-*") < 0) {
- r = -EIO;
- goto finish;
- }
-
- if (udev_enumerate_scan_devices(e) < 0) {
- r = -EIO;
- goto finish;
- }
-
- first = udev_enumerate_get_list_entry(e);
-
- udev_list_entry_foreach(item, first) {
- MountPoint *m;
- struct udev_device *d;
- dev_t devnum;
- char *node;
- const char *dn;
-
- if (!(d = udev_device_new_from_syspath(udev, udev_list_entry_get_name(item)))) {
- r = -ENOMEM;
- goto finish;
- }
-
- devnum = udev_device_get_devnum(d);
- dn = udev_device_get_devnode(d);
-
- if (major(devnum) == 0 || !dn) {
- udev_device_unref(d);
- continue;
- }
-
- node = strdup(dn);
- udev_device_unref(d);
-
- if (!node) {
- r = -ENOMEM;
- goto finish;
- }
-
- if (!(m = new(MountPoint, 1))) {
- free(node);
- r = -ENOMEM;
- goto finish;
- }
-
- m->path = node;
- m->devnum = devnum;
- LIST_PREPEND(MountPoint, mount_point, *head, m);
- }
-
- r = 0;
-
-finish:
- if (e)
- udev_enumerate_unref(e);
-
- if (udev)
- udev_unref(udev);
-
- return r;
-}
-
-static int delete_loopback(const char *device) {
- int fd, r;
-
- if ((fd = open(device, O_RDONLY|O_CLOEXEC)) < 0)
- return errno == ENOENT ? 0 : -errno;
-
- r = ioctl(fd, LOOP_CLR_FD, 0);
- close_nointr_nofail(fd);
-
- 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) {
- int fd, r;
- struct dm_ioctl dm;
-
- assert(major(devnum) != 0);
-
- if ((fd = open("/dev/mapper/control", O_RDWR|O_CLOEXEC)) < 0)
- return -errno;
-
- zero(dm);
- dm.version[0] = DM_VERSION_MAJOR;
- dm.version[1] = DM_VERSION_MINOR;
- dm.version[2] = DM_VERSION_PATCHLEVEL;
-
- dm.data_size = sizeof(dm);
- dm.dev = devnum;
-
- r = ioctl(fd, DM_DEV_REMOVE, &dm);
- close_nointr_nofail(fd);
-
- 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 (path_equal(m->path, "/")
-#ifndef HAVE_SPLIT_USR
- || path_equal(m->path, "/usr")
-#endif
- ) {
- n_failed++;
- continue;
- }
-
- /* Trying to umount. Forcing to umount if busy (only for NFS mounts) */
- if (umount2(m->path, MNT_FORCE) == 0) {
- log_info("Unmounted %s.", m->path);
- if (changed)
- *changed = true;
-
- mount_point_free(head, m);
- } else if (log_error) {
- log_warning("Could not unmount %s: %m", m->path);
- n_failed++;
- }
- }
-
- return n_failed;
-}
-
-static int mount_points_list_remount_read_only(MountPoint **head, bool *changed) {
- MountPoint *m, *n;
- int n_failed = 0;
-
- assert(head);
-
- LIST_FOREACH_SAFE(mount_point, m, n, *head) {
-
- /* Trying to remount read-only */
- if (mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, NULL) == 0) {
- if (changed)
- *changed = true;
-
- mount_point_free(head, m);
- } else {
- log_warning("Could not remount as read-only %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) {
- if (swapoff(m->path) == 0) {
- if (changed)
- *changed = true;
-
- mount_point_free(head, m);
- } else {
- log_warning("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;
- }
-
- if ((r = delete_loopback(m->path)) >= 0) {
-
- if (r > 0 && changed)
- *changed = true;
-
- mount_point_free(head, m);
- } else {
- log_warning("Could not delete 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;
- }
-
- if ((r = delete_dm(m->devnum)) >= 0) {
-
- if (r > 0 && changed)
- *changed = true;
-
- mount_point_free(head, m);
- } else {
- log_warning("Could not delete 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(MountPoint, 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;
-
- /* If we are in a container, don't attempt to read-only mount
- anything as that brings no real benefits, but might confuse
- the host, as we remount the superblock here, not the bind
- mound. */
- if (detect_container(NULL) <= 0)
- r = mount_points_list_remount_read_only(&mp_list_head, changed);
-
- 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(MountPoint, 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(MountPoint, 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(MountPoint, 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 8439ffe58f..0000000000
--- a/src/core/umount.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 ProFUSION embedded systems
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-int umount_all(bool *changed);
-
-int swapoff_all(bool *changed);
-
-int loopback_detach_all(bool *changed);
-
-int dm_detach_all(bool *changed);
diff --git a/src/core/unit-printf.c b/src/core/unit-printf.c
deleted file mode 100644
index cbae45d9f7..0000000000
--- a/src/core/unit-printf.c
+++ /dev/null
@@ -1,346 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "systemd/sd-id128.h"
-#include "unit.h"
-#include "specifier.h"
-#include "path-util.h"
-#include "strv.h"
-#include "unit-name.h"
-#include "unit-printf.h"
-
-static char *specifier_prefix_and_instance(char specifier, void *data, void *userdata) {
- Unit *u = userdata;
- assert(u);
-
- return unit_name_to_prefix_and_instance(u->id);
-}
-
-static char *specifier_prefix(char specifier, void *data, void *userdata) {
- Unit *u = userdata;
- assert(u);
-
- return unit_name_to_prefix(u->id);
-}
-
-static char *specifier_prefix_unescaped(char specifier, void *data, void *userdata) {
- Unit *u = userdata;
- char *p, *r;
-
- assert(u);
-
- p = unit_name_to_prefix(u->id);
- if (!p)
- return NULL;
-
- r = unit_name_unescape(p);
- free(p);
-
- return r;
-}
-
-static char *specifier_instance_unescaped(char specifier, void *data, void *userdata) {
- Unit *u = userdata;
- assert(u);
-
- if (u->instance)
- return unit_name_unescape(u->instance);
-
- return strdup("");
-}
-
-static char *specifier_filename(char specifier, void *data, void *userdata) {
- Unit *u = userdata;
- assert(u);
-
- if (u->instance)
- return unit_name_path_unescape(u->instance);
-
- return unit_name_to_path(u->id);
-}
-
-static char *specifier_cgroup(char specifier, void *data, void *userdata) {
- Unit *u = userdata;
- assert(u);
-
- return unit_default_cgroup_path(u);
-}
-
-static char *specifier_cgroup_root(char specifier, void *data, void *userdata) {
- Unit *u = userdata;
- char *p;
- assert(u);
-
- if (specifier == 'r')
- return strdup(u->manager->cgroup_hierarchy);
-
- if (path_get_parent(u->manager->cgroup_hierarchy, &p) < 0)
- return strdup("");
-
- if (streq(p, "/")) {
- free(p);
- return strdup("");
- }
-
- return p;
-}
-
-static char *specifier_runtime(char specifier, void *data, void *userdata) {
- Unit *u = userdata;
- assert(u);
-
- if (u->manager->running_as == SYSTEMD_USER) {
- const char *e;
-
- e = getenv("XDG_RUNTIME_DIR");
- if (e)
- return strdup(e);
- }
-
- return strdup("/run");
-}
-
-static char *specifier_user_name(char specifier, void *data, void *userdata) {
- Unit *u = userdata;
- ExecContext *c;
- int r;
- const char *username;
-
- assert(u);
-
- c = unit_get_exec_context(u);
- if (!c)
- return NULL;
-
- /* get USER env from our own env if set */
- if (!c->user)
- return getusername_malloc();
-
- /* fish username from passwd */
- username = c->user;
- r = get_user_creds(&username, NULL, NULL, NULL, NULL);
- if (r < 0)
- return NULL;
-
- return strdup(username);
-}
-
-static char *specifier_user_home(char specifier, void *data, void *userdata) {
- Unit *u = userdata;
- ExecContext *c;
- int r;
- const char *username, *home;
-
- assert(u);
-
- c = unit_get_exec_context(u);
- if (!c)
- return NULL;
-
- /* return HOME if set, otherwise from passwd */
- if (!c->user) {
- char *h;
-
- r = get_home_dir(&h);
- if (r < 0)
- return NULL;
-
- return h;
- }
-
- username = c->user;
- r = get_user_creds(&username, NULL, NULL, &home, NULL);
- if (r < 0)
- return NULL;
-
- return strdup(home);
-}
-
-static char *specifier_user_shell(char specifier, void *data, void *userdata) {
- Unit *u = userdata;
- ExecContext *c;
- int r;
- const char *username, *shell;
-
- assert(u);
-
- c = unit_get_exec_context(u);
- if (!c)
- return NULL;
-
- /* return HOME if set, otherwise from passwd */
- if (!c->user) {
- char *sh;
-
- r = get_shell(&sh);
- if (r < 0)
- return strdup("/bin/sh");
-
- return sh;
- }
-
- username = c->user;
- r = get_user_creds(&username, NULL, NULL, NULL, &shell);
- if (r < 0)
- return strdup("/bin/sh");
-
- return strdup(shell);
-}
-
-static char *specifier_machine_id(char specifier, void *data, void *userdata) {
- sd_id128_t id;
- char *buf;
- int r;
-
- r = sd_id128_get_machine(&id);
- if (r < 0)
- return NULL;
-
- buf = new(char, 33);
- if (!buf)
- return NULL;
-
- return sd_id128_to_string(id, buf);
-}
-
-static char *specifier_boot_id(char specifier, void *data, void *userdata) {
- sd_id128_t id;
- char *buf;
- int r;
-
- r = sd_id128_get_boot(&id);
- if (r < 0)
- return NULL;
-
- buf = new(char, 33);
- if (!buf)
- return NULL;
-
- return sd_id128_to_string(id, buf);
-}
-
-static char *specifier_host_name(char specifier, void *data, void *userdata) {
- return gethostname_malloc();
-}
-
-char *unit_name_printf(Unit *u, const char* format) {
-
- /*
- * 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);
-
- return specifier_printf(format, table, u);
-}
-
-char *unit_full_printf(Unit *u, const char *format) {
-
- /* This is similar to unit_name_printf() but also supports
- * unescaping. Also, adds a couple of additional codes:
- *
- * %f the the instance if set, otherwise the id
- * %c cgroup path of unit
- * %r root cgroup path of this systemd instance (e.g. "/user/lennart/shared/systemd-4711")
- * %R parent of root cgroup path (e.g. "/usr/lennart/shared")
- * %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR)
- * %u the username of the configured user or running user
- * %h the homedir of the configured user or running user
- * %s the shell of the configured user or running user
- * %m the machine ID of the running system
- * %b the boot ID of the running system
- * %H the host name of the running system
- */
-
- const Specifier table[] = {
- { 'n', specifier_string, u->id },
- { 'N', specifier_prefix_and_instance, NULL },
- { 'p', specifier_prefix, NULL },
- { 'P', specifier_prefix_unescaped, NULL },
- { 'i', specifier_string, u->instance },
- { 'I', specifier_instance_unescaped, NULL },
-
- { 'f', specifier_filename, NULL },
- { 'c', specifier_cgroup, NULL },
- { 'r', specifier_cgroup_root, NULL },
- { 'R', specifier_cgroup_root, NULL },
- { 't', specifier_runtime, NULL },
- { 'u', specifier_user_name, NULL },
- { '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 },
- { 0, NULL, NULL }
- };
-
- assert(u);
- assert(format);
-
- return specifier_printf(format, table, u);
-}
-
-char **unit_full_printf_strv(Unit *u, char **l) {
- size_t n;
- char **r, **i, **j;
-
- /* Applies unit_full_printf to every entry in l */
-
- assert(u);
-
- n = strv_length(l);
- r = new(char*, n+1);
- if (!r)
- return NULL;
-
- for (i = l, j = r; *i; i++, j++) {
- *j = unit_full_printf(u, *i);
- if (!*j)
- goto fail;
- }
-
- *j = NULL;
- return r;
-
-fail:
- for (j--; j >= r; j--)
- free(*j);
-
- free(r);
-
- return NULL;
-}
diff --git a/src/core/unit-printf.h b/src/core/unit-printf.h
deleted file mode 100644
index d2f4ccd178..0000000000
--- a/src/core/unit-printf.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "unit.h"
-
-char *unit_name_printf(Unit *u, const char* text);
-char *unit_full_printf(Unit *u, const char *text);
-char **unit_full_printf_strv(Unit *u, char **l);
diff --git a/src/core/unit.c b/src/core/unit.c
deleted file mode 100644
index 99e1c27948..0000000000
--- a/src/core/unit.c
+++ /dev/null
@@ -1,2738 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <assert.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include <sys/timerfd.h>
-#include <sys/poll.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <sys/stat.h>
-
-#include "systemd/sd-id128.h"
-#include "systemd/sd-messages.h"
-#include "set.h"
-#include "unit.h"
-#include "macro.h"
-#include "strv.h"
-#include "path-util.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
-#include "log.h"
-#include "unit-name.h"
-#include "dbus-unit.h"
-#include "special.h"
-#include "cgroup-util.h"
-#include "missing.h"
-#include "cgroup-attr.h"
-
-const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
- [UNIT_SERVICE] = &service_vtable,
- [UNIT_TIMER] = &timer_vtable,
- [UNIT_SOCKET] = &socket_vtable,
- [UNIT_TARGET] = &target_vtable,
- [UNIT_DEVICE] = &device_vtable,
- [UNIT_MOUNT] = &mount_vtable,
- [UNIT_AUTOMOUNT] = &automount_vtable,
- [UNIT_SNAPSHOT] = &snapshot_vtable,
- [UNIT_SWAP] = &swap_vtable,
- [UNIT_PATH] = &path_vtable
-};
-
-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_func, string_compare_func);
- if (!u->names) {
- free(u);
- return NULL;
- }
-
- u->manager = m;
- u->type = _UNIT_TYPE_INVALID;
- u->deserialized_job = _JOB_TYPE_INVALID;
- u->default_dependencies = true;
- u->unit_file_state = _UNIT_FILE_STATE_INVALID;
-
- return u;
-}
-
-bool unit_has_name(Unit *u, const char *name) {
- assert(u);
- assert(name);
-
- return !!set_get(u->names, (char*) name);
-}
-
-int unit_add_name(Unit *u, const char *text) {
- UnitType t;
- char *s, *i = NULL;
- int r;
-
- assert(u);
- assert(text);
-
- if (unit_name_is_template(text)) {
- if (!u->instance)
- return -EINVAL;
-
- s = unit_name_replace_instance(text, u->instance);
- } else
- s = strdup(text);
-
- if (!s)
- return -ENOMEM;
-
- if (!unit_name_is_valid(s, false)) {
- r = -EINVAL;
- goto fail;
- }
-
- assert_se((t = unit_name_to_type(s)) >= 0);
-
- if (u->type != _UNIT_TYPE_INVALID && t != u->type) {
- r = -EINVAL;
- goto fail;
- }
-
- if ((r = unit_name_to_instance(s, &i)) < 0)
- goto fail;
-
- if (i && unit_vtable[t]->no_instances) {
- r = -EINVAL;
- goto fail;
- }
-
- /* Ensure that this unit is either instanced or not instanced,
- * but not both. */
- if (u->type != _UNIT_TYPE_INVALID && !u->instance != !i) {
- r = -EINVAL;
- goto fail;
- }
-
- if (unit_vtable[t]->no_alias &&
- !set_isempty(u->names) &&
- !set_get(u->names, s)) {
- r = -EEXIST;
- goto fail;
- }
-
- if (hashmap_size(u->manager->units) >= MANAGER_MAX_NAMES) {
- r = -E2BIG;
- goto fail;
- }
-
- if ((r = set_put(u->names, s)) < 0) {
- if (r == -EEXIST)
- r = 0;
- goto fail;
- }
-
- if ((r = hashmap_put(u->manager->units, s, u)) < 0) {
- set_remove(u->names, s);
- goto fail;
- }
-
- if (u->type == _UNIT_TYPE_INVALID) {
-
- u->type = t;
- u->id = s;
- u->instance = i;
-
- LIST_PREPEND(Unit, units_by_type, u->manager->units_by_type[t], u);
-
- if (UNIT_VTABLE(u)->init)
- UNIT_VTABLE(u)->init(u);
- } else
- free(i);
-
- unit_add_to_dbus_queue(u);
- return 0;
-
-fail:
- free(s);
- free(i);
-
- return r;
-}
-
-int unit_choose_id(Unit *u, const char *name) {
- char *s, *t = NULL, *i;
- int r;
-
- assert(u);
- assert(name);
-
- if (unit_name_is_template(name)) {
-
- if (!u->instance)
- return -EINVAL;
-
- if (!(t = unit_name_replace_instance(name, u->instance)))
- return -ENOMEM;
-
- name = t;
- }
-
- /* Selects one of the names of this unit as the id */
- s = set_get(u->names, (char*) name);
- free(t);
-
- if (!s)
- return -ENOENT;
-
- if ((r = unit_name_to_instance(s, &i)) < 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 (!(s = strdup(description)))
- return -ENOMEM;
-
- free(u->description);
- u->description = s;
-
- unit_add_to_dbus_queue(u);
- return 0;
-}
-
-bool unit_check_gc(Unit *u) {
- assert(u);
-
- if (u->load_state == UNIT_STUB)
- return true;
-
- if (UNIT_VTABLE(u)->no_gc)
- return true;
-
- if (u->no_gc)
- return true;
-
- if (u->job)
- return true;
-
- if (u->nop_job)
- return true;
-
- if (unit_active_state(u) != UNIT_INACTIVE)
- 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(Unit, 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(Unit, 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(Unit, gc_queue, u->manager->gc_queue, u);
- u->in_gc_queue = true;
-
- u->manager->n_in_gc_queue ++;
-
- if (u->manager->gc_queue_timestamp <= 0)
- u->manager->gc_queue_timestamp = now(CLOCK_MONOTONIC);
-}
-
-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 (!bus_has_subscriber(u->manager)) {
- u->sent_dbus_new_signal = true;
- return;
- }
-
- LIST_PREPEND(Unit, 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);
-}
-
-void unit_free(Unit *u) {
- UnitDependency d;
- Iterator i;
- char *t;
-
- assert(u);
-
- bus_unit_send_removed_signal(u);
-
- if (u->load_state != UNIT_STUB)
- if (UNIT_VTABLE(u)->done)
- UNIT_VTABLE(u)->done(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->requires_mounts_for) {
- LIST_REMOVE(Unit, has_requires_mounts_for, u->manager->has_requires_mounts_for, u);
- strv_free(u->requires_mounts_for);
- }
-
- if (u->type != _UNIT_TYPE_INVALID)
- LIST_REMOVE(Unit, units_by_type, u->manager->units_by_type[u->type], u);
-
- if (u->in_load_queue)
- LIST_REMOVE(Unit, load_queue, u->manager->load_queue, u);
-
- if (u->in_dbus_queue)
- LIST_REMOVE(Unit, dbus_queue, u->manager->dbus_unit_queue, u);
-
- if (u->in_cleanup_queue)
- LIST_REMOVE(Unit, cleanup_queue, u->manager->cleanup_queue, u);
-
- if (u->in_gc_queue) {
- LIST_REMOVE(Unit, gc_queue, u->manager->gc_queue, u);
- u->manager->n_in_gc_queue--;
- }
-
- cgroup_bonding_free_list(u->cgroup_bondings, u->manager->n_reloading <= 0);
- cgroup_attribute_free_list(u->cgroup_attributes);
-
- free(u->description);
- strv_free(u->documentation);
- free(u->fragment_path);
- free(u->source_path);
- free(u->instance);
-
- set_free_free(u->names);
-
- condition_free_list(u->conditions);
-
- 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 void complete_move(Set **s, Set **other) {
- assert(s);
- assert(other);
-
- if (!*other)
- return;
-
- if (*s)
- set_move(*s, *other);
- else {
- *s = *other;
- *other = NULL;
- }
-}
-
-static void merge_names(Unit *u, Unit *other) {
- char *t;
- Iterator i;
-
- assert(u);
- assert(other);
-
- complete_move(&u->names, &other->names);
-
- 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);
-}
-
-static void merge_dependencies(Unit *u, Unit *other, 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++)
- if ((r = set_remove_and_put(back->dependencies[k], other, u)) < 0) {
-
- if (r == -EEXIST)
- set_remove(back->dependencies[k], other);
- else
- assert(r == -ENOENT);
- }
- }
-
- complete_move(&u->dependencies[d], &other->dependencies[d]);
-
- set_free(other->dependencies[d]);
- other->dependencies[d] = NULL;
-}
-
-int unit_merge(Unit *u, Unit *other) {
- UnitDependency d;
-
- 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_ERROR)
- 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;
-
- /* Merge names */
- merge_names(u, other);
-
- /* 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, 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;
- char *s = NULL;
-
- assert(u);
- assert(name);
-
- if (unit_name_is_template(name)) {
- if (!u->instance)
- return -EINVAL;
-
- if (!(s = unit_name_replace_instance(name, u->instance)))
- return -ENOMEM;
-
- name = s;
- }
-
- if (!(other = manager_get_unit(u->manager, name)))
- r = unit_add_name(u, name);
- else
- r = unit_merge(u, other);
-
- free(s);
- return r;
-}
-
-Unit* unit_follow_merge(Unit *u) {
- assert(u);
-
- while (u->load_state == UNIT_MERGED)
- assert_se(u = u->merged_into);
-
- return u;
-}
-
-int unit_add_exec_dependencies(Unit *u, ExecContext *c) {
- int r;
-
- assert(u);
- assert(c);
-
- if (c->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. */
-
- if (u->manager->running_as == SYSTEMD_SYSTEM)
- if ((r = unit_add_two_dependencies_by_name(u, UNIT_REQUIRES, UNIT_AFTER, SPECIAL_JOURNALD_SOCKET, NULL, true)) < 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;
- char *p2;
- const char *prefix2;
- char
- timestamp1[FORMAT_TIMESTAMP_MAX],
- timestamp2[FORMAT_TIMESTAMP_MAX],
- timestamp3[FORMAT_TIMESTAMP_MAX],
- timestamp4[FORMAT_TIMESTAMP_MAX],
- timespan[FORMAT_TIMESPAN_MAX];
- Unit *following;
-
- assert(u);
- assert(u->type >= 0);
-
- if (!prefix)
- prefix = "";
- p2 = strappend(prefix, "\t");
- prefix2 = p2 ? p2 : prefix;
-
- fprintf(f,
- "%s-> Unit %s:\n"
- "%s\tDescription: %s\n"
- "%s\tInstance: %s\n"
- "%s\tUnit Load State: %s\n"
- "%s\tUnit Active State: %s\n"
- "%s\tInactive Exit Timestamp: %s\n"
- "%s\tActive Enter Timestamp: %s\n"
- "%s\tActive Exit Timestamp: %s\n"
- "%s\tInactive Enter Timestamp: %s\n"
- "%s\tGC Check Good: %s\n"
- "%s\tNeed Daemon Reload: %s\n",
- prefix, u->id,
- prefix, unit_description(u),
- prefix, strna(u->instance),
- prefix, unit_load_state_to_string(u->load_state),
- prefix, unit_active_state_to_string(unit_active_state(u)),
- prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->inactive_exit_timestamp.realtime)),
- prefix, strna(format_timestamp(timestamp2, sizeof(timestamp2), u->active_enter_timestamp.realtime)),
- prefix, strna(format_timestamp(timestamp3, sizeof(timestamp3), u->active_exit_timestamp.realtime)),
- prefix, strna(format_timestamp(timestamp4, sizeof(timestamp4), u->inactive_enter_timestamp.realtime)),
- prefix, yes_no(unit_check_gc(u)),
- prefix, yes_no(unit_need_daemon_reload(u)));
-
- 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);
-
- if ((following = unit_following(u)))
- fprintf(f, "%s\tFollowing: %s\n", prefix, following->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);
-
- if (u->job_timeout > 0)
- fprintf(f, "%s\tJob Timeout: %s\n", prefix, format_timespan(timespan, sizeof(timespan), u->job_timeout));
-
- condition_dump_list(u->conditions, f, prefix);
-
- 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));
-
- 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) {
- CGroupBonding *b;
- CGroupAttribute *a;
-
- fprintf(f,
- "%s\tStopWhenUnneeded: %s\n"
- "%s\tRefuseManualStart: %s\n"
- "%s\tRefuseManualStop: %s\n"
- "%s\tDefaultDependencies: %s\n"
- "%s\tOnFailureIsolate: %s\n"
- "%s\tIgnoreOnIsolate: %s\n"
- "%s\tIgnoreOnSnapshot: %s\n",
- prefix, yes_no(u->stop_when_unneeded),
- prefix, yes_no(u->refuse_manual_start),
- prefix, yes_no(u->refuse_manual_stop),
- prefix, yes_no(u->default_dependencies),
- prefix, yes_no(u->on_failure_isolate),
- prefix, yes_no(u->ignore_on_isolate),
- prefix, yes_no(u->ignore_on_snapshot));
-
- LIST_FOREACH(by_unit, b, u->cgroup_bondings)
- fprintf(f, "%s\tControlGroup: %s:%s\n",
- prefix, b->controller, b->path);
-
- LIST_FOREACH(by_unit, a, u->cgroup_attributes) {
- char *v = NULL;
-
- if (a->map_callback)
- a->map_callback(a->controller, a->name, a->value, &v);
-
- fprintf(f, "%s\tControlGroupAttribute: %s %s \"%s\"\n",
- prefix, a->controller, a->name, v ? v : a->value);
-
- free(v);
- }
-
- 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);
-
- free(p2);
-}
-
-/* Common implementation for multiple backends */
-int unit_load_fragment_and_dropin(Unit *u) {
- int r;
-
- assert(u);
-
- /* Load a .service file */
- if ((r = unit_load_fragment(u)) < 0)
- return r;
-
- if (u->load_state == UNIT_STUB)
- return -ENOENT;
-
- /* Load drop-in directory data */
- if ((r = unit_load_dropin(unit_follow_merge(u))) < 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 */
- if ((r = unit_load_fragment(u)) < 0)
- return r;
-
- if (u->load_state == UNIT_STUB)
- u->load_state = UNIT_LOADED;
-
- /* Load drop-in directory data */
- if ((r = unit_load_dropin(unit_follow_merge(u))) < 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_default_dependencies(Unit *u) {
- static const UnitDependency deps[] = {
- UNIT_REQUIRED_BY,
- UNIT_REQUIRED_BY_OVERRIDABLE,
- UNIT_WANTED_BY,
- UNIT_BOUND_BY
- };
-
- Unit *target;
- Iterator i;
- int r;
- unsigned k;
-
- assert(u);
-
- for (k = 0; k < ELEMENTSOF(deps); k++)
- SET_FOREACH(target, u->dependencies[deps[k]], i)
- if ((r = unit_add_default_target_dependency(u, target)) < 0)
- return r;
-
- return 0;
-}
-
-int unit_load(Unit *u) {
- int r;
-
- assert(u);
-
- if (u->in_load_queue) {
- LIST_REMOVE(Unit, 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)
- if ((r = UNIT_VTABLE(u)->load(u)) < 0)
- goto fail;
-
- if (u->load_state == UNIT_STUB) {
- r = -ENOENT;
- goto fail;
- }
-
- if (u->load_state == UNIT_LOADED &&
- u->default_dependencies)
- if ((r = unit_add_default_dependencies(u)) < 0)
- goto fail;
-
- if (u->load_state == UNIT_LOADED) {
- r = unit_add_mount_links(u);
- if (r < 0)
- return r;
- }
-
- if (u->on_failure_isolate &&
- set_size(u->dependencies[UNIT_ON_FAILURE]) > 1) {
-
- log_error("More than one OnFailure= dependencies specified for %s but OnFailureIsolate= enabled. Refusing.",
- u->id);
-
- r = -EINVAL;
- goto fail;
- }
-
- 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 = UNIT_ERROR;
- u->load_error = r;
- unit_add_to_dbus_queue(u);
- unit_add_to_gc_queue(u);
-
- log_debug("Failed to load configuration for %s: %s", u->id, strerror(-r));
-
- return r;
-}
-
-bool unit_condition_test(Unit *u) {
- assert(u);
-
- dual_timestamp_get(&u->condition_timestamp);
- u->condition_result = condition_test_list(u->conditions);
-
- return u->condition_result;
-}
-
-static const char* unit_get_status_message_format(Unit *u, JobType t) {
- const UnitStatusMessageFormats *format_table;
-
- assert(u);
- assert(t >= 0);
- assert(t < _JOB_TYPE_MAX);
-
- if (t != JOB_START && t != JOB_STOP)
- return NULL;
-
- format_table = &UNIT_VTABLE(u)->status_message_formats;
- if (!format_table)
- return NULL;
-
- return format_table->starting_stopping[t == JOB_STOP];
-}
-
-static const char *unit_get_status_message_format_try_harder(Unit *u, JobType t) {
- const char *format;
-
- assert(u);
- assert(t >= 0);
- assert(t < _JOB_TYPE_MAX);
-
- format = unit_get_status_message_format(u, t);
- if (format)
- return format;
-
- /* Return generic strings */
- if (t == JOB_START)
- return "Starting %s.";
- else if (t == JOB_STOP)
- return "Stopping %s.";
- else if (t == JOB_RELOAD)
- return "Reloading %s.";
-
- return NULL;
-}
-
-static void unit_status_print_starting_stopping(Unit *u, JobType t) {
- const char *format;
-
- assert(u);
-
- /* We only print status messages for selected units on
- * selected operations. */
-
- format = unit_get_status_message_format(u, t);
- if (!format)
- return;
-
- unit_status_printf(u, "", format, unit_description(u));
-}
-
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wformat-nonliteral"
-static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
- const char *format;
- char buf[LINE_MAX];
- sd_id128_t mid;
-
- assert(u);
-
- if (t != JOB_START && t != JOB_STOP && t != JOB_RELOAD)
- return;
-
- if (log_on_console())
- return;
-
- /* We log status messages for all units and all operations. */
-
- format = unit_get_status_message_format_try_harder(u, t);
- if (!format)
- return;
-
- snprintf(buf, sizeof(buf), format, unit_description(u));
- char_array_0(buf);
-
- mid = t == JOB_START ? SD_MESSAGE_UNIT_STARTING :
- t == JOB_STOP ? SD_MESSAGE_UNIT_STOPPING :
- SD_MESSAGE_UNIT_RELOADING;
-
- log_struct(LOG_INFO,
- MESSAGE_ID(mid),
- "UNIT=%s", u->id,
- "MESSAGE=%s", buf,
- NULL);
-}
-#pragma GCC diagnostic pop
-
-/* 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.
- */
-int unit_start(Unit *u) {
- UnitActiveState state;
- Unit *following;
-
- assert(u);
-
- if (u->load_state != UNIT_LOADED)
- return -EINVAL;
-
- /* If this is already started, then this will succeed. Note
- * that this will even succeed if this unit is not startable
- * by the user. This is relied on to detect when we need to
- * wait for units and when waiting is finished. */
- state = unit_active_state(u);
- if (UNIT_IS_ACTIVE_OR_RELOADING(state))
- return -EALREADY;
-
- /* If the conditions failed, don't do anything at all. If we
- * already are activating this call might still be useful to
- * speed up activation in case there is some hold-off time,
- * but we don't want to recheck the condition in that case. */
- if (state != UNIT_ACTIVATING &&
- !unit_condition_test(u)) {
- log_debug("Starting of %s requested but condition failed. Ignoring.", u->id);
- return -EALREADY;
- }
-
- /* Forward to the main object, if we aren't it. */
- if ((following = unit_following(u))) {
- log_debug("Redirecting start request from %s to %s.", u->id, following->id);
- return unit_start(following);
- }
-
- unit_status_log_starting_stopping_reloading(u, JOB_START);
- unit_status_print_starting_stopping(u, JOB_START);
-
- /* 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);
-
- 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;
-
- if ((following = unit_following(u))) {
- log_debug("Redirecting stop request from %s to %s.", u->id, following->id);
- return unit_stop(following);
- }
-
- unit_status_log_starting_stopping_reloading(u, JOB_STOP);
- unit_status_print_starting_stopping(u, JOB_STOP);
-
- 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)
- return -ENOEXEC;
-
- if ((following = unit_following(u))) {
- log_debug("Redirecting reload request from %s to %s.", u->id, following->id);
- return unit_reload(following);
- }
-
- unit_status_log_starting_stopping_reloading(u, JOB_RELOAD);
-
- 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) {
- Iterator i;
- Unit *other;
-
- assert(u);
-
- /* If this service shall be shut down when unneeded then do
- * so. */
-
- if (!u->stop_when_unneeded)
- return;
-
- if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)))
- return;
-
- SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i)
- if (unit_pending_active(other))
- return;
-
- SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
- if (unit_pending_active(other))
- return;
-
- SET_FOREACH(other, u->dependencies[UNIT_WANTED_BY], i)
- if (unit_pending_active(other))
- return;
-
- SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
- if (unit_pending_active(other))
- return;
-
- log_info("Service %s is not needed anymore. Stopping.", u->id);
-
- /* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */
- manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, true, NULL, NULL);
-}
-
-static void retroactively_start_dependencies(Unit *u) {
- Iterator i;
- Unit *other;
-
- assert(u);
- assert(UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)));
-
- SET_FOREACH(other, u->dependencies[UNIT_REQUIRES], i)
- if (!set_get(u->dependencies[UNIT_AFTER], other) &&
- !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
- manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL);
-
- SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], i)
- if (!set_get(u->dependencies[UNIT_AFTER], other) &&
- !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
- manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL);
-
- SET_FOREACH(other, u->dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
- if (!set_get(u->dependencies[UNIT_AFTER], other) &&
- !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
- manager_add_job(u->manager, JOB_START, other, JOB_FAIL, false, NULL, NULL);
-
- SET_FOREACH(other, u->dependencies[UNIT_REQUISITE], i)
- if (!set_get(u->dependencies[UNIT_AFTER], other) &&
- !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
- manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL);
-
- SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
- if (!set_get(u->dependencies[UNIT_AFTER], other) &&
- !UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
- manager_add_job(u->manager, JOB_START, other, JOB_FAIL, false, NULL, NULL);
-
- SET_FOREACH(other, u->dependencies[UNIT_CONFLICTS], i)
- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
- manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL);
-
- SET_FOREACH(other, u->dependencies[UNIT_CONFLICTED_BY], i)
- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
- manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL);
-}
-
-static void retroactively_stop_dependencies(Unit *u) {
- Iterator i;
- Unit *other;
-
- assert(u);
- assert(UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u)));
-
- /* Pull down units which are bound to us recursively if enabled */
- SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
- manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL);
-}
-
-static void check_unneeded_dependencies(Unit *u) {
- Iterator i;
- Unit *other;
-
- assert(u);
- assert(UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(u)));
-
- /* Garbage collect services that might not be needed anymore, if enabled */
- SET_FOREACH(other, u->dependencies[UNIT_REQUIRES], i)
- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
- unit_check_unneeded(other);
- SET_FOREACH(other, u->dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
- unit_check_unneeded(other);
- SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
- unit_check_unneeded(other);
- SET_FOREACH(other, u->dependencies[UNIT_REQUISITE], i)
- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
- unit_check_unneeded(other);
- SET_FOREACH(other, u->dependencies[UNIT_REQUISITE_OVERRIDABLE], i)
- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
- unit_check_unneeded(other);
- SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], i)
- if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
- unit_check_unneeded(other);
-}
-
-void unit_trigger_on_failure(Unit *u) {
- Unit *other;
- Iterator i;
-
- assert(u);
-
- if (set_size(u->dependencies[UNIT_ON_FAILURE]) <= 0)
- return;
-
- log_info("Triggering OnFailure= dependencies of %s.", u->id);
-
- SET_FOREACH(other, u->dependencies[UNIT_ON_FAILURE], i) {
- int r;
-
- if ((r = manager_add_job(u->manager, JOB_START, other, u->on_failure_isolate ? JOB_ISOLATE : JOB_REPLACE, true, NULL, NULL)) < 0)
- log_error("Failed to enqueue OnFailure= job: %s", strerror(-r));
- }
-}
-
-void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success) {
- 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 OK an expected
- * behavior here. For example: if a mount point is remounted
- * this function will be called too! */
-
- if (u->manager->n_reloading <= 0) {
- dual_timestamp ts;
-
- dual_timestamp_get(&ts);
-
- if (UNIT_IS_INACTIVE_OR_FAILED(os) && !UNIT_IS_INACTIVE_OR_FAILED(ns))
- u->inactive_exit_timestamp = ts;
- else if (!UNIT_IS_INACTIVE_OR_FAILED(os) && UNIT_IS_INACTIVE_OR_FAILED(ns))
- u->inactive_enter_timestamp = ts;
-
- if (!UNIT_IS_ACTIVE_OR_RELOADING(os) && UNIT_IS_ACTIVE_OR_RELOADING(ns))
- u->active_enter_timestamp = ts;
- else if (UNIT_IS_ACTIVE_OR_RELOADING(os) && !UNIT_IS_ACTIVE_OR_RELOADING(ns))
- u->active_exit_timestamp = ts;
-
- timer_unit_notify(u, ns);
- path_unit_notify(u, ns);
- }
-
- if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- cgroup_bonding_trim_list(u->cgroup_bondings, true);
-
- if (u->job) {
- unexpected = false;
-
- if (u->job->state == JOB_WAITING)
-
- /* So we reached a different state for this
- * job. Let's see if we can run it now if it
- * failed previously due to EAGAIN. */
- job_add_to_run_queue(u->job);
-
- /* Let's check whether this state change constitutes a
- * finished job, or maybe contradicts a running job and
- * hence needs to invalidate jobs. */
-
- switch (u->job->type) {
-
- case JOB_START:
- case JOB_VERIFY_ACTIVE:
-
- if (UNIT_IS_ACTIVE_OR_RELOADING(ns))
- job_finish_and_invalidate(u->job, JOB_DONE, true);
- else if (u->job->state == JOB_RUNNING && ns != UNIT_ACTIVATING) {
- unexpected = true;
-
- if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true);
- }
-
- break;
-
- case JOB_RELOAD:
- case JOB_RELOAD_OR_START:
-
- if (u->job->state == JOB_RUNNING) {
- if (ns == UNIT_ACTIVE)
- job_finish_and_invalidate(u->job, reload_success ? JOB_DONE : JOB_FAILED, true);
- else if (ns != UNIT_ACTIVATING && ns != UNIT_RELOADING) {
- unexpected = true;
-
- if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- job_finish_and_invalidate(u->job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE, true);
- }
- }
-
- break;
-
- case JOB_STOP:
- case JOB_RESTART:
- case JOB_TRY_RESTART:
-
- if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- job_finish_and_invalidate(u->job, JOB_DONE, true);
- else if (u->job->state == JOB_RUNNING && ns != UNIT_DEACTIVATING) {
- unexpected = true;
- job_finish_and_invalidate(u->job, JOB_FAILED, true);
- }
-
- break;
-
- default:
- assert_not_reached("Job type unknown");
- }
-
- } else
- unexpected = true;
-
- if (u->manager->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_ACTIVE_OR_ACTIVATING(os) && UNIT_IS_INACTIVE_OR_DEACTIVATING(ns))
- check_unneeded_dependencies(u);
-
- if (ns != os && ns == UNIT_FAILED) {
- log_struct(LOG_NOTICE,
- "MESSAGE=Unit %s entered failed state", u->id,
- "UNIT=%s", u->id,
- NULL);
- unit_trigger_on_failure(u);
- }
- }
-
- /* Some names are special */
- if (UNIT_IS_ACTIVE_OR_RELOADING(ns)) {
-
- if (unit_has_name(u, SPECIAL_DBUS_SERVICE))
- /* The bus just might have become available,
- * hence try to connect to it, if we aren't
- * yet connected. */
- bus_init(u->manager, true);
-
- if (u->type == UNIT_SERVICE &&
- !UNIT_IS_ACTIVE_OR_RELOADING(os) &&
- u->manager->n_reloading <= 0) {
- /* Write audit record if we have just finished starting up */
- manager_send_unit_audit(u->manager, u, AUDIT_SERVICE_START, true);
- u->in_audit = true;
- }
-
- if (!UNIT_IS_ACTIVE_OR_RELOADING(os))
- manager_send_unit_plymouth(u->manager, 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) &&
- u->manager->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(u->manager, u, AUDIT_SERVICE_START, ns == UNIT_INACTIVE);
-
- if (ns == UNIT_INACTIVE)
- manager_send_unit_audit(u->manager, u, AUDIT_SERVICE_STOP, true);
- } else
- /* Write audit record if we have just finished shutting down */
- manager_send_unit_audit(u->manager, u, AUDIT_SERVICE_STOP, ns == UNIT_INACTIVE);
-
- u->in_audit = false;
- }
- }
-
- manager_recheck_journal(u->manager);
-
- /* Maybe we finished startup and are now ready for being
- * stopped because unneeded? */
- unit_check_unneeded(u);
-
- unit_add_to_dbus_queue(u);
- unit_add_to_gc_queue(u);
-}
-
-int unit_watch_fd(Unit *u, int fd, uint32_t events, Watch *w) {
- struct epoll_event ev;
-
- assert(u);
- assert(fd >= 0);
- assert(w);
- assert(w->type == WATCH_INVALID || (w->type == WATCH_FD && w->fd == fd && w->data.unit == u));
-
- zero(ev);
- ev.data.ptr = w;
- ev.events = events;
-
- if (epoll_ctl(u->manager->epoll_fd,
- w->type == WATCH_INVALID ? EPOLL_CTL_ADD : EPOLL_CTL_MOD,
- fd,
- &ev) < 0)
- return -errno;
-
- w->fd = fd;
- w->type = WATCH_FD;
- w->data.unit = u;
-
- return 0;
-}
-
-void unit_unwatch_fd(Unit *u, Watch *w) {
- assert(u);
- assert(w);
-
- if (w->type == WATCH_INVALID)
- return;
-
- assert(w->type == WATCH_FD);
- assert(w->data.unit == u);
- assert_se(epoll_ctl(u->manager->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
-
- w->fd = -1;
- w->type = WATCH_INVALID;
- w->data.unit = NULL;
-}
-
-int unit_watch_pid(Unit *u, pid_t pid) {
- assert(u);
- assert(pid >= 1);
-
- /* Watch a specific PID. We only support one unit watching
- * each PID for now. */
-
- return hashmap_put(u->manager->watch_pids, LONG_TO_PTR(pid), u);
-}
-
-void unit_unwatch_pid(Unit *u, pid_t pid) {
- assert(u);
- assert(pid >= 1);
-
- hashmap_remove_value(u->manager->watch_pids, LONG_TO_PTR(pid), u);
-}
-
-int unit_watch_timer(Unit *u, usec_t delay, Watch *w) {
- struct itimerspec its;
- int flags, fd;
- bool ours;
-
- assert(u);
- assert(w);
- assert(w->type == WATCH_INVALID || (w->type == WATCH_UNIT_TIMER && w->data.unit == u));
-
- /* This will try to reuse the old timer if there is one */
-
- if (w->type == WATCH_UNIT_TIMER) {
- assert(w->data.unit == u);
- assert(w->fd >= 0);
-
- ours = false;
- fd = w->fd;
- } else if (w->type == WATCH_INVALID) {
-
- ours = true;
- if ((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0)
- return -errno;
- } else
- assert_not_reached("Invalid watch type");
-
- zero(its);
-
- if (delay <= 0) {
- /* Set absolute time in the past, but not 0, since we
- * don't want to disarm the timer */
- its.it_value.tv_sec = 0;
- its.it_value.tv_nsec = 1;
-
- flags = TFD_TIMER_ABSTIME;
- } else {
- timespec_store(&its.it_value, delay);
- flags = 0;
- }
-
- /* This will also flush the elapse counter */
- if (timerfd_settime(fd, flags, &its, NULL) < 0)
- goto fail;
-
- if (w->type == WATCH_INVALID) {
- struct epoll_event ev;
-
- zero(ev);
- ev.data.ptr = w;
- ev.events = EPOLLIN;
-
- if (epoll_ctl(u->manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0)
- goto fail;
- }
-
- w->type = WATCH_UNIT_TIMER;
- w->fd = fd;
- w->data.unit = u;
-
- return 0;
-
-fail:
- if (ours)
- close_nointr_nofail(fd);
-
- return -errno;
-}
-
-void unit_unwatch_timer(Unit *u, Watch *w) {
- assert(u);
- assert(w);
-
- if (w->type == WATCH_INVALID)
- return;
-
- assert(w->type == WATCH_UNIT_TIMER);
- assert(w->data.unit == u);
- assert(w->fd >= 0);
-
- assert_se(epoll_ctl(u->manager->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
- close_nointr_nofail(w->fd);
-
- w->fd = -1;
- w->type = WATCH_INVALID;
- w->data.unit = NULL;
-}
-
-bool unit_job_is_applicable(Unit *u, JobType j) {
- assert(u);
- assert(j >= 0 && j < _JOB_TYPE_MAX);
-
- switch (j) {
-
- case JOB_VERIFY_ACTIVE:
- case JOB_START:
- case JOB_STOP:
- case JOB_NOP:
- return true;
-
- case JOB_RESTART:
- case JOB_TRY_RESTART:
- return unit_can_start(u);
-
- case JOB_RELOAD:
- return unit_can_reload(u);
-
- case JOB_RELOAD_OR_START:
- return unit_can_reload(u) && unit_can_start(u);
-
- default:
- assert_not_reached("Invalid job type");
- }
-}
-
-int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_reference) {
-
- static const UnitDependency inverse_table[_UNIT_DEPENDENCY_MAX] = {
- [UNIT_REQUIRES] = UNIT_REQUIRED_BY,
- [UNIT_REQUIRES_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE,
- [UNIT_WANTS] = UNIT_WANTED_BY,
- [UNIT_REQUISITE] = UNIT_REQUIRED_BY,
- [UNIT_REQUISITE_OVERRIDABLE] = UNIT_REQUIRED_BY_OVERRIDABLE,
- [UNIT_BINDS_TO] = UNIT_BOUND_BY,
- [UNIT_PART_OF] = UNIT_CONSISTS_OF,
- [UNIT_REQUIRED_BY] = _UNIT_DEPENDENCY_INVALID,
- [UNIT_REQUIRED_BY_OVERRIDABLE] = _UNIT_DEPENDENCY_INVALID,
- [UNIT_WANTED_BY] = _UNIT_DEPENDENCY_INVALID,
- [UNIT_BOUND_BY] = UNIT_BINDS_TO,
- [UNIT_CONSISTS_OF] = UNIT_PART_OF,
- [UNIT_CONFLICTS] = UNIT_CONFLICTED_BY,
- [UNIT_CONFLICTED_BY] = UNIT_CONFLICTS,
- [UNIT_BEFORE] = UNIT_AFTER,
- [UNIT_AFTER] = UNIT_BEFORE,
- [UNIT_ON_FAILURE] = _UNIT_DEPENDENCY_INVALID,
- [UNIT_REFERENCES] = UNIT_REFERENCED_BY,
- [UNIT_REFERENCED_BY] = UNIT_REFERENCES,
- [UNIT_TRIGGERS] = UNIT_TRIGGERED_BY,
- [UNIT_TRIGGERED_BY] = UNIT_TRIGGERS,
- [UNIT_PROPAGATES_RELOAD_TO] = UNIT_RELOAD_PROPAGATED_FROM,
- [UNIT_RELOAD_PROPAGATED_FROM] = UNIT_PROPAGATES_RELOAD_TO,
- };
- int r, q = 0, v = 0, w = 0;
-
- 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)
- return 0;
-
- if ((r = set_ensure_allocated(&u->dependencies[d], trivial_hash_func, trivial_compare_func)) < 0)
- return r;
-
- if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID)
- if ((r = set_ensure_allocated(&other->dependencies[inverse_table[d]], trivial_hash_func, trivial_compare_func)) < 0)
- return r;
-
- if (add_reference)
- if ((r = set_ensure_allocated(&u->dependencies[UNIT_REFERENCES], trivial_hash_func, trivial_compare_func)) < 0 ||
- (r = set_ensure_allocated(&other->dependencies[UNIT_REFERENCED_BY], trivial_hash_func, trivial_compare_func)) < 0)
- return r;
-
- if ((q = set_put(u->dependencies[d], other)) < 0)
- return q;
-
- if (inverse_table[d] != _UNIT_DEPENDENCY_INVALID)
- if ((v = set_put(other->dependencies[inverse_table[d]], u)) < 0) {
- r = v;
- goto fail;
- }
-
- if (add_reference) {
- if ((w = set_put(u->dependencies[UNIT_REFERENCES], other)) < 0) {
- r = w;
- goto fail;
- }
-
- if ((r = set_put(other->dependencies[UNIT_REFERENCED_BY], u)) < 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);
-
- if ((r = unit_add_dependency(u, d, other, add_reference)) < 0)
- return r;
-
- if ((r = unit_add_dependency(u, e, other, add_reference)) < 0)
- return r;
-
- return 0;
-}
-
-static const char *resolve_template(Unit *u, const char *name, const char*path, char **p) {
- char *s;
-
- assert(u);
- assert(name || path);
-
- if (!name)
- name = path_get_file_name(path);
-
- if (!unit_name_is_template(name)) {
- *p = NULL;
- return name;
- }
-
- if (u->instance)
- s = unit_name_replace_instance(name, u->instance);
- else {
- char *i;
-
- if (!(i = unit_name_to_prefix(u->id)))
- return NULL;
-
- s = unit_name_replace_instance(name, i);
- free(i);
- }
-
- if (!s)
- return NULL;
-
- *p = s;
- return s;
-}
-
-int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) {
- Unit *other;
- int r;
- char *s;
-
- assert(u);
- assert(name || path);
-
- if (!(name = resolve_template(u, name, path, &s)))
- return -ENOMEM;
-
- if ((r = manager_load_unit(u->manager, name, path, NULL, &other)) < 0)
- goto finish;
-
- r = unit_add_dependency(u, d, other, add_reference);
-
-finish:
- free(s);
- return r;
-}
-
-int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference) {
- Unit *other;
- int r;
- char *s;
-
- assert(u);
- assert(name || path);
-
- if (!(name = resolve_template(u, name, path, &s)))
- return -ENOMEM;
-
- if ((r = manager_load_unit(u->manager, name, path, NULL, &other)) < 0)
- goto finish;
-
- r = unit_add_two_dependencies(u, d, e, other, add_reference);
-
-finish:
- free(s);
- return r;
-}
-
-int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) {
- Unit *other;
- int r;
- char *s;
-
- assert(u);
- assert(name || path);
-
- if (!(name = resolve_template(u, name, path, &s)))
- return -ENOMEM;
-
- if ((r = manager_load_unit(u->manager, name, path, NULL, &other)) < 0)
- goto finish;
-
- r = unit_add_dependency(other, d, u, add_reference);
-
-finish:
- free(s);
- return r;
-}
-
-int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference) {
- Unit *other;
- int r;
- char *s;
-
- assert(u);
- assert(name || path);
-
- if (!(name = resolve_template(u, name, path, &s)))
- return -ENOMEM;
-
- if ((r = manager_load_unit(u->manager, name, path, NULL, &other)) < 0)
- goto finish;
-
- if ((r = unit_add_two_dependencies(other, d, e, u, add_reference)) < 0)
- goto finish;
-
-finish:
- free(s);
- return r;
-}
-
-int set_unit_path(const char *p) {
- char *cwd, *c;
- int r;
-
- /* This is mostly for debug purposes */
-
- if (path_is_absolute(p)) {
- if (!(c = strdup(p)))
- return -ENOMEM;
- } else {
- if (!(cwd = get_current_dir_name()))
- return -errno;
-
- r = asprintf(&c, "%s/%s", cwd, p);
- free(cwd);
-
- if (r < 0)
- return -ENOMEM;
- }
-
- if (setenv("SYSTEMD_UNIT_PATH", c, 0) < 0) {
- r = -errno;
- free(c);
- return r;
- }
-
- 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_add_cgroup(Unit *u, CGroupBonding *b) {
- int r;
-
- assert(u);
- assert(b);
-
- assert(b->path);
-
- if (!b->controller) {
- if (!(b->controller = strdup(SYSTEMD_CGROUP_CONTROLLER)))
- return -ENOMEM;
-
- b->ours = true;
- }
-
- /* Ensure this hasn't been added yet */
- assert(!b->unit);
-
- if (streq(b->controller, SYSTEMD_CGROUP_CONTROLLER)) {
- CGroupBonding *l;
-
- l = hashmap_get(u->manager->cgroup_bondings, b->path);
- LIST_PREPEND(CGroupBonding, by_path, l, b);
-
- if ((r = hashmap_replace(u->manager->cgroup_bondings, b->path, l)) < 0) {
- LIST_REMOVE(CGroupBonding, by_path, l, b);
- return r;
- }
- }
-
- LIST_PREPEND(CGroupBonding, by_unit, u->cgroup_bondings, b);
- b->unit = u;
-
- return 0;
-}
-
-char *unit_default_cgroup_path(Unit *u) {
- char *p;
-
- assert(u);
-
- if (u->instance) {
- char *t;
-
- t = unit_name_template(u->id);
- if (!t)
- return NULL;
-
- p = strjoin(u->manager->cgroup_hierarchy, "/", t, "/", u->instance, NULL);
- free(t);
- } else
- p = strjoin(u->manager->cgroup_hierarchy, "/", u->id, NULL);
-
- return p;
-}
-
-int unit_add_cgroup_from_text(Unit *u, const char *name) {
- char *controller = NULL, *path = NULL;
- CGroupBonding *b = NULL;
- bool ours = false;
- int r;
-
- assert(u);
- assert(name);
-
- if ((r = cg_split_spec(name, &controller, &path)) < 0)
- return r;
-
- if (!path) {
- path = unit_default_cgroup_path(u);
- ours = true;
- }
-
- if (!controller) {
- controller = strdup(SYSTEMD_CGROUP_CONTROLLER);
- ours = true;
- }
-
- if (!path || !controller) {
- free(path);
- free(controller);
-
- return -ENOMEM;
- }
-
- if (cgroup_bonding_find_list(u->cgroup_bondings, controller)) {
- r = -EEXIST;
- goto fail;
- }
-
- if (!(b = new0(CGroupBonding, 1))) {
- r = -ENOMEM;
- goto fail;
- }
-
- b->controller = controller;
- b->path = path;
- b->ours = ours;
- b->essential = streq(controller, SYSTEMD_CGROUP_CONTROLLER);
-
- if ((r = unit_add_cgroup(u, b)) < 0)
- goto fail;
-
- return 0;
-
-fail:
- free(path);
- free(controller);
- free(b);
-
- return r;
-}
-
-static int unit_add_one_default_cgroup(Unit *u, const char *controller) {
- CGroupBonding *b = NULL;
- int r = -ENOMEM;
-
- assert(u);
-
- if (!controller)
- controller = SYSTEMD_CGROUP_CONTROLLER;
-
- if (cgroup_bonding_find_list(u->cgroup_bondings, controller))
- return 0;
-
- if (!(b = new0(CGroupBonding, 1)))
- return -ENOMEM;
-
- if (!(b->controller = strdup(controller)))
- goto fail;
-
- b->path = unit_default_cgroup_path(u);
- if (!b->path)
- goto fail;
-
- b->ours = true;
- b->essential = streq(controller, SYSTEMD_CGROUP_CONTROLLER);
-
- if ((r = unit_add_cgroup(u, b)) < 0)
- goto fail;
-
- return 0;
-
-fail:
- free(b->path);
- free(b->controller);
- free(b);
-
- return r;
-}
-
-int unit_add_default_cgroups(Unit *u) {
- CGroupAttribute *a;
- char **c;
- int r;
-
- assert(u);
-
- /* Adds in the default cgroups, if they weren't specified
- * otherwise. */
-
- if (!u->manager->cgroup_hierarchy)
- return 0;
-
- if ((r = unit_add_one_default_cgroup(u, NULL)) < 0)
- return r;
-
- STRV_FOREACH(c, u->manager->default_controllers)
- unit_add_one_default_cgroup(u, *c);
-
- LIST_FOREACH(by_unit, a, u->cgroup_attributes)
- unit_add_one_default_cgroup(u, a->controller);
-
- return 0;
-}
-
-CGroupBonding* unit_get_default_cgroup(Unit *u) {
- assert(u);
-
- return cgroup_bonding_find_list(u->cgroup_bondings, SYSTEMD_CGROUP_CONTROLLER);
-}
-
-int unit_add_cgroup_attribute(Unit *u, const char *controller, const char *name, const char *value, CGroupAttributeMapCallback map_callback) {
- int r;
- char *c = NULL;
- CGroupAttribute *a;
-
- assert(u);
- assert(name);
- assert(value);
-
- if (!controller) {
- const char *dot;
-
- dot = strchr(name, '.');
- if (!dot)
- return -EINVAL;
-
- c = strndup(name, dot - name);
- if (!c)
- return -ENOMEM;
-
- controller = c;
- }
-
- if (streq(controller, SYSTEMD_CGROUP_CONTROLLER)) {
- r = -EINVAL;
- goto finish;
- }
-
- a = new0(CGroupAttribute, 1);
- if (!a) {
- r = -ENOMEM;
- goto finish;
- }
-
- if (c) {
- a->controller = c;
- c = NULL;
- } else
- a->controller = strdup(controller);
-
- a->name = strdup(name);
- a->value = strdup(value);
-
- if (!a->controller || !a->name || !a->value) {
- free(a->controller);
- free(a->name);
- free(a->value);
- free(a);
-
- return -ENOMEM;
- }
-
- a->map_callback = map_callback;
-
- LIST_PREPEND(CGroupAttribute, by_unit, u->cgroup_attributes, a);
-
- r = 0;
-
-finish:
- free(c);
- return r;
-}
-
-int unit_load_related_unit(Unit *u, const char *type, Unit **_found) {
- char *t;
- int r;
-
- assert(u);
- assert(type);
- assert(_found);
-
- if (!(t = unit_name_change_suffix(u->id, type)))
- return -ENOMEM;
-
- assert(!unit_has_name(u, t));
-
- r = manager_load_unit(u->manager, t, NULL, NULL, _found);
- free(t);
-
- assert(r < 0 || *_found != u);
-
- return r;
-}
-
-int unit_get_related_unit(Unit *u, const char *type, Unit **_found) {
- Unit *found;
- char *t;
-
- assert(u);
- assert(type);
- assert(_found);
-
- if (!(t = unit_name_change_suffix(u->id, type)))
- return -ENOMEM;
-
- assert(!unit_has_name(u, t));
-
- found = manager_get_unit(u->manager, t);
- free(t);
-
- if (!found)
- return -ENOENT;
-
- *_found = found;
- return 0;
-}
-
-int unit_watch_bus_name(Unit *u, const char *name) {
- assert(u);
- assert(name);
-
- /* Watch a specific name on the bus. We only support one unit
- * watching each name for now. */
-
- return hashmap_put(u->manager->watch_bus, name, u);
-}
-
-void unit_unwatch_bus_name(Unit *u, const char *name) {
- assert(u);
- assert(name);
-
- hashmap_remove_value(u->manager->watch_bus, name, u);
-}
-
-bool unit_can_serialize(Unit *u) {
- assert(u);
-
- return UNIT_VTABLE(u)->serialize && UNIT_VTABLE(u)->deserialize_item;
-}
-
-int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
- int r;
-
- assert(u);
- assert(f);
- assert(fds);
-
- if (!unit_can_serialize(u))
- return 0;
-
- if ((r = UNIT_VTABLE(u)->serialize(u, f, fds)) < 0)
- return r;
-
-
- 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);
- }
- }
-
- 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);
-
- if (dual_timestamp_is_set(&u->condition_timestamp))
- unit_serialize_item(u, f, "condition-result", yes_no(u->condition_result));
-
- /* End marker */
- fputc('\n', f);
- return 0;
-}
-
-void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *format, ...) {
- va_list ap;
-
- assert(u);
- assert(f);
- assert(key);
- assert(format);
-
- fputs(key, f);
- fputc('=', f);
-
- va_start(ap, format);
- vfprintf(f, format, ap);
- va_end(ap);
-
- fputc('\n', f);
-}
-
-void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) {
- assert(u);
- assert(f);
- assert(key);
- assert(value);
-
- fprintf(f, "%s=%s\n", key, value);
-}
-
-int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
- int r;
-
- assert(u);
- assert(f);
- assert(fds);
-
- if (!unit_can_serialize(u))
- return 0;
-
- for (;;) {
- char line[LINE_MAX], *l, *v;
- size_t k;
-
- if (!fgets(line, sizeof(line), f)) {
- if (feof(f))
- return 0;
- return -errno;
- }
-
- char_array_0(line);
- l = strstrip(line);
-
- /* End marker */
- if (l[0] == 0)
- return 0;
-
- k = strcspn(l, "=");
-
- if (l[k] == '=') {
- l[k] = 0;
- v = l+k+1;
- } else
- v = l+k;
-
- if (streq(l, "job")) {
- if (v[0] == '\0') {
- /* new-style serialized job */
- Job *j = job_new_raw(u);
- if (!j)
- return -ENOMEM;
-
- r = job_deserialize(j, f, fds);
- if (r < 0) {
- job_free(j);
- return r;
- }
-
- r = hashmap_put(u->manager->jobs, UINT32_TO_PTR(j->id), j);
- if (r < 0) {
- job_free(j);
- return r;
- }
-
- r = job_install_deserialized(j);
- if (r < 0) {
- hashmap_remove(u->manager->jobs, UINT32_TO_PTR(j->id));
- job_free(j);
- return r;
- }
- } else {
- /* legacy */
- JobType type = job_type_from_string(v);
- if (type < 0)
- log_debug("Failed to parse job type value %s", v);
- else
- u->deserialized_job = type;
- }
- continue;
- } else if (streq(l, "inactive-exit-timestamp")) {
- dual_timestamp_deserialize(v, &u->inactive_exit_timestamp);
- continue;
- } else if (streq(l, "active-enter-timestamp")) {
- dual_timestamp_deserialize(v, &u->active_enter_timestamp);
- continue;
- } else if (streq(l, "active-exit-timestamp")) {
- dual_timestamp_deserialize(v, &u->active_exit_timestamp);
- continue;
- } else if (streq(l, "inactive-enter-timestamp")) {
- dual_timestamp_deserialize(v, &u->inactive_enter_timestamp);
- continue;
- } else if (streq(l, "condition-timestamp")) {
- dual_timestamp_deserialize(v, &u->condition_timestamp);
- continue;
- } else if (streq(l, "condition-result")) {
- int b;
-
- if ((b = parse_boolean(v)) < 0)
- log_debug("Failed to parse condition result value %s", v);
- else
- u->condition_result = b;
-
- continue;
- }
-
- if ((r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds)) < 0)
- return r;
- }
-}
-
-int unit_add_node_link(Unit *u, const char *what, bool wants) {
- Unit *device;
- char *e;
- int r;
-
- assert(u);
-
- if (!what)
- return 0;
-
- /* Adds in links to the device node that this unit is based on */
-
- if (!is_device_path(what))
- return 0;
-
- e = unit_name_from_path(what, ".device");
- if (!e)
- return -ENOMEM;
-
- r = manager_load_unit(u->manager, e, NULL, NULL, &device);
- free(e);
- if (r < 0)
- return r;
-
- r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_BINDS_TO, 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;
-
- assert(u);
-
- if (UNIT_VTABLE(u)->coldplug)
- if ((r = UNIT_VTABLE(u)->coldplug(u)) < 0)
- return r;
-
- if (u->job) {
- r = job_coldplug(u->job);
- if (r < 0)
- return r;
- } else if (u->deserialized_job >= 0) {
- /* legacy */
- r = manager_add_job(u->manager, u->deserialized_job, u, JOB_IGNORE_REQUIREMENTS, false, NULL, NULL);
- if (r < 0)
- return r;
-
- u->deserialized_job = _JOB_TYPE_INVALID;
- }
-
- return 0;
-}
-
-void unit_status_printf(Unit *u, const char *status, const char *format, ...) {
- va_list ap;
-
- assert(u);
- assert(format);
-
- if (!manager_get_show_status(u->manager))
- return;
-
- if (!manager_is_booting_or_shutting_down(u->manager))
- return;
-
- va_start(ap, format);
- status_vprintf(status, true, format, ap);
- va_end(ap);
-}
-
-bool unit_need_daemon_reload(Unit *u) {
- struct stat st;
-
- 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;
- }
-
- return false;
-}
-
-void unit_reset_failed(Unit *u) {
- assert(u);
-
- if (UNIT_VTABLE(u)->reset_failed)
- UNIT_VTABLE(u)->reset_failed(u);
-}
-
-Unit *unit_following(Unit *u) {
- assert(u);
-
- if (UNIT_VTABLE(u)->following)
- return UNIT_VTABLE(u)->following(u);
-
- return NULL;
-}
-
-bool unit_pending_inactive(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 (u->job && u->job->type == JOB_STOP)
- return true;
-
- return false;
-}
-
-bool unit_pending_active(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, DBusError *error) {
- assert(u);
- assert(w >= 0 && w < _KILL_WHO_MAX);
- assert(signo > 0);
- assert(signo < _NSIG);
-
- if (!UNIT_VTABLE(u)->kill)
- return -ENOTSUP;
-
- return UNIT_VTABLE(u)->kill(u, w, signo, error);
-}
-
-int unit_following_set(Unit *u, Set **s) {
- assert(u);
- assert(s);
-
- if (UNIT_VTABLE(u)->following_set)
- return UNIT_VTABLE(u)->following_set(u, s);
-
- *s = NULL;
- return 0;
-}
-
-UnitFileState unit_get_unit_file_state(Unit *u) {
- assert(u);
-
- if (u->unit_file_state < 0 && u->fragment_path)
- u->unit_file_state = unit_file_get_state(
- u->manager->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER,
- NULL, path_get_file_name(u->fragment_path));
-
- return u->unit_file_state;
-}
-
-Unit* unit_ref_set(UnitRef *ref, Unit *u) {
- assert(ref);
- assert(u);
-
- if (ref->unit)
- unit_ref_unset(ref);
-
- ref->unit = u;
- LIST_PREPEND(UnitRef, refs, u->refs, ref);
- return u;
-}
-
-void unit_ref_unset(UnitRef *ref) {
- assert(ref);
-
- if (!ref->unit)
- return;
-
- LIST_REMOVE(UnitRef, refs, ref->unit->refs, ref);
- ref->unit = NULL;
-}
-
-int unit_add_one_mount_link(Unit *u, Mount *m) {
- char **i;
-
- assert(u);
- assert(m);
-
- if (u->load_state != UNIT_LOADED ||
- UNIT(m)->load_state != UNIT_LOADED)
- return 0;
-
- STRV_FOREACH(i, u->requires_mounts_for) {
-
- if (UNIT(m) == u)
- continue;
-
- if (!path_startswith(*i, m->where))
- continue;
-
- return unit_add_two_dependencies(u, UNIT_AFTER, UNIT_REQUIRES, UNIT(m), true);
- }
-
- return 0;
-}
-
-int unit_add_mount_links(Unit *u) {
- Unit *other;
- int r;
-
- assert(u);
-
- LIST_FOREACH(units_by_type, other, u->manager->units_by_type[UNIT_MOUNT]) {
- r = unit_add_one_mount_link(u, MOUNT(other));
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-int unit_exec_context_defaults(Unit *u, ExecContext *c) {
- unsigned i;
- int r;
-
- assert(u);
- assert(c);
-
- /* This only copies in the ones that need memory */
-
- for (i = 0; i < RLIMIT_NLIMITS; i++)
- if (u->manager->rlimit[i] && !c->rlimit[i]) {
- c->rlimit[i] = newdup(struct rlimit, u->manager->rlimit[i], 1);
- if (!c->rlimit[i])
- return -ENOMEM;
- }
-
- if (u->manager->running_as == SYSTEMD_USER &&
- !c->working_directory) {
-
- r = get_home_dir(&c->working_directory);
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
-ExecContext *unit_get_exec_context(Unit *u) {
- size_t offset;
- assert(u);
-
- offset = UNIT_VTABLE(u)->exec_context_offset;
- if (offset <= 0)
- return NULL;
-
- return (ExecContext*) ((uint8_t*) u + offset);
-}
-
-static const char* const unit_active_state_table[_UNIT_ACTIVE_STATE_MAX] = {
- [UNIT_ACTIVE] = "active",
- [UNIT_RELOADING] = "reloading",
- [UNIT_INACTIVE] = "inactive",
- [UNIT_FAILED] = "failed",
- [UNIT_ACTIVATING] = "activating",
- [UNIT_DEACTIVATING] = "deactivating"
-};
-
-DEFINE_STRING_TABLE_LOOKUP(unit_active_state, UnitActiveState);
-
-static const char* const unit_dependency_table[_UNIT_DEPENDENCY_MAX] = {
- [UNIT_REQUIRES] = "Requires",
- [UNIT_REQUIRES_OVERRIDABLE] = "RequiresOverridable",
- [UNIT_REQUISITE] = "Requisite",
- [UNIT_REQUISITE_OVERRIDABLE] = "RequisiteOverridable",
- [UNIT_WANTS] = "Wants",
- [UNIT_BINDS_TO] = "BindsTo",
- [UNIT_PART_OF] = "PartOf",
- [UNIT_REQUIRED_BY] = "RequiredBy",
- [UNIT_REQUIRED_BY_OVERRIDABLE] = "RequiredByOverridable",
- [UNIT_WANTED_BY] = "WantedBy",
- [UNIT_BOUND_BY] = "BoundBy",
- [UNIT_CONSISTS_OF] = "ConsistsOf",
- [UNIT_CONFLICTS] = "Conflicts",
- [UNIT_CONFLICTED_BY] = "ConflictedBy",
- [UNIT_BEFORE] = "Before",
- [UNIT_AFTER] = "After",
- [UNIT_ON_FAILURE] = "OnFailure",
- [UNIT_TRIGGERS] = "Triggers",
- [UNIT_TRIGGERED_BY] = "TriggeredBy",
- [UNIT_PROPAGATES_RELOAD_TO] = "PropagatesReloadTo",
- [UNIT_RELOAD_PROPAGATED_FROM] = "ReloadPropagatedFrom",
- [UNIT_REFERENCES] = "References",
- [UNIT_REFERENCED_BY] = "ReferencedBy",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(unit_dependency, UnitDependency);
diff --git a/src/core/unit.h b/src/core/unit.h
deleted file mode 100644
index bf961c2aac..0000000000
--- a/src/core/unit.h
+++ /dev/null
@@ -1,551 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <stdbool.h>
-#include <stdlib.h>
-
-typedef struct Unit Unit;
-typedef struct UnitVTable UnitVTable;
-typedef enum UnitActiveState UnitActiveState;
-typedef enum UnitDependency UnitDependency;
-typedef struct UnitRef UnitRef;
-typedef struct UnitStatusMessageFormats UnitStatusMessageFormats;
-
-#include "set.h"
-#include "util.h"
-#include "list.h"
-#include "socket-util.h"
-#include "execute.h"
-#include "condition.h"
-#include "install.h"
-#include "unit-name.h"
-
-enum UnitActiveState {
- UNIT_ACTIVE,
- UNIT_RELOADING,
- UNIT_INACTIVE,
- UNIT_FAILED,
- UNIT_ACTIVATING,
- UNIT_DEACTIVATING,
- _UNIT_ACTIVE_STATE_MAX,
- _UNIT_ACTIVE_STATE_INVALID = -1
-};
-
-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;
-}
-
-enum UnitDependency {
- /* Positive dependencies */
- UNIT_REQUIRES,
- UNIT_REQUIRES_OVERRIDABLE,
- UNIT_REQUISITE,
- UNIT_REQUISITE_OVERRIDABLE,
- UNIT_WANTS,
- UNIT_BINDS_TO,
- UNIT_PART_OF,
-
- /* Inverse of the above */
- UNIT_REQUIRED_BY, /* inverse of 'requires' and 'requisite' is 'required_by' */
- UNIT_REQUIRED_BY_OVERRIDABLE, /* inverse of 'requires_overridable' and 'requisite_overridable' is 'soft_required_by' */
- UNIT_WANTED_BY, /* inverse of 'wants' */
- UNIT_BOUND_BY, /* inverse of 'binds_to' */
- UNIT_CONSISTS_OF, /* inverse of 'part_of' */
-
- /* Negative dependencies */
- UNIT_CONFLICTS, /* inverse of 'conflicts' is 'conflicted_by' */
- UNIT_CONFLICTED_BY,
-
- /* Order */
- UNIT_BEFORE, /* inverse of 'before' is 'after' and vice versa */
- UNIT_AFTER,
-
- /* On Failure */
- UNIT_ON_FAILURE,
-
- /* Triggers (i.e. a socket triggers a service) */
- UNIT_TRIGGERS,
- UNIT_TRIGGERED_BY,
-
- /* Propagate reloads */
- UNIT_PROPAGATES_RELOAD_TO,
- UNIT_RELOAD_PROPAGATED_FROM,
-
- /* Reference information for GC logic */
- UNIT_REFERENCES, /* Inverse of 'references' is 'referenced_by' */
- UNIT_REFERENCED_BY,
-
- _UNIT_DEPENDENCY_MAX,
- _UNIT_DEPENDENCY_INVALID = -1
-};
-
-#include "manager.h"
-#include "job.h"
-#include "cgroup.h"
-#include "cgroup-attr.h"
-
-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 */
- usec_t fragment_mtime;
- usec_t source_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;
-
- usec_t job_timeout;
-
- /* References to this */
- LIST_HEAD(UnitRef, refs);
-
- /* Conditions to check */
- LIST_HEAD(Condition, conditions);
-
- dual_timestamp condition_timestamp;
-
- dual_timestamp inactive_exit_timestamp;
- dual_timestamp active_enter_timestamp;
- dual_timestamp active_exit_timestamp;
- dual_timestamp inactive_enter_timestamp;
-
- /* Counterparts in the cgroup filesystem */
- CGroupBonding *cgroup_bondings;
- CGroupAttribute *cgroup_attributes;
-
- /* 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);
-
- /* Used during GC sweeps */
- unsigned gc_marker;
-
- /* When deserializing, temporarily store the job type for this
- * unit here, if there was a job scheduled.
- * Only for deserializing from a legacy version. New style uses full
- * serialized jobs. */
- int deserialized_job; /* This is actually of type JobType */
-
- /* Error code when we didn't manage to load the unit (negative) */
- int load_error;
-
- /* Cached unit file state */
- UnitFileState unit_file_state;
-
- /* 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;
-
- /* Isolate OnFailure unit */
- bool on_failure_isolate;
-
- /* Ignore this unit when isolating */
- bool ignore_on_isolate;
-
- /* Ignore this unit when snapshotting */
- bool ignore_on_snapshot;
-
- /* Did the last condition check succeed? */
- bool condition_result;
-
- bool in_load_queue:1;
- bool in_dbus_queue:1;
- bool in_cleanup_queue:1;
- bool in_gc_queue:1;
-
- bool sent_dbus_new_signal:1;
-
- bool no_gc:1;
-
- bool in_audit:1;
-};
-
-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 UnitStatusMessageFormats {
- const char *starting_stopping[2];
- const char *finished_start_job[_JOB_RESULT_MAX];
- const char *finished_stop_job[_JOB_RESULT_MAX];
-};
-
-#include "service.h"
-#include "timer.h"
-#include "socket.h"
-#include "target.h"
-#include "device.h"
-#include "mount.h"
-#include "automount.h"
-#include "snapshot.h"
-#include "swap.h"
-#include "path.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;
-
- /* 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, DBusError *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);
-
- /* 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);
-
- /* Return true when this unit is suitable for snapshotting */
- bool (*check_snapshot)(Unit *u);
-
- void (*fd_event)(Unit *u, int fd, uint32_t events, Watch *w);
- void (*sigchld_event)(Unit *u, pid_t pid, int code, int status);
- void (*timer_event)(Unit *u, uint64_t n_elapsed, Watch *w);
-
- /* 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 (*cgroup_notify_empty)(Unit *u);
-
- /* Called whenever a process of this unit sends us a message */
- void (*notify_message)(Unit *u, pid_t pid, char **tags);
-
- /* Called whenever a name thus 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 whenever a bus PID lookup finishes */
- void (*bus_query_pid_done)(Unit *u, const char *name, pid_t pid);
-
- /* Called for each message received on the bus */
- DBusHandlerResult (*bus_message_handler)(Unit *u, DBusConnection *c, DBusMessage *message);
-
- /* 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);
-
- /* This is called for each unit type and should be used to
- * enumerate existing devices and load them. However,
- * everything that is loaded here should still stay in
- * inactive state. It is the job of the coldplug() call above
- * to put the units into the initial state. */
- int (*enumerate)(Manager *m);
-
- /* Type specific cleanups. */
- void (*shutdown)(Manager *m);
-
- /* When sending out PropertiesChanged signal, which properties
- * shall be invalidated? This is a NUL separated list of
- * strings, to minimize relocations a little. */
- const char *bus_invalidating_properties;
-
- /* The interface name */
- const char *bus_interface;
-
- UnitStatusMessageFormats status_message_formats;
-
- /* Can units of this type have multiple names? */
- bool no_alias:1;
-
- /* Instances make no sense for this type */
- bool no_instances:1;
-
- /* Exclude from automatic gc */
- bool no_gc:1;
-};
-
-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_CAST(SOCKET, Socket);
-DEFINE_CAST(TIMER, Timer);
-DEFINE_CAST(SERVICE, Service);
-DEFINE_CAST(TARGET, Target);
-DEFINE_CAST(DEVICE, Device);
-DEFINE_CAST(MOUNT, Mount);
-DEFINE_CAST(AUTOMOUNT, Automount);
-DEFINE_CAST(SNAPSHOT, Snapshot);
-DEFINE_CAST(SWAP, Swap);
-DEFINE_CAST(PATH, Path);
-
-Unit *unit_new(Manager *m, size_t size);
-void unit_free(Unit *u);
-
-int unit_add_name(Unit *u, const char *name);
-
-int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_reference);
-int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit *other, bool add_reference);
-
-int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference);
-int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference);
-
-int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference);
-int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference);
-
-int unit_add_exec_dependencies(Unit *u, ExecContext *c);
-
-int unit_add_cgroup(Unit *u, CGroupBonding *b);
-int unit_add_cgroup_from_text(Unit *u, const char *name);
-int unit_add_default_cgroups(Unit *u);
-CGroupBonding* unit_get_default_cgroup(Unit *u);
-int unit_add_cgroup_attribute(Unit *u, const char *controller, const char *name, const char *value, CGroupAttributeMapCallback map_callback);
-
-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);
-
-int unit_load_fragment_and_dropin(Unit *u);
-int unit_load_fragment_and_dropin_optional(Unit *u);
-int unit_load(Unit *unit);
-
-const char *unit_description(Unit *u);
-
-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);
-bool unit_can_start(Unit *u);
-bool unit_can_isolate(Unit *u);
-
-int unit_start(Unit *u);
-int unit_stop(Unit *u);
-int unit_reload(Unit *u);
-
-int unit_kill(Unit *u, KillWho w, int signo, DBusError *error);
-
-void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success);
-
-int unit_watch_fd(Unit *u, int fd, uint32_t events, Watch *w);
-void unit_unwatch_fd(Unit *u, Watch *w);
-
-int unit_watch_pid(Unit *u, pid_t pid);
-void unit_unwatch_pid(Unit *u, pid_t pid);
-
-int unit_watch_timer(Unit *u, usec_t delay, Watch *w);
-void unit_unwatch_timer(Unit *u, Watch *w);
-
-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);
-int unit_get_related_unit(Unit *u, const char *type, Unit **_found);
-
-bool unit_can_serialize(Unit *u);
-int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs);
-void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_attr_(4,5);
-void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value);
-int unit_deserialize(Unit *u, FILE *f, FDSet *fds);
-
-int unit_add_node_link(Unit *u, const char *what, bool wants);
-
-int unit_coldplug(Unit *u);
-
-void unit_status_printf(Unit *u, const char *status, const char *format, ...);
-
-bool unit_need_daemon_reload(Unit *u);
-
-void unit_reset_failed(Unit *u);
-
-Unit *unit_following(Unit *u);
-
-bool unit_pending_inactive(Unit *u);
-bool unit_pending_active(Unit *u);
-
-int unit_add_default_target_dependency(Unit *u, Unit *target);
-
-char *unit_default_cgroup_path(Unit *u);
-
-int unit_following_set(Unit *u, Set **s);
-
-void unit_trigger_on_failure(Unit *u);
-
-bool unit_condition_test(Unit *u);
-
-UnitFileState unit_get_unit_file_state(Unit *u);
-
-Unit* unit_ref_set(UnitRef *ref, Unit *u);
-void unit_ref_unset(UnitRef *ref);
-
-#define UNIT_DEREF(ref) ((ref).unit)
-
-int unit_add_one_mount_link(Unit *u, Mount *m);
-int unit_add_mount_links(Unit *u);
-
-int unit_exec_context_defaults(Unit *u, ExecContext *c);
-
-ExecContext *unit_get_exec_context(Unit *u);
-
-const char *unit_active_state_to_string(UnitActiveState i);
-UnitActiveState unit_active_state_from_string(const char *s);
-
-const char *unit_dependency_to_string(UnitDependency i);
-UnitDependency unit_dependency_from_string(const char *s);
diff --git a/src/core/user.conf b/src/core/user.conf
deleted file mode 100644
index e02b46bc3a..0000000000
--- a/src/core/user.conf
+++ /dev/null
@@ -1,17 +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.
-#
-# See systemd.conf(5) for details
-
-[Manager]
-#LogLevel=info
-#LogTarget=console
-#LogColor=yes
-#LogLocation=no
-#DefaultControllers=cpu
-#DefaultStandardOutput=inherit
-#DefaultStandardError=inherit