summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/.gitignore1
-rw-r--r--src/core/audit-fd.c4
-rw-r--r--src/core/automount.c110
-rw-r--r--src/core/bus-endpoint.c5
-rw-r--r--src/core/bus-endpoint.h2
-rw-r--r--src/core/bus-policy.c7
-rw-r--r--src/core/bus-policy.h2
-rw-r--r--src/core/busname.c48
-rw-r--r--src/core/busname.h2
-rw-r--r--src/core/cgroup.c36
-rw-r--r--src/core/cgroup.h2
-rw-r--r--src/core/dbus-automount.c3
-rw-r--r--src/core/dbus-busname.c5
-rw-r--r--src/core/dbus-cgroup.c17
-rw-r--r--src/core/dbus-cgroup.h1
-rw-r--r--src/core/dbus-device.c4
-rw-r--r--src/core/dbus-execute.c496
-rw-r--r--src/core/dbus-execute.h1
-rw-r--r--src/core/dbus-job.c9
-rw-r--r--src/core/dbus-job.h1
-rw-r--r--src/core/dbus-kill.c5
-rw-r--r--src/core/dbus-kill.h3
-rw-r--r--src/core/dbus-manager.c199
-rw-r--r--src/core/dbus-mount.c9
-rw-r--r--src/core/dbus-mount.h1
-rw-r--r--src/core/dbus-path.c7
-rw-r--r--src/core/dbus-scope.c15
-rw-r--r--src/core/dbus-scope.h1
-rw-r--r--src/core/dbus-service.c55
-rw-r--r--src/core/dbus-service.h1
-rw-r--r--src/core/dbus-slice.c4
-rw-r--r--src/core/dbus-slice.h1
-rw-r--r--src/core/dbus-snapshot.c55
-rw-r--r--src/core/dbus-snapshot.h28
-rw-r--r--src/core/dbus-socket.c31
-rw-r--r--src/core/dbus-socket.h1
-rw-r--r--src/core/dbus-swap.c9
-rw-r--r--src/core/dbus-swap.h1
-rw-r--r--src/core/dbus-target.c2
-rw-r--r--src/core/dbus-target.h1
-rw-r--r--src/core/dbus-timer.c41
-rw-r--r--src/core/dbus-timer.h1
-rw-r--r--src/core/dbus-unit.c59
-rw-r--r--src/core/dbus-unit.h1
-rw-r--r--src/core/dbus.c41
-rw-r--r--src/core/device.c51
-rw-r--r--src/core/execute.c326
-rw-r--r--src/core/execute.h39
-rw-r--r--src/core/failure-action.c27
-rw-r--r--src/core/hostname-setup.c17
-rw-r--r--src/core/ima-setup.c6
-rw-r--r--src/core/job.c111
-rw-r--r--src/core/job.h8
-rw-r--r--src/core/kill.c5
-rw-r--r--src/core/killall.c14
-rw-r--r--src/core/kmod-setup.c6
-rw-r--r--src/core/load-dropin.c6
-rw-r--r--src/core/load-dropin.h2
-rw-r--r--src/core/load-fragment-gperf.gperf.m433
-rw-r--r--src/core/load-fragment.c541
-rw-r--r--src/core/load-fragment.h7
-rw-r--r--src/core/locale-setup.c11
-rw-r--r--src/core/loopback-setup.c5
-rw-r--r--src/core/machine-id-setup.c11
-rw-r--r--src/core/macros.systemd.in12
-rw-r--r--src/core/main.c173
-rw-r--r--src/core/manager.c289
-rw-r--r--src/core/manager.h15
-rw-r--r--src/core/mount-setup.c27
-rw-r--r--src/core/mount.c157
-rw-r--r--src/core/mount.h2
-rw-r--r--src/core/namespace.c30
-rw-r--r--src/core/path.c47
-rw-r--r--src/core/scope.c53
-rw-r--r--src/core/selinux-access.c24
-rw-r--r--src/core/selinux-access.h3
-rw-r--r--src/core/selinux-setup.c9
-rw-r--r--src/core/service.c533
-rw-r--r--src/core/service.h9
-rw-r--r--src/core/show-status.c84
-rw-r--r--src/core/show-status.h7
-rw-r--r--src/core/shutdown.c33
-rw-r--r--src/core/slice.c37
-rw-r--r--src/core/smack-setup.c16
-rw-r--r--src/core/snapshot.c299
-rw-r--r--src/core/snapshot.h37
-rw-r--r--src/core/socket.c104
-rw-r--r--src/core/socket.h14
-rw-r--r--src/core/swap.c85
-rw-r--r--src/core/swap.h2
-rw-r--r--src/core/system.conf2
-rw-r--r--src/core/target.c10
-rw-r--r--src/core/timer.c122
-rw-r--r--src/core/timer.h2
-rw-r--r--src/core/transaction.c55
-rw-r--r--src/core/transaction.h7
-rw-r--r--src/core/triggers.systemd.in26
-rw-r--r--src/core/umount.c41
-rw-r--r--src/core/unit-printf.c186
-rw-r--r--src/core/unit.c372
-rw-r--r--src/core/unit.h48
101 files changed, 3216 insertions, 2310 deletions
diff --git a/src/core/.gitignore b/src/core/.gitignore
index f293bbdc93..465b4fcc20 100644
--- a/src/core/.gitignore
+++ b/src/core/.gitignore
@@ -1,2 +1,3 @@
/macros.systemd
+/triggers.systemd
/systemd.pc
diff --git a/src/core/audit-fd.c b/src/core/audit-fd.c
index 5a18e263a8..0a484d89fc 100644
--- a/src/core/audit-fd.c
+++ b/src/core/audit-fd.c
@@ -21,13 +21,15 @@
#include <errno.h>
+
#include "audit-fd.h"
#ifdef HAVE_AUDIT
-#include <stdbool.h>
#include <libaudit.h>
+#include <stdbool.h>
+#include "fd-util.h"
#include "log.h"
#include "util.h"
diff --git a/src/core/automount.c b/src/core/automount.c
index 8173a6cbe8..85b7b4e842 100644
--- a/src/core/automount.c
+++ b/src/core/automount.c
@@ -20,29 +20,37 @@
***/
#include <errno.h>
-#include <limits.h>
-#include <sys/mount.h>
-#include <unistd.h>
#include <fcntl.h>
+#include <limits.h>
+#include <linux/auto_dev-ioctl.h>
+#include <linux/auto_fs4.h>
#include <sys/epoll.h>
+#include <sys/mount.h>
#include <sys/stat.h>
-#include <linux/auto_fs4.h>
-#include <linux/auto_dev-ioctl.h>
+#include <unistd.h>
-#include "unit.h"
+#include "alloc-util.h"
+#include "async.h"
#include "automount.h"
-#include "mount.h"
-#include "unit-name.h"
-#include "special.h"
+#include "bus-error.h"
+#include "bus-util.h"
+#include "dbus-automount.h"
+#include "fd-util.h"
+#include "formats-util.h"
+#include "io-util.h"
#include "label.h"
#include "mkdir.h"
+#include "mount-util.h"
+#include "mount.h"
+#include "parse-util.h"
#include "path-util.h"
-#include "dbus-automount.h"
-#include "bus-util.h"
-#include "bus-error.h"
-#include "formats-util.h"
#include "process-util.h"
-#include "async.h"
+#include "special.h"
+#include "stdio-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "unit-name.h"
+#include "unit.h"
static const UnitActiveState state_translation_table[_AUTOMOUNT_STATE_MAX] = {
[AUTOMOUNT_DEAD] = UNIT_INACTIVE,
@@ -81,26 +89,11 @@ static void automount_init(Unit *u) {
UNIT(a)->ignore_on_isolate = true;
}
-static void repeat_unmount(const char *path) {
- assert(path);
-
- for (;;) {
- /* If there are multiple mounts on a mount point, this
- * removes them all */
-
- if (umount2(path, MNT_DETACH) >= 0)
- continue;
-
- if (errno != EINVAL)
- log_error_errno(errno, "Failed to unmount: %m");
-
- break;
- }
-}
-
static int automount_send_ready(Automount *a, Set *tokens, int status);
static void unmount_autofs(Automount *a) {
+ int r;
+
assert(a);
if (a->pipe_fd < 0)
@@ -116,8 +109,11 @@ static void unmount_autofs(Automount *a) {
* around */
if (a->where &&
(UNIT(a)->manager->exit_code != MANAGER_RELOAD &&
- UNIT(a)->manager->exit_code != MANAGER_REEXECUTE))
- repeat_unmount(a->where);
+ UNIT(a)->manager->exit_code != MANAGER_REEXECUTE)) {
+ r = repeat_unmount(a->where, MNT_DETACH);
+ if (r < 0)
+ log_error_errno(r, "Failed to unmount: %m");
+ }
}
static void automount_done(Unit *u) {
@@ -137,13 +133,12 @@ static void automount_done(Unit *u) {
static int automount_add_mount_links(Automount *a) {
_cleanup_free_ char *parent = NULL;
- int r;
assert(a);
- r = path_get_parent(a->where, &parent);
- if (r < 0)
- return r;
+ parent = dirname_malloc(a->where);
+ if (!parent)
+ return -ENOMEM;
return unit_require_mounts_for(UNIT(a), parent);
}
@@ -153,6 +148,9 @@ static int automount_add_default_dependencies(Automount *a) {
assert(a);
+ if (!UNIT(a)->default_dependencies)
+ return 0;
+
if (UNIT(a)->manager->running_as != MANAGER_SYSTEM)
return 0;
@@ -224,11 +222,9 @@ static int automount_load(Unit *u) {
if (r < 0)
return r;
- if (UNIT(a)->default_dependencies) {
- r = automount_add_default_dependencies(a);
- if (r < 0)
- return r;
- }
+ r = automount_add_default_dependencies(a);
+ if (r < 0)
+ return r;
}
return automount_verify(a);
@@ -608,12 +604,16 @@ static void automount_enter_waiting(Automount *a) {
return;
fail:
+ log_unit_error_errno(UNIT(a), r, "Failed to initialize automounter: %m");
+
safe_close_pair(p);
- if (mounted)
- repeat_unmount(a->where);
+ if (mounted) {
+ r = repeat_unmount(a->where, MNT_DETACH);
+ if (r < 0)
+ log_error_errno(r, "Failed to unmount, ignoring: %m");
+ }
- log_unit_error_errno(UNIT(a), r, "Failed to initialize automounter: %m");
automount_enter_dead(a, AUTOMOUNT_FAILURE_RESOURCES);
}
@@ -728,8 +728,7 @@ static void automount_enter_runnning(Automount *a) {
if (!S_ISDIR(st.st_mode) || st.st_dev != a->dev_id)
log_unit_info(UNIT(a), "Automount point already active?");
else {
- r = manager_add_job(UNIT(a)->manager, JOB_START, UNIT_TRIGGER(UNIT(a)),
- JOB_REPLACE, true, &error, NULL);
+ r = manager_add_job(UNIT(a)->manager, JOB_START, UNIT_TRIGGER(UNIT(a)), JOB_REPLACE, &error, NULL);
if (r < 0) {
log_unit_warning(UNIT(a), "Failed to queue mount startup job: %s", bus_error_message(&error, r));
goto fail;
@@ -774,8 +773,9 @@ static int automount_stop(Unit *u) {
static int automount_serialize(Unit *u, FILE *f, FDSet *fds) {
Automount *a = AUTOMOUNT(u);
- void *p;
Iterator i;
+ void *p;
+ int r;
assert(a);
assert(f);
@@ -790,15 +790,9 @@ static int automount_serialize(Unit *u, FILE *f, FDSet *fds) {
SET_FOREACH(p, a->expire_tokens, i)
unit_serialize_item_format(u, f, "expire-token", "%u", PTR_TO_UINT(p));
- if (a->pipe_fd >= 0) {
- int copy;
-
- copy = fdset_put_dup(fds, a->pipe_fd);
- if (copy < 0)
- return copy;
-
- unit_serialize_item_format(u, f, "pipe-fd", "%i", copy);
- }
+ r = unit_serialize_item_fd(u, f, fds, "pipe-fd", a->pipe_fd);
+ if (r < 0)
+ return r;
return 0;
}
@@ -979,7 +973,7 @@ static int automount_dispatch_io(sd_event_source *s, int fd, uint32_t events, vo
break;
}
- r = manager_add_job(UNIT(a)->manager, JOB_STOP, UNIT_TRIGGER(UNIT(a)), JOB_REPLACE, true, &error, NULL);
+ r = manager_add_job(UNIT(a)->manager, JOB_STOP, UNIT_TRIGGER(UNIT(a)), JOB_REPLACE, &error, NULL);
if (r < 0) {
log_unit_warning(UNIT(a), "Failed to queue umount startup job: %s", bus_error_message(&error, r));
goto fail;
diff --git a/src/core/bus-endpoint.c b/src/core/bus-endpoint.c
index 0c4b3e7c8b..d22a80c91f 100644
--- a/src/core/bus-endpoint.c
+++ b/src/core/bus-endpoint.c
@@ -19,10 +19,11 @@
#include <stdlib.h>
-#include "kdbus.h"
+#include "alloc-util.h"
+#include "bus-endpoint.h"
#include "bus-kernel.h"
#include "bus-policy.h"
-#include "bus-endpoint.h"
+#include "kdbus.h"
int bus_kernel_set_endpoint_policy(int fd, uid_t uid, BusEndpoint *ep) {
diff --git a/src/core/bus-endpoint.h b/src/core/bus-endpoint.h
index 4a31f4c4be..f6c5f7c5af 100644
--- a/src/core/bus-endpoint.h
+++ b/src/core/bus-endpoint.h
@@ -24,8 +24,8 @@
typedef struct BusEndpoint BusEndpoint;
typedef struct BusEndpointPolicy BusEndpointPolicy;
-#include "hashmap.h"
#include "bus-policy.h"
+#include "hashmap.h"
struct BusEndpointPolicy {
char *name;
diff --git a/src/core/bus-policy.c b/src/core/bus-policy.c
index a6a8fcd4d3..4907c268e8 100644
--- a/src/core/bus-policy.c
+++ b/src/core/bus-policy.c
@@ -19,10 +19,13 @@
#include <stdlib.h>
-#include "kdbus.h"
-#include "util.h"
+#include "alloc-util.h"
#include "bus-kernel.h"
#include "bus-policy.h"
+#include "kdbus.h"
+#include "string-table.h"
+#include "user-util.h"
+#include "util.h"
int bus_kernel_translate_access(BusPolicyAccess access) {
assert(access >= 0);
diff --git a/src/core/bus-policy.h b/src/core/bus-policy.h
index 3b04f5457a..2f61289185 100644
--- a/src/core/bus-policy.h
+++ b/src/core/bus-policy.h
@@ -21,9 +21,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "kdbus.h"
#include "list.h"
#include "macro.h"
-#include "kdbus.h"
typedef struct BusNamePolicy BusNamePolicy;
diff --git a/src/core/busname.c b/src/core/busname.c
index ba353ab660..04fa12a4da 100644
--- a/src/core/busname.c
+++ b/src/core/busname.c
@@ -21,17 +21,23 @@
#include <sys/mman.h>
-#include "special.h"
-#include "formats-util.h"
-#include "signal-util.h"
-#include "bus-kernel.h"
+#include "alloc-util.h"
#include "bus-internal.h"
+#include "bus-kernel.h"
+#include "bus-policy.h"
#include "bus-util.h"
+#include "busname.h"
+#include "dbus-busname.h"
+#include "fd-util.h"
+#include "formats-util.h"
#include "kdbus.h"
-#include "bus-policy.h"
+#include "parse-util.h"
+#include "process-util.h"
#include "service.h"
-#include "dbus-busname.h"
-#include "busname.h"
+#include "signal-util.h"
+#include "special.h"
+#include "string-table.h"
+#include "string-util.h"
static const UnitActiveState state_translation_table[_BUSNAME_STATE_MAX] = {
[BUSNAME_DEAD] = UNIT_INACTIVE,
@@ -358,10 +364,9 @@ static int busname_coldplug(Unit *u) {
if (n->deserialized_state == n->state)
return 0;
- if (IN_SET(n->deserialized_state, BUSNAME_MAKING, BUSNAME_SIGTERM, BUSNAME_SIGKILL)) {
-
- if (n->control_pid <= 0)
- return -EBADMSG;
+ if (n->control_pid > 0 &&
+ pid_is_unwaited(n->control_pid) &&
+ IN_SET(n->deserialized_state, BUSNAME_MAKING, BUSNAME_SIGTERM, BUSNAME_SIGKILL)) {
r = unit_watch_pid(UNIT(n), n->control_pid);
if (r < 0)
@@ -585,7 +590,13 @@ static void busname_enter_running(BusName *n) {
}
if (!pending) {
- r = manager_add_job(UNIT(n)->manager, JOB_START, UNIT_DEREF(n->service), JOB_REPLACE, true, &error, NULL);
+ if (!UNIT_ISSET(n->service)) {
+ log_unit_error(UNIT(n), "Service to activate vanished, refusing activation.");
+ r = -ENOENT;
+ goto fail;
+ }
+
+ r = manager_add_job(UNIT(n)->manager, JOB_START, UNIT_DEREF(n->service), JOB_REPLACE, &error, NULL);
if (r < 0)
goto fail;
}
@@ -656,6 +667,7 @@ static int busname_stop(Unit *u) {
static int busname_serialize(Unit *u, FILE *f, FDSet *fds) {
BusName *n = BUSNAME(u);
+ int r;
assert(n);
assert(f);
@@ -667,15 +679,9 @@ static int busname_serialize(Unit *u, FILE *f, FDSet *fds) {
if (n->control_pid > 0)
unit_serialize_item_format(u, f, "control-pid", PID_FMT, n->control_pid);
- if (n->starter_fd >= 0) {
- int copy;
-
- copy = fdset_put_dup(fds, n->starter_fd);
- if (copy < 0)
- return copy;
-
- unit_serialize_item_format(u, f, "starter-fd", "%i", copy);
- }
+ r = unit_serialize_item_fd(u, f, fds, "starter-fd", n->starter_fd);
+ if (r < 0)
+ return r;
return 0;
}
diff --git a/src/core/busname.h b/src/core/busname.h
index 1bc3290596..46f7b6f097 100644
--- a/src/core/busname.h
+++ b/src/core/busname.h
@@ -24,6 +24,8 @@
typedef struct BusName BusName;
typedef struct BusNamePolicy BusNamePolicy;
+#include "unit.h"
+
typedef enum BusNameResult {
BUSNAME_SUCCESS,
BUSNAME_FAILURE_RESOURCES,
diff --git a/src/core/cgroup.c b/src/core/cgroup.c
index 0c790c33da..d122175417 100644
--- a/src/core/cgroup.c
+++ b/src/core/cgroup.c
@@ -22,12 +22,18 @@
#include <fcntl.h>
#include <fnmatch.h>
+#include "alloc-util.h"
#include "cgroup-util.h"
+#include "cgroup.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
+#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
#include "special.h"
-
-#include "cgroup.h"
+#include "string-table.h"
+#include "string-util.h"
#define CGROUP_CPU_QUOTA_PERIOD_USEC ((usec_t) 100 * USEC_PER_MSEC)
@@ -211,7 +217,7 @@ static int whitelist_device(const char *path, const char *node, const char *acc)
r = cg_set_attribute("devices", path, "devices.allow", buf);
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL) ? LOG_DEBUG : LOG_WARNING, r,
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set devices.allow on %s: %m", path);
return r;
@@ -282,7 +288,7 @@ static int whitelist_major(const char *path, const char *name, char type, const
r = cg_set_attribute("devices", path, "devices.allow", buf);
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL) ? LOG_DEBUG : LOG_WARNING, r,
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set devices.allow on %s: %m", path);
}
@@ -322,13 +328,13 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u
c->cpu_shares != CGROUP_CPU_SHARES_INVALID ? c->cpu_shares : CGROUP_CPU_SHARES_DEFAULT);
r = cg_set_attribute("cpu", path, "cpu.shares", buf);
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set cpu.shares on %s: %m", path);
sprintf(buf, USEC_FMT "\n", CGROUP_CPU_QUOTA_PERIOD_USEC);
r = cg_set_attribute("cpu", path, "cpu.cfs_period_us", buf);
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set cpu.cfs_period_us on %s: %m", path);
if (c->cpu_quota_per_sec_usec != USEC_INFINITY) {
@@ -337,7 +343,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u
} else
r = cg_set_attribute("cpu", path, "cpu.cfs_quota_us", "-1");
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set cpu.cfs_quota_us on %s: %m", path);
}
@@ -353,7 +359,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u
c->blockio_weight != CGROUP_BLKIO_WEIGHT_INVALID ? c->blockio_weight : CGROUP_BLKIO_WEIGHT_DEFAULT);
r = cg_set_attribute("blkio", path, "blkio.weight", buf);
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set blkio.weight on %s: %m", path);
/* FIXME: no way to reset this list */
@@ -367,7 +373,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u
sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), w->weight);
r = cg_set_attribute("blkio", path, "blkio.weight_device", buf);
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set blkio.weight_device on %s: %m", path);
}
}
@@ -386,7 +392,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u
sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), b->bandwidth);
r = cg_set_attribute("blkio", path, a, buf);
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set %s on %s: %m", a, path);
}
}
@@ -410,7 +416,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u
}
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set memory.limit_in_bytes/memory.max on %s: %m", path);
}
@@ -426,7 +432,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u
else
r = cg_set_attribute("devices", path, "devices.allow", "a");
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL) ? LOG_DEBUG : LOG_WARNING, r,
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to reset devices.list on %s: %m", path);
if (c->device_policy == CGROUP_CLOSED ||
@@ -488,7 +494,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u
r = cg_set_attribute("pids", path, "pids.max", "max");
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set pids.max on %s: %m", path);
}
@@ -499,7 +505,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, u
r = cg_set_attribute("net_cls", path, "net_cls.classid", buf);
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS) ? LOG_DEBUG : LOG_WARNING, r,
+ log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
"Failed to set net_cls.classid on %s: %m", path);
}
}
@@ -1203,7 +1209,7 @@ int unit_search_main_pid(Unit *u, pid_t *ret) {
continue;
/* Ignore processes that aren't our kids */
- if (get_parent_of_pid(npid, &ppid) >= 0 && ppid != mypid)
+ if (get_process_ppid(npid, &ppid) >= 0 && ppid != mypid)
continue;
if (pid != 0)
diff --git a/src/core/cgroup.h b/src/core/cgroup.h
index 457544b49f..1b18d06652 100644
--- a/src/core/cgroup.h
+++ b/src/core/cgroup.h
@@ -112,8 +112,8 @@ struct CGroupContext {
bool delegate;
};
-#include "unit.h"
#include "cgroup-util.h"
+#include "unit.h"
void cgroup_context_init(CGroupContext *c);
void cgroup_context_done(CGroupContext *c);
diff --git a/src/core/dbus-automount.c b/src/core/dbus-automount.c
index 5162ce34cb..54830a515b 100644
--- a/src/core/dbus-automount.c
+++ b/src/core/dbus-automount.c
@@ -20,8 +20,9 @@
***/
#include "automount.h"
-#include "dbus-automount.h"
#include "bus-util.h"
+#include "dbus-automount.h"
+#include "string-util.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, automount_result, AutomountResult);
diff --git a/src/core/dbus-busname.c b/src/core/dbus-busname.c
index b1ceb05b1a..445b237643 100644
--- a/src/core/dbus-busname.c
+++ b/src/core/dbus-busname.c
@@ -19,10 +19,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "unit.h"
+#include "bus-util.h"
#include "busname.h"
#include "dbus-busname.h"
-#include "bus-util.h"
+#include "string-util.h"
+#include "unit.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, busname_result, BusNameResult);
diff --git a/src/core/dbus-cgroup.c b/src/core/dbus-cgroup.c
index f334dc928d..3fd295baa9 100644
--- a/src/core/dbus-cgroup.c
+++ b/src/core/dbus-cgroup.c
@@ -19,11 +19,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
#include "bus-util.h"
-#include "path-util.h"
#include "cgroup-util.h"
#include "cgroup.h"
#include "dbus-cgroup.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "path-util.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_cgroup_device_policy, cgroup_device_policy, CGroupDevicePolicy);
@@ -421,7 +424,9 @@ int bus_cgroup_set_property(
fprintf(f, "BlockIOWriteBandwidth=%s %" PRIu64 "\n", a->path, a->bandwidth);
}
- fflush(f);
+ r = fflush_and_check(f);
+ if (r < 0)
+ return r;
unit_write_drop_in_private(u, mode, name, buf);
}
@@ -495,7 +500,9 @@ int bus_cgroup_set_property(
LIST_FOREACH(device_weights, a, c->blockio_device_weights)
fprintf(f, "BlockIODeviceWeight=%s %" PRIu64 "\n", a->path, a->weight);
- fflush(f);
+ r = fflush_and_check(f);
+ if (r < 0)
+ return r;
unit_write_drop_in_private(u, mode, name, buf);
}
@@ -640,7 +647,9 @@ int bus_cgroup_set_property(
LIST_FOREACH(device_allow, a, c->device_allow)
fprintf(f, "DeviceAllow=%s %s%s%s\n", a->path, a->r ? "r" : "", a->w ? "w" : "", a->m ? "m" : "");
- fflush(f);
+ r = fflush_and_check(f);
+ if (r < 0)
+ return r;
unit_write_drop_in_private(u, mode, name, buf);
}
diff --git a/src/core/dbus-cgroup.h b/src/core/dbus-cgroup.h
index c2a3910f3d..9dc187c066 100644
--- a/src/core/dbus-cgroup.h
+++ b/src/core/dbus-cgroup.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "cgroup.h"
extern const sd_bus_vtable bus_cgroup_vtable[];
diff --git a/src/core/dbus-device.c b/src/core/dbus-device.c
index cb156fd37c..97e4a47556 100644
--- a/src/core/dbus-device.c
+++ b/src/core/dbus-device.c
@@ -19,9 +19,9 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "unit.h"
-#include "device.h"
#include "dbus-device.h"
+#include "device.h"
+#include "unit.h"
const sd_bus_vtable bus_device_vtable[] = {
SD_BUS_VTABLE_START(0),
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index adf613d328..093179c003 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -25,22 +25,28 @@
#include <seccomp.h>
#endif
+#include "af-list.h"
+#include "alloc-util.h"
#include "bus-util.h"
-#include "missing.h"
-#include "ioprio.h"
-#include "strv.h"
-#include "fileio.h"
-#include "execute.h"
-#include "capability.h"
+#include "capability-util.h"
+#include "dbus-execute.h"
#include "env-util.h"
-#include "af-list.h"
+#include "execute.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "ioprio.h"
+#include "missing.h"
#include "namespace.h"
+#include "parse-util.h"
#include "path-util.h"
-#include "dbus-execute.h"
-
+#include "process-util.h"
+#include "rlimit-util.h"
#ifdef HAVE_SECCOMP
#include "seccomp-util.h"
#endif
+#include "strv.h"
+#include "syslog-util.h"
+#include "utf8.h"
BUS_DEFINE_PROPERTY_GET_ENUM(bus_property_get_exec_output, exec_output, ExecOutput);
@@ -83,45 +89,6 @@ static int property_get_environment_files(
return sd_bus_message_close_container(reply);
}
-static int property_get_rlimit(
- sd_bus *bus,
- const char *path,
- const char *interface,
- const char *property,
- sd_bus_message *reply,
- void *userdata,
- sd_bus_error *error) {
-
- struct rlimit *rl;
- uint64_t u;
- rlim_t x;
-
- assert(bus);
- assert(reply);
- assert(userdata);
-
- rl = *(struct rlimit**) userdata;
- if (rl)
- x = rl->rlim_max;
- else {
- struct rlimit buf = {};
- int z;
-
- z = rlimit_from_string(property);
- assert(z >= 0);
-
- getrlimit(z, &buf);
- x = buf.rlim_max;
- }
-
- /* rlim_t might have different sizes, let's map
- * RLIMIT_INFINITY to (uint64_t) -1, so that it is the same on
- * all archs */
- u = x == RLIM_INFINITY ? (uint64_t) -1 : (uint64_t) x;
-
- return sd_bus_message_append(reply, "t", u);
-}
-
static int property_get_oom_score_adjust(
sd_bus *bus,
const char *path,
@@ -146,7 +113,7 @@ static int property_get_oom_score_adjust(
n = 0;
if (read_one_line_file("/proc/self/oom_score_adj", &t) >= 0)
- safe_atoi(t, &n);
+ safe_atoi32(t, &n);
}
return sd_bus_message_append(reply, "i", n);
@@ -622,27 +589,64 @@ static int property_get_working_directory(
return sd_bus_message_append(reply, "s", wd);
}
+static int property_get_syslog_level(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ ExecContext *c = userdata;
+
+ assert(bus);
+ assert(reply);
+ assert(c);
+
+ return sd_bus_message_append(reply, "i", LOG_PRI(c->syslog_priority));
+}
+
+static int property_get_syslog_facility(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ ExecContext *c = userdata;
+
+ assert(bus);
+ assert(reply);
+ assert(c);
+
+ return sd_bus_message_append(reply, "i", LOG_FAC(c->syslog_priority));
+}
+
const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("Environment", "as", NULL, offsetof(ExecContext, environment), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("EnvironmentFiles", "a(sb)", property_get_environment_files, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("PassEnvironment", "as", NULL, offsetof(ExecContext, pass_environment), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("UMask", "u", bus_property_get_mode, offsetof(ExecContext, umask), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitCPU", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitFSIZE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitDATA", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitSTACK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitCORE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitRSS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitNOFILE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitAS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitNPROC", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitMEMLOCK", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitLOCKS", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitSIGPENDING", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitMSGQUEUE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitNICE", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitRTPRIO", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("LimitRTTIME", "t", property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitCPU", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitFSIZE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitDATA", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitSTACK", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitCORE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitRSS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitNOFILE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitAS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitNPROC", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitMEMLOCK", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitLOCKS", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitSIGPENDING", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitMSGQUEUE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitNICE", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitRTPRIO", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("LimitRTTIME", "t", bus_property_get_rlimit, offsetof(ExecContext, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("WorkingDirectory", "s", property_get_working_directory, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(ExecContext, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OOMScoreAdjust", "i", property_get_oom_score_adjust, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@@ -664,6 +668,8 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("SyslogPriority", "i", bus_property_get_int, offsetof(ExecContext, syslog_priority), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SyslogIdentifier", "s", NULL, offsetof(ExecContext, syslog_identifier), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SyslogLevelPrefix", "b", bus_property_get_bool, offsetof(ExecContext, syslog_level_prefix), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("SyslogLevel", "i", property_get_syslog_level, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("SyslogFacility", "i", property_get_syslog_facility, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Capabilities", "s", property_get_capabilities, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SecureBits", "i", bus_property_get_int, offsetof(ExecContext, secure_bits), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("CapabilityBoundingSet", "t", property_get_capability_bounding_set, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@@ -856,7 +862,64 @@ int bus_exec_context_set_transient_property(
}
return 1;
+ } else if (streq(name, "SyslogIdentifier")) {
+ const char *id;
+
+ r = sd_bus_message_read(message, "s", &id);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+
+ if (isempty(id)) {
+ c->syslog_identifier = mfree(c->syslog_identifier);
+ } else {
+ char *t;
+
+ t = strdup(id);
+ if (!t)
+ return -ENOMEM;
+
+ free(c->syslog_identifier);
+ c->syslog_identifier = t;
+ }
+
+ unit_write_drop_in_private_format(u, mode, name, "SyslogIdentifier=%s\n", id);
+ }
+
+ return 1;
+ } else if (streq(name, "SyslogLevel")) {
+ int level;
+
+ r = sd_bus_message_read(message, "i", &level);
+ if (r < 0)
+ return r;
+
+ if (!log_level_is_valid(level))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log level value out of range");
+
+ if (mode != UNIT_CHECK) {
+ c->syslog_priority = (c->syslog_priority & LOG_FACMASK) | level;
+ unit_write_drop_in_private_format(u, mode, name, "SyslogLevel=%i\n", level);
+ }
+
+ return 1;
+ } else if (streq(name, "SyslogFacility")) {
+ int facility;
+
+ r = sd_bus_message_read(message, "i", &facility);
+ if (r < 0)
+ return r;
+
+ if (!log_facility_unshifted_is_valid(facility))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Log facility value out of range");
+
+ if (mode != UNIT_CHECK) {
+ c->syslog_priority = (facility << 3) | LOG_PRI(c->syslog_priority);
+ unit_write_drop_in_private_format(u, mode, name, "SyslogFacility=%i\n", facility);
+ }
+ return 1;
} else if (streq(name, "Nice")) {
int n;
@@ -998,7 +1061,7 @@ int bus_exec_context_set_transient_property(
} else if (STR_IN_SET(name,
"IgnoreSIGPIPE", "TTYVHangup", "TTYReset",
"PrivateTmp", "PrivateDevices", "PrivateNetwork",
- "NoNewPrivileges")) {
+ "NoNewPrivileges", "SyslogLevelPrefix")) {
int b;
r = sd_bus_message_read(message, "b", &b);
@@ -1020,6 +1083,8 @@ int bus_exec_context_set_transient_property(
c->private_network = b;
else if (streq(name, "NoNewPrivileges"))
c->no_new_privileges = b;
+ else if (streq(name, "SyslogLevelPrefix"))
+ c->syslog_level_prefix = b;
unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, yes_no(b));
}
@@ -1097,18 +1162,299 @@ int bus_exec_context_set_transient_property(
_cleanup_free_ char *joined = NULL;
char **e;
- e = strv_env_merge(2, c->environment, l);
- if (!e)
- return -ENOMEM;
+ if (strv_length(l) == 0) {
+ c->environment = strv_free(c->environment);
+ unit_write_drop_in_private_format(u, mode, name, "Environment=\n");
+ } else {
+ e = strv_env_merge(2, c->environment, l);
+ if (!e)
+ return -ENOMEM;
- strv_free(c->environment);
- c->environment = e;
+ strv_free(c->environment);
+ c->environment = e;
- joined = strv_join_quoted(c->environment);
- if (!joined)
- return -ENOMEM;
+ joined = strv_join_quoted(c->environment);
+ if (!joined)
+ return -ENOMEM;
+
+ unit_write_drop_in_private_format(u, mode, name, "Environment=%s\n", joined);
+ }
+ }
+
+ return 1;
+
+ } else if (streq(name, "TimerSlackNSec")) {
+
+ nsec_t n;
+
+ r = sd_bus_message_read(message, "t", &n);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ c->timer_slack_nsec = n;
+ unit_write_drop_in_private_format(u, mode, name, "TimerSlackNSec=" NSEC_FMT "\n", n);
+ }
+
+ return 1;
+
+ } else if (streq(name, "OOMScoreAdjust")) {
+ int oa;
+
+ r = sd_bus_message_read(message, "i", &oa);
+ if (r < 0)
+ return r;
+
+ if (!oom_score_adjust_is_valid(oa))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "OOM score adjust value out of range");
- unit_write_drop_in_private_format(u, mode, name, "Environment=%s\n", joined);
+ if (mode != UNIT_CHECK) {
+ c->oom_score_adjust = oa;
+ c->oom_score_adjust_set = true;
+ unit_write_drop_in_private_format(u, mode, name, "OOMScoreAdjust=%i\n", oa);
+ }
+
+ return 1;
+
+ } else if (streq(name, "EnvironmentFiles")) {
+
+ _cleanup_free_ char *joined = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ _cleanup_free_ char **l = NULL;
+ size_t size = 0;
+ char **i;
+
+ r = sd_bus_message_enter_container(message, 'a', "(sb)");
+ if (r < 0)
+ return r;
+
+ f = open_memstream(&joined, &size);
+ if (!f)
+ return -ENOMEM;
+
+ STRV_FOREACH(i, c->environment_files)
+ fprintf(f, "EnvironmentFile=%s\n", *i);
+
+ while ((r = sd_bus_message_enter_container(message, 'r', "sb")) > 0) {
+ const char *path;
+ int b;
+
+ r = sd_bus_message_read(message, "sb", &path, &b);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_exit_container(message);
+ if (r < 0)
+ return r;
+
+ if (!isempty(path) && !path_is_absolute(path))
+ return sd_bus_error_set_errnof(error, EINVAL, "Path %s is not absolute.", path);
+
+ if (mode != UNIT_CHECK) {
+ char *buf = NULL;
+
+ buf = strjoin(b ? "-" : "", path, NULL);
+ if (!buf)
+ return -ENOMEM;
+
+ fprintf(f, "EnvironmentFile=%s\n", buf);
+
+ r = strv_consume(&l, buf);
+ if (r < 0)
+ return r;
+ }
+ }
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_exit_container(message);
+ if (r < 0)
+ return r;
+
+ r = fflush_and_check(f);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ if (strv_isempty(l)) {
+ c->environment_files = strv_free(c->environment_files);
+ unit_write_drop_in_private(u, mode, name, "EnvironmentFile=\n");
+ } else {
+ r = strv_extend_strv(&c->environment_files, l, true);
+ if (r < 0)
+ return r;
+
+ unit_write_drop_in_private(u, mode, name, joined);
+ }
+ }
+
+ return 1;
+
+ } else if (streq(name, "PassEnvironment")) {
+
+ _cleanup_strv_free_ char **l = NULL;
+
+ r = sd_bus_message_read_strv(message, &l);
+ if (r < 0)
+ return r;
+
+ if (!strv_env_name_is_valid(l))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid PassEnvironment block.");
+
+ if (mode != UNIT_CHECK) {
+ if (strv_isempty(l)) {
+ c->pass_environment = strv_free(c->pass_environment);
+ unit_write_drop_in_private_format(u, mode, name, "PassEnvironment=\n");
+ } else {
+ _cleanup_free_ char *joined = NULL;
+
+ r = strv_extend_strv(&c->pass_environment, l, true);
+ if (r < 0)
+ return r;
+
+ joined = strv_join_quoted(c->pass_environment);
+ if (!joined)
+ return -ENOMEM;
+
+ unit_write_drop_in_private_format(u, mode, name, "PassEnvironment=%s\n", joined);
+ }
+ }
+
+ return 1;
+
+ } else if (STR_IN_SET(name, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) {
+
+ _cleanup_strv_free_ char **l = NULL;
+ char ***dirs;
+ char **p;
+
+ r = sd_bus_message_read_strv(message, &l);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(p, l) {
+ int offset;
+ if (!utf8_is_valid(*p))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s", name);
+
+ offset = **p == '-';
+ if (!path_is_absolute(*p + offset))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid %s", name);
+ }
+
+ if (mode != UNIT_CHECK) {
+ _cleanup_free_ char *joined = NULL;
+
+ if (streq(name, "ReadWriteDirectories"))
+ dirs = &c->read_write_dirs;
+ else if (streq(name, "ReadOnlyDirectories"))
+ dirs = &c->read_only_dirs;
+ else if (streq(name, "InaccessibleDirectories"))
+ dirs = &c->inaccessible_dirs;
+
+ if (strv_length(l) == 0) {
+ *dirs = strv_free(*dirs);
+ unit_write_drop_in_private_format(u, mode, name, "%s=\n", name);
+ } else {
+ r = strv_extend_strv(dirs, l, true);
+
+ if (r < 0)
+ return -ENOMEM;
+
+ joined = strv_join_quoted(*dirs);
+ if (!joined)
+ return -ENOMEM;
+
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, joined);
+ }
+
+ }
+
+ return 1;
+
+ } else if (streq(name, "ProtectSystem")) {
+ const char *s;
+ ProtectSystem ps;
+
+ r = sd_bus_message_read(message, "s", &s);
+ if (r < 0)
+ return r;
+
+ r = parse_boolean(s);
+ if (r > 0)
+ ps = PROTECT_SYSTEM_YES;
+ else if (r == 0)
+ ps = PROTECT_SYSTEM_NO;
+ else {
+ ps = protect_system_from_string(s);
+ if (ps < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Failed to parse protect system value");
+ }
+
+ if (mode != UNIT_CHECK) {
+ c->protect_system = ps;
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s);
+ }
+
+ return 1;
+
+ } else if (streq(name, "ProtectHome")) {
+ const char *s;
+ ProtectHome ph;
+
+ r = sd_bus_message_read(message, "s", &s);
+ if (r < 0)
+ return r;
+
+ r = parse_boolean(s);
+ if (r > 0)
+ ph = PROTECT_HOME_YES;
+ else if (r == 0)
+ ph = PROTECT_HOME_NO;
+ else {
+ ph = protect_home_from_string(s);
+ if (ph < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Failed to parse protect home value");
+ }
+
+ if (mode != UNIT_CHECK) {
+ c->protect_home = ph;
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s);
+ }
+
+ return 1;
+
+ } else if (streq(name, "RuntimeDirectory")) {
+ _cleanup_strv_free_ char **l = NULL;
+ char **p;
+
+ r = sd_bus_message_read_strv(message, &l);
+ if (r < 0)
+ return r;
+
+ STRV_FOREACH(p, l) {
+ if (!filename_is_valid(*p))
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Runtime directory is not valid %s", *p);
+ }
+
+ if (mode != UNIT_CHECK) {
+ _cleanup_free_ char *joined = NULL;
+
+ if (strv_isempty(l)) {
+ c->runtime_directory = strv_free(c->runtime_directory);
+ unit_write_drop_in_private_format(u, mode, name, "%s=\n", name);
+ } else {
+ r = strv_extend_strv(&c->runtime_directory, l, true);
+
+ if (r < 0)
+ return -ENOMEM;
+
+ joined = strv_join_quoted(c->runtime_directory);
+ if (!joined)
+ return -ENOMEM;
+
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, joined);
+ }
}
return 1;
diff --git a/src/core/dbus-execute.h b/src/core/dbus-execute.h
index e4c2d5ddf6..c44517ea22 100644
--- a/src/core/dbus-execute.h
+++ b/src/core/dbus-execute.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "execute.h"
#define BUS_EXEC_STATUS_VTABLE(prefix, offset, flags) \
diff --git a/src/core/dbus-job.c b/src/core/dbus-job.c
index cd6b909426..8c30d66250 100644
--- a/src/core/dbus-job.c
+++ b/src/core/dbus-job.c
@@ -19,12 +19,15 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "log.h"
#include "sd-bus.h"
-#include "selinux-access.h"
-#include "job.h"
+
+#include "alloc-util.h"
#include "dbus-job.h"
#include "dbus.h"
+#include "job.h"
+#include "log.h"
+#include "selinux-access.h"
+#include "string-util.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, job_type, JobType);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_state, job_state, JobState);
diff --git a/src/core/dbus-job.h b/src/core/dbus-job.h
index fb5f1b513e..0f2fbe2ee2 100644
--- a/src/core/dbus-job.h
+++ b/src/core/dbus-job.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "job.h"
extern const sd_bus_vtable bus_job_vtable[];
diff --git a/src/core/dbus-kill.c b/src/core/dbus-kill.c
index 3b8116281c..c633eb1b76 100644
--- a/src/core/dbus-kill.c
+++ b/src/core/dbus-kill.c
@@ -19,11 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "signal-util.h"
#include "bus-util.h"
-
-#include "kill.h"
#include "dbus-kill.h"
+#include "kill.h"
+#include "signal-util.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_kill_mode, kill_mode, KillMode);
diff --git a/src/core/dbus-kill.h b/src/core/dbus-kill.h
index 7c15f3a90b..1d32fca547 100644
--- a/src/core/dbus-kill.h
+++ b/src/core/dbus-kill.h
@@ -22,8 +22,9 @@
***/
#include "sd-bus.h"
-#include "unit.h"
+
#include "kill.h"
+#include "unit.h"
extern const sd_bus_vtable bus_kill_vtable[];
diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 1a3a72ae37..4d730290b2 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -20,27 +20,33 @@
***/
#include <errno.h>
+#include <sys/prctl.h>
#include <unistd.h>
-#include "log.h"
-#include "strv.h"
+#include "alloc-util.h"
+#include "architecture.h"
#include "build.h"
-#include "install.h"
-#include "selinux-access.h"
-#include "watchdog.h"
+#include "bus-common-errors.h"
#include "clock-util.h"
-#include "path-util.h"
-#include "virt.h"
-#include "architecture.h"
-#include "env-util.h"
-#include "dbus.h"
+#include "dbus-execute.h"
#include "dbus-job.h"
#include "dbus-manager.h"
#include "dbus-unit.h"
-#include "dbus-snapshot.h"
-#include "dbus-execute.h"
-#include "bus-common-errors.h"
+#include "dbus.h"
+#include "env-util.h"
+#include "fd-util.h"
+#include "fileio.h"
#include "formats-util.h"
+#include "install.h"
+#include "log.h"
+#include "path-util.h"
+#include "selinux-access.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "syslog-util.h"
+#include "virt.h"
+#include "watchdog.h"
static int property_get_version(
sd_bus *bus,
@@ -122,8 +128,7 @@ static int property_get_tainted(
void *userdata,
sd_bus_error *error) {
- char buf[sizeof("split-usr:mtab-not-symlink:cgroups-missing:local-hwclock:")] = "", *e = buf;
- _cleanup_free_ char *p = NULL;
+ char buf[sizeof("split-usr:cgroups-missing:local-hwclock:")] = "", *e = buf;
Manager *m = userdata;
assert(bus);
@@ -133,9 +138,6 @@ static int property_get_tainted(
if (m->taint_usr)
e = stpcpy(e, "split-usr:");
- if (readlink_malloc("/etc/mtab", &p) < 0)
- e = stpcpy(e, "mtab-not-symlink:");
-
if (access("/proc/cgroups", F_OK) < 0)
e = stpcpy(e, "cgroups-missing:");
@@ -350,6 +352,21 @@ static int property_set_runtime_watchdog(
return watchdog_set_timeout(t);
}
+static int property_get_timer_slack_nsec(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ assert(bus);
+ assert(reply);
+
+ return sd_bus_message_append(reply, "t", (uint64_t) prctl(PR_GET_TIMERSLACK));
+}
+
static int method_get_unit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_free_ char *path = NULL;
Manager *m = userdata;
@@ -627,6 +644,7 @@ static int transient_unit_from_message(
Unit **unit,
sd_bus_error *error) {
+ UnitType t;
Unit *u;
int r;
@@ -634,12 +652,18 @@ static int transient_unit_from_message(
assert(message);
assert(name);
+ t = unit_name_to_type(name);
+ if (t < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name or type.");
+
+ if (!unit_vtable[t]->can_transient)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units.", unit_type_to_string(t));
+
r = manager_load_unit(m, name, NULL, error, &u);
if (r < 0)
return r;
- if (u->load_state != UNIT_NOT_FOUND ||
- set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0)
+ if (!unit_is_pristine(u))
return sd_bus_error_setf(error, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name);
/* OK, the unit failed to load and is unreferenced, now let's
@@ -653,6 +677,9 @@ static int transient_unit_from_message(
if (r < 0)
return r;
+ /* Now load the missing bits of the unit we just created */
+ manager_dispatch_load_queue(m);
+
*unit = u;
return 0;
@@ -663,8 +690,6 @@ static int transient_aux_units_from_message(
sd_bus_message *message,
sd_bus_error *error) {
- Unit *u;
- char *name = NULL;
int r;
assert(m);
@@ -675,20 +700,17 @@ static int transient_aux_units_from_message(
return r;
while ((r = sd_bus_message_enter_container(message, 'r', "sa(sv)")) > 0) {
+ const char *name = NULL;
+ Unit *u;
+
r = sd_bus_message_read(message, "s", &name);
if (r < 0)
return r;
r = transient_unit_from_message(m, message, name, &u, error);
- if (r < 0 && r != -EEXIST)
+ if (r < 0)
return r;
- if (r != -EEXIST) {
- r = unit_load(u);
- if (r < 0)
- return r;
- }
-
r = sd_bus_message_exit_container(message);
if (r < 0)
return r;
@@ -707,7 +729,6 @@ static int method_start_transient_unit(sd_bus_message *message, void *userdata,
const char *name, *smode;
Manager *m = userdata;
JobMode mode;
- UnitType t;
Unit *u;
int r;
@@ -722,13 +743,6 @@ static int method_start_transient_unit(sd_bus_message *message, void *userdata,
if (r < 0)
return r;
- t = unit_name_to_type(name);
- if (t < 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit type.");
-
- if (!unit_vtable[t]->can_transient)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units.", unit_type_to_string(t));
-
mode = job_mode_from_string(smode);
if (mode < 0)
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s is invalid.", smode);
@@ -747,13 +761,6 @@ static int method_start_transient_unit(sd_bus_message *message, void *userdata,
if (r < 0)
return r;
- /* And load this stub fully */
- r = unit_load(u);
- if (r < 0)
- return r;
-
- manager_dispatch_load_queue(m);
-
/* Finally, start it */
return bus_unit_queue_job(message, u, JOB_START, mode, false, error);
}
@@ -1083,66 +1090,8 @@ static int method_dump(sd_bus_message *message, void *userdata, sd_bus_error *er
return sd_bus_reply_method_return(message, "s", dump);
}
-static int method_create_snapshot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- _cleanup_free_ char *path = NULL;
- Manager *m = userdata;
- const char *name;
- int cleanup;
- Snapshot *s = NULL;
- int r;
-
- assert(message);
- assert(m);
-
- r = mac_selinux_access_check(message, "start", error);
- if (r < 0)
- return r;
-
- r = sd_bus_message_read(message, "sb", &name, &cleanup);
- if (r < 0)
- return r;
-
- if (isempty(name))
- name = NULL;
-
- r = bus_verify_manage_units_async(m, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
- r = snapshot_create(m, name, cleanup, error, &s);
- if (r < 0)
- return r;
-
- path = unit_dbus_path(UNIT(s));
- if (!path)
- return -ENOMEM;
-
- return sd_bus_reply_method_return(message, "o", path);
-}
-
-static int method_remove_snapshot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Manager *m = userdata;
- const char *name;
- Unit *u;
- int r;
-
- assert(message);
- assert(m);
-
- r = sd_bus_message_read(message, "s", &name);
- if (r < 0)
- return r;
-
- u = manager_get_unit(m, name);
- if (!u)
- return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name);
-
- if (u->type != UNIT_SNAPSHOT)
- return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot", name);
-
- return bus_snapshot_method_remove(message, u, error);
+static int method_refuse_snapshot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+ return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Support for snapshots has been removed.");
}
static int method_reload(sd_bus_message *message, void *userdata, sd_bus_error *error) {
@@ -1562,9 +1511,9 @@ static int method_get_unit_file_state(sd_bus_message *message, void *userdata, s
scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
- state = unit_file_get_state(scope, NULL, name);
- if (state < 0)
- return state;
+ r = unit_file_get_state(scope, NULL, name, &state);
+ if (r < 0)
+ return r;
return sd_bus_reply_method_return(message, "s", unit_file_state_to_string(state));
}
@@ -1692,6 +1641,8 @@ static int method_enable_unit_files_generic(
scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
r = call(scope, runtime, NULL, l, force, &changes, &n_changes);
+ if (r == -ESHUTDOWN)
+ return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked");
if (r < 0)
return r;
@@ -1926,6 +1877,8 @@ static int method_add_dependency_unit_files(sd_bus_message *message, void *userd
scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
r = unit_file_add_dependency(scope, runtime, NULL, l, target, dep, force, &changes, &n_changes);
+ if (r == -ESHUTDOWN)
+ return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit file is masked");
if (r < 0)
return r;
@@ -1971,6 +1924,34 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_PROPERTY("ControlGroup", "s", NULL, offsetof(Manager, cgroup_root), 0),
SD_BUS_PROPERTY("SystemState", "s", property_get_system_state, 0, 0),
SD_BUS_PROPERTY("ExitCode", "y", bus_property_get_unsigned, offsetof(Manager, return_value), 0),
+ SD_BUS_PROPERTY("DefaultTimerAccuracyUSec", "t", bus_property_get_usec, offsetof(Manager, default_timer_accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultTimeoutStartUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_start_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultTimeoutStopUSec", "t", bus_property_get_usec, offsetof(Manager, default_timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultRestartUSec", "t", bus_property_get_usec, offsetof(Manager, default_restart_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultStartLimitInterval", "t", bus_property_get_usec, offsetof(Manager, default_start_limit_interval), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultStartLimitBurst", "u", bus_property_get_unsigned, offsetof(Manager, default_start_limit_burst), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultCPUAccounting", "b", bus_property_get_bool, offsetof(Manager, default_cpu_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultBlockIOAccounting", "b", bus_property_get_bool, offsetof(Manager, default_blockio_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultMemoryAccounting", "b", bus_property_get_bool, offsetof(Manager, default_memory_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultTasksAccounting", "b", bus_property_get_bool, offsetof(Manager, default_tasks_accounting), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitCPU", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CPU]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitFSIZE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_FSIZE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitDATA", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_DATA]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitSTACK", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_STACK]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitCORE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_CORE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitRSS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RSS]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitNOFILE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NOFILE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitAS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_AS]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitNPROC", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NPROC]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitMEMLOCK", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_MEMLOCK]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitLOCKS", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_LOCKS]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitSIGPENDING", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_SIGPENDING]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitMSGQUEUE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_MSGQUEUE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitNICE", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_NICE]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitRTPRIO", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTPRIO]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultLimitRTTIME", "t", bus_property_get_rlimit, offsetof(Manager, rlimit[RLIMIT_RTTIME]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("DefaultTasksMax", "t", NULL, offsetof(Manager, default_tasks_max), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("TimerSlackNSec", "t", property_get_timer_slack_nsec, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD("GetUnit", "s", "o", method_get_unit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetUnitByPID", "u", "o", method_get_unit_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
@@ -1997,8 +1978,8 @@ const sd_bus_vtable bus_manager_vtable[] = {
SD_BUS_METHOD("Subscribe", NULL, NULL, method_subscribe, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Unsubscribe", NULL, NULL, method_unsubscribe, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Dump", NULL, "s", method_dump, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("CreateSnapshot", "sb", "o", method_create_snapshot, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_METHOD("RemoveSnapshot", "s", NULL, method_remove_snapshot, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("CreateSnapshot", "sb", "o", method_refuse_snapshot, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_METHOD("RemoveSnapshot", "s", NULL, method_refuse_snapshot, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Reload", NULL, NULL, method_reload, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Reexecute", NULL, NULL, method_reexecute, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Exit", NULL, NULL, method_exit, 0),
diff --git a/src/core/dbus-mount.c b/src/core/dbus-mount.c
index 24813c6d20..bc5751a10d 100644
--- a/src/core/dbus-mount.c
+++ b/src/core/dbus-mount.c
@@ -19,13 +19,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "unit.h"
-#include "mount.h"
+#include "bus-util.h"
+#include "dbus-cgroup.h"
#include "dbus-execute.h"
#include "dbus-kill.h"
-#include "dbus-cgroup.h"
#include "dbus-mount.h"
-#include "bus-util.h"
+#include "mount.h"
+#include "string-util.h"
+#include "unit.h"
static int property_get_what(
sd_bus *bus,
diff --git a/src/core/dbus-mount.h b/src/core/dbus-mount.h
index f7004d252f..dd0bf51bb0 100644
--- a/src/core/dbus-mount.h
+++ b/src/core/dbus-mount.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "unit.h"
extern const sd_bus_vtable bus_mount_vtable[];
diff --git a/src/core/dbus-path.c b/src/core/dbus-path.c
index 683561999b..e0544e9161 100644
--- a/src/core/dbus-path.c
+++ b/src/core/dbus-path.c
@@ -19,10 +19,11 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "unit.h"
-#include "path.h"
-#include "dbus-path.h"
#include "bus-util.h"
+#include "dbus-path.h"
+#include "path.h"
+#include "string-util.h"
+#include "unit.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, path_result, PathResult);
diff --git a/src/core/dbus-scope.c b/src/core/dbus-scope.c
index f8fb373bf0..16375b2311 100644
--- a/src/core/dbus-scope.c
+++ b/src/core/dbus-scope.c
@@ -19,17 +19,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "selinux-access.h"
-#include "unit.h"
-#include "scope.h"
-#include "dbus.h"
-#include "bus-util.h"
-#include "bus-internal.h"
+#include "alloc-util.h"
#include "bus-common-errors.h"
-#include "dbus-unit.h"
+#include "bus-internal.h"
+#include "bus-util.h"
#include "dbus-cgroup.h"
#include "dbus-kill.h"
#include "dbus-scope.h"
+#include "dbus-unit.h"
+#include "dbus.h"
+#include "scope.h"
+#include "selinux-access.h"
+#include "unit.h"
static int bus_scope_abandon(sd_bus_message *message, void *userdata, sd_bus_error *error) {
Scope *s = userdata;
diff --git a/src/core/dbus-scope.h b/src/core/dbus-scope.h
index 33beda47b7..4fb0b25e09 100644
--- a/src/core/dbus-scope.h
+++ b/src/core/dbus-scope.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "unit.h"
extern const sd_bus_vtable bus_scope_vtable[];
diff --git a/src/core/dbus-service.c b/src/core/dbus-service.c
index 3436342bef..24f611a593 100644
--- a/src/core/dbus-service.c
+++ b/src/core/dbus-service.c
@@ -19,15 +19,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "strv.h"
-#include "path-util.h"
-#include "unit.h"
-#include "service.h"
+#include "alloc-util.h"
+#include "async.h"
+#include "bus-util.h"
+#include "dbus-cgroup.h"
#include "dbus-execute.h"
#include "dbus-kill.h"
-#include "dbus-cgroup.h"
#include "dbus-service.h"
-#include "bus-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "path-util.h"
+#include "service.h"
+#include "string-util.h"
+#include "strv.h"
+#include "unit.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, service_type, ServiceType);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, service_result, ServiceResult);
@@ -58,7 +63,8 @@ const sd_bus_vtable bus_service_vtable[] = {
SD_BUS_PROPERTY("MainPID", "u", bus_property_get_pid, offsetof(Service, main_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("ControlPID", "u", bus_property_get_pid, offsetof(Service, control_pid), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("BusName", "s", NULL, offsetof(Service, bus_name), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("FileDescriptorStoreMax", "u", NULL, offsetof(Service, n_fd_store_max), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("FileDescriptorStoreMax", "u", bus_property_get_unsigned, offsetof(Service, n_fd_store_max), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("NFileDescriptorStore", "u", bus_property_get_unsigned, offsetof(Service, n_fd_store), 0),
SD_BUS_PROPERTY("StatusText", "s", NULL, offsetof(Service, status_text), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("StatusErrno", "i", NULL, offsetof(Service, status_errno), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Service, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
@@ -120,6 +126,37 @@ static int bus_service_set_transient_property(
return 1;
+ } else if (STR_IN_SET(name,
+ "StandardInputFileDescriptor",
+ "StandardOutputFileDescriptor",
+ "StandardErrorFileDescriptor")) {
+ int fd;
+
+ r = sd_bus_message_read(message, "h", &fd);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ int copy;
+
+ copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+ if (copy < 0)
+ return -errno;
+
+ if (streq(name, "StandardInputFileDescriptor")) {
+ asynchronous_close(s->stdin_fd);
+ s->stdin_fd = copy;
+ } else if (streq(name, "StandardOutputFileDescriptor")) {
+ asynchronous_close(s->stdout_fd);
+ s->stdout_fd = copy;
+ } else {
+ asynchronous_close(s->stderr_fd);
+ s->stderr_fd = copy;
+ }
+ }
+
+ return 1;
+
} else if (streq(name, "ExecStart")) {
unsigned n = 0;
@@ -211,7 +248,9 @@ static int bus_service_set_transient_property(
a);
}
- fflush(f);
+ r = fflush_and_check(f);
+ if (r < 0)
+ return r;
unit_write_drop_in_private(UNIT(s), mode, name, buf);
}
diff --git a/src/core/dbus-service.h b/src/core/dbus-service.h
index aab9f7aa26..a67b64ab5b 100644
--- a/src/core/dbus-service.h
+++ b/src/core/dbus-service.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "unit.h"
extern const sd_bus_vtable bus_service_vtable[];
diff --git a/src/core/dbus-slice.c b/src/core/dbus-slice.c
index 09e78d1f33..469e3e1c93 100644
--- a/src/core/dbus-slice.c
+++ b/src/core/dbus-slice.c
@@ -19,10 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "unit.h"
-#include "slice.h"
#include "dbus-cgroup.h"
#include "dbus-slice.h"
+#include "slice.h"
+#include "unit.h"
const sd_bus_vtable bus_slice_vtable[] = {
SD_BUS_VTABLE_START(0),
diff --git a/src/core/dbus-slice.h b/src/core/dbus-slice.h
index eadc3b1a9c..117d11471b 100644
--- a/src/core/dbus-slice.h
+++ b/src/core/dbus-slice.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "unit.h"
extern const sd_bus_vtable bus_slice_vtable[];
diff --git a/src/core/dbus-snapshot.c b/src/core/dbus-snapshot.c
deleted file mode 100644
index cfe44c9c15..0000000000
--- a/src/core/dbus-snapshot.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "selinux-access.h"
-#include "unit.h"
-#include "dbus.h"
-#include "snapshot.h"
-#include "dbus-snapshot.h"
-
-int bus_snapshot_method_remove(sd_bus_message *message, void *userdata, sd_bus_error *error) {
- Snapshot *s = userdata;
- int r;
-
- assert(message);
- assert(s);
-
- r = mac_selinux_unit_access_check(UNIT(s), message, "stop", error);
- if (r < 0)
- return r;
-
- r = bus_verify_manage_units_async(UNIT(s)->manager, message, error);
- if (r < 0)
- return r;
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
- snapshot_remove(s);
-
- return sd_bus_reply_method_return(message, NULL);
-}
-
-const sd_bus_vtable bus_snapshot_vtable[] = {
- SD_BUS_VTABLE_START(0),
- SD_BUS_PROPERTY("Cleanup", "b", bus_property_get_bool, offsetof(Snapshot, cleanup), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_METHOD("Remove", NULL, NULL, bus_snapshot_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
- SD_BUS_VTABLE_END
-};
diff --git a/src/core/dbus-snapshot.h b/src/core/dbus-snapshot.h
deleted file mode 100644
index 9288f44e15..0000000000
--- a/src/core/dbus-snapshot.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-#pragma once
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include "sd-bus.h"
-
-extern const sd_bus_vtable bus_snapshot_vtable[];
-
-int bus_snapshot_method_remove(sd_bus_message *message, void *userdata, sd_bus_error *error);
diff --git a/src/core/dbus-socket.c b/src/core/dbus-socket.c
index 4611ad5f86..895dd07753 100644
--- a/src/core/dbus-socket.c
+++ b/src/core/dbus-socket.c
@@ -19,12 +19,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "unit.h"
-#include "socket.h"
-#include "dbus-execute.h"
+#include "alloc-util.h"
+#include "bus-util.h"
#include "dbus-cgroup.h"
+#include "dbus-execute.h"
#include "dbus-socket.h"
-#include "bus-util.h"
+#include "socket.h"
+#include "string-util.h"
+#include "unit.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, socket_result, SocketResult);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_bind_ipv6_only, socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
@@ -84,6 +86,25 @@ static int property_get_listen(
return sd_bus_message_close_container(reply);
}
+
+static int property_get_fdname(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ Socket *s = SOCKET(userdata);
+
+ assert(bus);
+ assert(reply);
+ assert(s);
+
+ return sd_bus_message_append(reply, "s", socket_fdname(s));
+}
+
const sd_bus_vtable bus_socket_vtable[] = {
SD_BUS_VTABLE_START(0),
SD_BUS_PROPERTY("BindIPv6Only", "s", property_get_bind_ipv6_only, offsetof(Socket, bind_ipv6_only), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -128,6 +149,8 @@ const sd_bus_vtable bus_socket_vtable[] = {
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Socket, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("NConnections", "u", bus_property_get_unsigned, offsetof(Socket, n_connections), 0),
SD_BUS_PROPERTY("NAccepted", "u", bus_property_get_unsigned, offsetof(Socket, n_accepted), 0),
+ SD_BUS_PROPERTY("FileDescriptorName", "s", property_get_fdname, 0, 0),
+ SD_BUS_PROPERTY("SocketProtocol", "i", bus_property_get_int, offsetof(Socket, socket_protocol), SD_BUS_VTABLE_PROPERTY_CONST),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPre", offsetof(Socket, exec_command[SOCKET_EXEC_START_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStartPost", offsetof(Socket, exec_command[SOCKET_EXEC_START_POST]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
BUS_EXEC_COMMAND_LIST_VTABLE("ExecStopPre", offsetof(Socket, exec_command[SOCKET_EXEC_STOP_PRE]), SD_BUS_VTABLE_PROPERTY_EMITS_INVALIDATION),
diff --git a/src/core/dbus-socket.h b/src/core/dbus-socket.h
index 17164d9871..8dad6ea2e9 100644
--- a/src/core/dbus-socket.h
+++ b/src/core/dbus-socket.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "unit.h"
extern const sd_bus_vtable bus_socket_vtable[];
diff --git a/src/core/dbus-swap.c b/src/core/dbus-swap.c
index 0093371306..f2a0f1d172 100644
--- a/src/core/dbus-swap.c
+++ b/src/core/dbus-swap.c
@@ -20,12 +20,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "unit.h"
-#include "swap.h"
-#include "dbus-execute.h"
+#include "bus-util.h"
#include "dbus-cgroup.h"
+#include "dbus-execute.h"
#include "dbus-swap.h"
-#include "bus-util.h"
+#include "string-util.h"
+#include "swap.h"
+#include "unit.h"
static int property_get_priority(
sd_bus *bus,
diff --git a/src/core/dbus-swap.h b/src/core/dbus-swap.h
index 9469f68ab8..a414ca7f75 100644
--- a/src/core/dbus-swap.h
+++ b/src/core/dbus-swap.h
@@ -23,6 +23,7 @@
***/
#include "sd-bus.h"
+
#include "unit.h"
extern const sd_bus_vtable bus_swap_vtable[];
diff --git a/src/core/dbus-target.c b/src/core/dbus-target.c
index 350f5c3ed2..654bcf1a29 100644
--- a/src/core/dbus-target.c
+++ b/src/core/dbus-target.c
@@ -19,8 +19,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "unit.h"
#include "dbus-target.h"
+#include "unit.h"
const sd_bus_vtable bus_target_vtable[] = {
SD_BUS_VTABLE_START(0),
diff --git a/src/core/dbus-target.h b/src/core/dbus-target.h
index 4c4297bc9e..6be9c9f708 100644
--- a/src/core/dbus-target.h
+++ b/src/core/dbus-target.h
@@ -21,5 +21,6 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "sd-bus.h"
extern const sd_bus_vtable bus_target_vtable[];
diff --git a/src/core/dbus-timer.c b/src/core/dbus-timer.c
index 8ea2cf84a4..4bee82df07 100644
--- a/src/core/dbus-timer.c
+++ b/src/core/dbus-timer.c
@@ -19,11 +19,12 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "unit.h"
-#include "timer.h"
-#include "dbus-timer.h"
+#include "alloc-util.h"
#include "bus-util.h"
+#include "dbus-timer.h"
#include "strv.h"
+#include "timer.h"
+#include "unit.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, timer_result, TimerResult);
@@ -179,8 +180,10 @@ const sd_bus_vtable bus_timer_vtable[] = {
BUS_PROPERTY_DUAL_TIMESTAMP("LastTriggerUSec", offsetof(Timer, last_trigger), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Timer, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("AccuracyUSec", "t", bus_property_get_usec, offsetof(Timer, accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RandomUSec", "t", bus_property_get_usec, offsetof(Timer, random_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Persistent", "b", bus_property_get_bool, offsetof(Timer, persistent), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("WakeSystem", "b", bus_property_get_bool, offsetof(Timer, wake_system), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RemainAfterElapse", "b", bus_property_get_bool, offsetof(Timer, remain_after_elapse), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_VTABLE_END
};
@@ -281,8 +284,23 @@ static int bus_timer_set_transient_property(
return 1;
- } else if (streq(name, "WakeSystem")) {
+ } else if (streq(name, "RandomUSec")) {
+ usec_t u = 0;
+
+ r = sd_bus_message_read(message, "t", &u);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ char time[FORMAT_TIMESPAN_MAX];
+ t->random_usec = u;
+ unit_write_drop_in_private_format(UNIT(t), mode, name, "RandomSec=%s\n", format_timespan(time, sizeof(time), u, USEC_PER_MSEC));
+ }
+
+ return 1;
+
+ } else if (streq(name, "WakeSystem")) {
int b;
r = sd_bus_message_read(message, "b", &b);
@@ -291,11 +309,24 @@ static int bus_timer_set_transient_property(
if (mode != UNIT_CHECK) {
t->wake_system = b;
- unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, yes_no(t->wake_system));
+ unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, yes_no(b));
}
return 1;
+ } else if (streq(name, "RemainAfterElapse")) {
+ int b;
+
+ r = sd_bus_message_read(message, "b", &b);
+ if (r < 0)
+ return r;
+
+ if (mode != UNIT_CHECK) {
+ t->remain_after_elapse = b;
+ unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, yes_no(b));
+ }
+
+ return 1;
}
return 0;
diff --git a/src/core/dbus-timer.h b/src/core/dbus-timer.h
index 103172f055..ca35c4b8c1 100644
--- a/src/core/dbus-timer.h
+++ b/src/core/dbus-timer.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "unit.h"
extern const sd_bus_vtable bus_timer_vtable[];
diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index cd88a87340..d9b7382c82 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -20,14 +20,19 @@
***/
#include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "bus-common-errors.h"
+#include "cgroup-util.h"
+#include "dbus-unit.h"
+#include "dbus.h"
+#include "locale-util.h"
#include "log.h"
#include "selinux-access.h"
-#include "cgroup-util.h"
-#include "strv.h"
-#include "bus-common-errors.h"
#include "special.h"
-#include "dbus.h"
-#include "dbus-unit.h"
+#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState);
static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode);
@@ -113,6 +118,22 @@ static int property_get_dependencies(
return sd_bus_message_close_container(reply);
}
+static int property_get_obsolete_dependencies(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ assert(bus);
+ assert(reply);
+
+ /* For dependency types we don't support anymore always return an empty array */
+ return sd_bus_message_append(reply, "as", 0);
+}
+
static int property_get_description(
sd_bus *bus,
const char *path,
@@ -616,16 +637,12 @@ const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_PROPERTY("Names", "as", property_get_names, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0),
SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Wants", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTS]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BINDS_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PART_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RequisiteOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("RequisiteOfOverridable", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OF_OVERRIDABLE]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -639,6 +656,10 @@ const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_JOINS_NAMESPACE_OF]), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
+ SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
+ SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
+ SD_BUS_PROPERTY("RequisiteOfOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN),
SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST),
@@ -666,7 +687,6 @@ const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool, offsetof(Unit, ignore_on_snapshot), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_failure_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -679,7 +699,7 @@ const sd_bus_vtable bus_unit_vtable[] = {
SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0),
SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("NetClass", "u", bus_property_get_unsigned, offsetof(Unit, cgroup_netclass_id), 0),
+ SD_BUS_PROPERTY("NetClass", "u", NULL, offsetof(Unit, cgroup_netclass_id), 0),
SD_BUS_METHOD("Start", "s", "o", method_start, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("Stop", "s", "o", method_stop, SD_BUS_VTABLE_UNPRIVILEGED),
@@ -984,10 +1004,11 @@ int bus_unit_queue_job(
if ((type == JOB_START && u->refuse_manual_start) ||
(type == JOB_STOP && u->refuse_manual_stop) ||
- ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)))
+ ((type == JOB_RESTART || type == JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)) ||
+ (type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start))
return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only.", u->id);
- r = manager_add_job(u->manager, type, u, mode, true, error, &j);
+ r = manager_add_job(u->manager, type, u, mode, error, &j);
if (r < 0)
return r;
@@ -1103,9 +1124,15 @@ static int bus_unit_set_transient_property(
UnitDependency d;
const char *other;
- d = unit_dependency_from_string(name);
- if (d < 0)
- return -EINVAL;
+ if (streq(name, "RequiresOverridable"))
+ d = UNIT_REQUIRES; /* redirect for obsolete unit dependency type */
+ else if (streq(name, "RequisiteOverridable"))
+ d = UNIT_REQUISITE; /* same here */
+ else {
+ d = unit_dependency_from_string(name);
+ if (d < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit dependency: %s", name);
+ }
r = sd_bus_message_enter_container(message, 'a', "s");
if (r < 0)
diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h
index b622e0ae8d..b8c6ec398a 100644
--- a/src/core/dbus-unit.h
+++ b/src/core/dbus-unit.h
@@ -22,6 +22,7 @@
***/
#include "sd-bus.h"
+
#include "unit.h"
extern const sd_bus_vtable bus_unit_vtable[];
diff --git a/src/core/dbus.c b/src/core/dbus.c
index 2d6a1ff836..7932130036 100644
--- a/src/core/dbus.c
+++ b/src/core/dbus.c
@@ -19,29 +19,34 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/epoll.h>
#include <errno.h>
+#include <sys/epoll.h>
#include <unistd.h>
#include "sd-bus.h"
-#include "log.h"
-#include "strv.h"
-#include "mkdir.h"
-#include "missing.h"
-#include "dbus-unit.h"
-#include "dbus-job.h"
-#include "dbus-manager.h"
+
+#include "alloc-util.h"
+#include "bus-common-errors.h"
+#include "bus-error.h"
+#include "bus-internal.h"
+#include "bus-util.h"
+#include "dbus-cgroup.h"
#include "dbus-execute.h"
+#include "dbus-job.h"
#include "dbus-kill.h"
-#include "dbus-cgroup.h"
-#include "special.h"
+#include "dbus-manager.h"
+#include "dbus-unit.h"
#include "dbus.h"
-#include "bus-util.h"
-#include "bus-error.h"
-#include "bus-common-errors.h"
-#include "strxcpyx.h"
-#include "bus-internal.h"
+#include "fd-util.h"
+#include "log.h"
+#include "missing.h"
+#include "mkdir.h"
#include "selinux-access.h"
+#include "special.h"
+#include "string-util.h"
+#include "strv.h"
+#include "strxcpyx.h"
+#include "user-util.h"
#define CONNECTIONS_MAX 4096
@@ -172,7 +177,7 @@ static int signal_activation_request(sd_bus_message *message, void *userdata, sd
goto failed;
}
- r = manager_add_job(m, JOB_START, u, JOB_REPLACE, true, &error, NULL);
+ r = manager_add_job(m, JOB_START, u, JOB_REPLACE, &error, NULL);
if (r < 0)
goto failed;
@@ -777,9 +782,9 @@ static int bus_setup_api(Manager *m, sd_bus *bus) {
return r;
HASHMAP_FOREACH_KEY(u, name, m->watch_bus, i) {
- r = unit_install_bus_match(bus, u, name);
+ r = unit_install_bus_match(u, bus, name);
if (r < 0)
- log_error_errno(r, "Failed to subscribe to NameOwnerChanged signal: %m");
+ log_error_errno(r, "Failed to subscribe to NameOwnerChanged signal for '%s': %m", name);
}
r = sd_bus_add_match(
diff --git a/src/core/device.c b/src/core/device.c
index a819ab8d4e..bcd4d1146b 100644
--- a/src/core/device.c
+++ b/src/core/device.c
@@ -21,16 +21,21 @@
#include <errno.h>
#include <sys/epoll.h>
-#include <libudev.h>
-#include "log.h"
-#include "unit-name.h"
+#include "libudev.h"
+
+#include "alloc-util.h"
#include "dbus-device.h"
+#include "device.h"
+#include "log.h"
+#include "parse-util.h"
#include "path-util.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "swap.h"
#include "udev-util.h"
+#include "unit-name.h"
#include "unit.h"
-#include "swap.h"
-#include "device.h"
static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
[DEVICE_DEAD] = UNIT_INACTIVE,
@@ -112,7 +117,6 @@ static void device_init(Unit *u) {
u->job_timeout = u->manager->default_timeout_start_usec;
u->ignore_on_isolate = true;
- u->ignore_on_snapshot = true;
}
static void device_done(Unit *u) {
@@ -597,7 +601,7 @@ static void device_shutdown(Manager *m) {
m->devices_by_sysfs = hashmap_free(m->devices_by_sysfs);
}
-static int device_enumerate(Manager *m) {
+static void device_enumerate(Manager *m) {
_cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
struct udev_list_entry *item = NULL, *first = NULL;
int r;
@@ -607,7 +611,7 @@ static int device_enumerate(Manager *m) {
if (!m->udev_monitor) {
m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
if (!m->udev_monitor) {
- r = -ENOMEM;
+ log_oom();
goto fail;
}
@@ -617,37 +621,49 @@ static int device_enumerate(Manager *m) {
(void) udev_monitor_set_receive_buffer_size(m->udev_monitor, 128*1024*1024);
r = udev_monitor_filter_add_match_tag(m->udev_monitor, "systemd");
- if (r < 0)
+ if (r < 0) {
+ log_error_errno(r, "Failed to add udev tag match: %m");
goto fail;
+ }
r = udev_monitor_enable_receiving(m->udev_monitor);
- if (r < 0)
+ if (r < 0) {
+ log_error_errno(r, "Failed to enable udev event reception: %m");
goto fail;
+ }
r = sd_event_add_io(m->event, &m->udev_event_source, udev_monitor_get_fd(m->udev_monitor), EPOLLIN, device_dispatch_io, m);
- if (r < 0)
+ if (r < 0) {
+ log_error_errno(r, "Failed to watch udev file descriptor: %m");
goto fail;
+ }
(void) sd_event_source_set_description(m->udev_event_source, "device");
}
e = udev_enumerate_new(m->udev);
if (!e) {
- r = -ENOMEM;
+ log_oom();
goto fail;
}
r = udev_enumerate_add_match_tag(e, "systemd");
- if (r < 0)
+ if (r < 0) {
+ log_error_errno(r, "Failed to create udev tag enumeration: %m");
goto fail;
+ }
r = udev_enumerate_add_match_is_initialized(e);
- if (r < 0)
+ if (r < 0) {
+ log_error_errno(r, "Failed to install initialization match into enumeration: %m");
goto fail;
+ }
r = udev_enumerate_scan_devices(e);
- if (r < 0)
+ if (r < 0) {
+ log_error_errno(r, "Failed to enumerate devices: %m");
goto fail;
+ }
first = udev_enumerate_get_list_entry(e);
udev_list_entry_foreach(item, first) {
@@ -670,13 +686,10 @@ static int device_enumerate(Manager *m) {
device_update_found_by_sysfs(m, sysfs, true, DEVICE_FOUND_UDEV, false);
}
- return 0;
+ return;
fail:
- log_error_errno(r, "Failed to enumerate devices: %m");
-
device_shutdown(m);
- return r;
}
static int device_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
diff --git a/src/core/execute.c b/src/core/execute.c
index 137a176c18..07979bf8b3 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -21,18 +21,18 @@
#include <errno.h>
#include <fcntl.h>
-#include <unistd.h>
-#include <string.h>
+#include <glob.h>
+#include <grp.h>
+#include <poll.h>
#include <signal.h>
-#include <sys/socket.h>
-#include <sys/un.h>
+#include <string.h>
+#include <sys/personality.h>
#include <sys/prctl.h>
+#include <sys/socket.h>
#include <sys/stat.h>
-#include <grp.h>
-#include <poll.h>
-#include <glob.h>
+#include <sys/un.h>
+#include <unistd.h>
#include <utmpx.h>
-#include <sys/personality.h>
#ifdef HAVE_PAM
#include <security/pam_appl.h>
@@ -50,47 +50,56 @@
#include <sys/apparmor.h>
#endif
-#include "barrier.h"
#include "sd-messages.h"
-#include "rm-rf.h"
-#include "strv.h"
-#include "macro.h"
-#include "capability.h"
-#include "util.h"
-#include "log.h"
-#include "ioprio.h"
-#include "securebits.h"
-#include "namespace.h"
-#include "exit-status.h"
-#include "missing.h"
-#include "utmp-wtmp.h"
-#include "def.h"
-#include "path-util.h"
-#include "env-util.h"
-#include "fileio.h"
-#include "unit.h"
-#include "async.h"
-#include "selinux-util.h"
-#include "errno-list.h"
+
#include "af-list.h"
-#include "mkdir.h"
-#include "smack-util.h"
+#include "alloc-util.h"
+#ifdef HAVE_APPARMOR
+#include "apparmor-util.h"
+#endif
+#include "async.h"
+#include "barrier.h"
#include "bus-endpoint.h"
#include "cap-list.h"
+#include "capability-util.h"
+#include "def.h"
+#include "env-util.h"
+#include "errno-list.h"
+#include "execute.h"
+#include "exit-status.h"
+#include "fd-util.h"
+#include "fileio.h"
#include "formats-util.h"
+#include "fs-util.h"
+#include "glob-util.h"
+#include "io-util.h"
+#include "ioprio.h"
+#include "log.h"
+#include "macro.h"
+#include "missing.h"
+#include "mkdir.h"
+#include "namespace.h"
+#include "parse-util.h"
+#include "path-util.h"
#include "process-util.h"
-#include "terminal-util.h"
-#include "signal-util.h"
-
-#ifdef HAVE_APPARMOR
-#include "apparmor-util.h"
-#endif
-
+#include "rlimit-util.h"
+#include "rm-rf.h"
#ifdef HAVE_SECCOMP
#include "seccomp-util.h"
#endif
-
-#include "execute.h"
+#include "securebits.h"
+#include "selinux-util.h"
+#include "signal-util.h"
+#include "smack-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "syslog-util.h"
+#include "terminal-util.h"
+#include "unit.h"
+#include "user-util.h"
+#include "util.h"
+#include "utmp-wtmp.h"
#define IDLE_TIMEOUT_USEC (5*USEC_PER_SEC)
#define IDLE_TIMEOUT2_USEC (1*USEC_PER_SEC)
@@ -358,12 +367,28 @@ static int fixup_output(ExecOutput std_output, int socket_fd) {
return std_output;
}
-static int setup_input(const ExecContext *context, int socket_fd, bool apply_tty_stdin) {
+static int setup_input(
+ const ExecContext *context,
+ const ExecParameters *params,
+ int socket_fd) {
+
ExecInput i;
assert(context);
+ assert(params);
+
+ if (params->stdin_fd >= 0) {
+ if (dup2(params->stdin_fd, STDIN_FILENO) < 0)
+ return -errno;
+
+ /* Try to make this the controlling tty, if it is a tty, and reset it */
+ (void) ioctl(STDIN_FILENO, TIOCSCTTY, context->std_input == EXEC_INPUT_TTY_FORCE);
+ (void) reset_terminal_fd(STDIN_FILENO, true);
+
+ return STDIN_FILENO;
+ }
- i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
+ i = fixup_input(context->std_input, socket_fd, params->apply_tty_stdin);
switch (i) {
@@ -400,16 +425,40 @@ static int setup_input(const ExecContext *context, int socket_fd, bool apply_tty
}
}
-static int setup_output(Unit *unit, const ExecContext *context, int fileno, int socket_fd, const char *ident, bool apply_tty_stdin, uid_t uid, gid_t gid) {
+static int setup_output(
+ Unit *unit,
+ const ExecContext *context,
+ const ExecParameters *params,
+ int fileno,
+ int socket_fd,
+ const char *ident,
+ uid_t uid, gid_t gid) {
+
ExecOutput o;
ExecInput i;
int r;
assert(unit);
assert(context);
+ assert(params);
assert(ident);
- i = fixup_input(context->std_input, socket_fd, apply_tty_stdin);
+ if (fileno == STDOUT_FILENO && params->stdout_fd >= 0) {
+
+ if (dup2(params->stdout_fd, STDOUT_FILENO) < 0)
+ return -errno;
+
+ return STDOUT_FILENO;
+ }
+
+ if (fileno == STDERR_FILENO && params->stderr_fd >= 0) {
+ if (dup2(params->stderr_fd, STDERR_FILENO) < 0)
+ return -errno;
+
+ return STDERR_FILENO;
+ }
+
+ i = fixup_input(context->std_input, socket_fd, params->apply_tty_stdin);
o = fixup_output(context->std_output, socket_fd);
if (fileno == STDERR_FILENO) {
@@ -502,9 +551,9 @@ static int chown_terminal(int fd, uid_t uid) {
return 0;
}
-static int setup_confirm_stdio(int *_saved_stdin,
- int *_saved_stdout) {
- int fd = -1, saved_stdin, saved_stdout = -1, r;
+static int setup_confirm_stdio(int *_saved_stdin, int *_saved_stdout) {
+ _cleanup_close_ int fd = -1, saved_stdin = -1, saved_stdout = -1;
+ int r;
assert(_saved_stdin);
assert(_saved_stdout);
@@ -514,10 +563,8 @@ static int setup_confirm_stdio(int *_saved_stdin,
return -errno;
saved_stdout = fcntl(STDOUT_FILENO, F_DUPFD, 3);
- if (saved_stdout < 0) {
- r = errno;
- goto fail;
- }
+ if (saved_stdout < 0)
+ return -errno;
fd = acquire_terminal(
"/dev/console",
@@ -525,39 +572,33 @@ static int setup_confirm_stdio(int *_saved_stdin,
false,
false,
DEFAULT_CONFIRM_USEC);
- if (fd < 0) {
- r = fd;
- goto fail;
- }
+ if (fd < 0)
+ return fd;
r = chown_terminal(fd, getuid());
if (r < 0)
- goto fail;
+ return r;
- if (dup2(fd, STDIN_FILENO) < 0) {
- r = -errno;
- goto fail;
- }
+ r = reset_terminal_fd(fd, true);
+ if (r < 0)
+ return r;
- if (dup2(fd, STDOUT_FILENO) < 0) {
- r = -errno;
- goto fail;
- }
+ if (dup2(fd, STDIN_FILENO) < 0)
+ return -errno;
+
+ if (dup2(fd, STDOUT_FILENO) < 0)
+ return -errno;
if (fd >= 2)
safe_close(fd);
+ fd = -1;
*_saved_stdin = saved_stdin;
*_saved_stdout = saved_stdout;
- return 0;
-
-fail:
- safe_close(saved_stdout);
- safe_close(saved_stdin);
- safe_close(fd);
+ saved_stdin = saved_stdout = -1;
- return r;
+ return 0;
}
_printf_(1, 2) static int write_confirm_message(const char *format, ...) {
@@ -577,9 +618,7 @@ _printf_(1, 2) static int write_confirm_message(const char *format, ...) {
return 0;
}
-static int restore_confirm_stdio(int *saved_stdin,
- int *saved_stdout) {
-
+static int restore_confirm_stdio(int *saved_stdin, int *saved_stdout) {
int r = 0;
assert(saved_stdin);
@@ -595,8 +634,8 @@ static int restore_confirm_stdio(int *saved_stdin,
if (dup2(*saved_stdout, STDOUT_FILENO) < 0)
r = -errno;
- safe_close(*saved_stdin);
- safe_close(*saved_stdout);
+ *saved_stdin = safe_close(*saved_stdin);
+ *saved_stdout = safe_close(*saved_stdout);
return r;
}
@@ -1198,6 +1237,7 @@ static void do_idle_pipe_dance(int idle_pipe[4]) {
static int build_environment(
const ExecContext *c,
unsigned n_fds,
+ char ** fd_names,
usec_t watchdog_usec,
const char *home,
const char *username,
@@ -1211,11 +1251,13 @@ static int build_environment(
assert(c);
assert(ret);
- our_env = new0(char*, 10);
+ our_env = new0(char*, 11);
if (!our_env)
return -ENOMEM;
if (n_fds > 0) {
+ _cleanup_free_ char *joined = NULL;
+
if (asprintf(&x, "LISTEN_PID="PID_FMT, getpid()) < 0)
return -ENOMEM;
our_env[n_env++] = x;
@@ -1223,6 +1265,15 @@ static int build_environment(
if (asprintf(&x, "LISTEN_FDS=%u", n_fds) < 0)
return -ENOMEM;
our_env[n_env++] = x;
+
+ joined = strv_join(fd_names, ":");
+ if (!joined)
+ return -ENOMEM;
+
+ x = strjoin("LISTEN_FDNAMES=", joined, NULL);
+ if (!x)
+ return -ENOMEM;
+ our_env[n_env++] = x;
}
if (watchdog_usec > 0) {
@@ -1273,7 +1324,7 @@ static int build_environment(
}
our_env[n_env++] = NULL;
- assert(n_env <= 10);
+ assert(n_env <= 11);
*ret = our_env;
our_env = NULL;
@@ -1281,6 +1332,34 @@ static int build_environment(
return 0;
}
+static int build_pass_environment(const ExecContext *c, char ***ret) {
+ _cleanup_strv_free_ char **pass_env = NULL;
+ size_t n_env = 0, n_bufsize = 0;
+ char **i;
+
+ STRV_FOREACH(i, c->pass_environment) {
+ _cleanup_free_ char *x = NULL;
+ char *v;
+
+ v = getenv(*i);
+ if (!v)
+ continue;
+ x = strjoin(*i, "=", v, NULL);
+ if (!x)
+ return -ENOMEM;
+ if (!GREEDY_REALLOC(pass_env, n_bufsize, n_env + 2))
+ return -ENOMEM;
+ pass_env[n_env++] = x;
+ pass_env[n_env] = NULL;
+ x = NULL;
+ }
+
+ *ret = pass_env;
+ pass_env = NULL;
+
+ return 0;
+}
+
static bool exec_needs_mount_namespace(
const ExecContext *context,
const ExecParameters *params,
@@ -1311,6 +1390,44 @@ static bool exec_needs_mount_namespace(
return false;
}
+static int close_remaining_fds(
+ const ExecParameters *params,
+ ExecRuntime *runtime,
+ int socket_fd,
+ int *fds, unsigned n_fds) {
+
+ unsigned n_dont_close = 0;
+ int dont_close[n_fds + 7];
+
+ assert(params);
+
+ if (params->stdin_fd >= 0)
+ dont_close[n_dont_close++] = params->stdin_fd;
+ if (params->stdout_fd >= 0)
+ dont_close[n_dont_close++] = params->stdout_fd;
+ if (params->stderr_fd >= 0)
+ dont_close[n_dont_close++] = params->stderr_fd;
+
+ if (socket_fd >= 0)
+ dont_close[n_dont_close++] = socket_fd;
+ if (n_fds > 0) {
+ memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds);
+ n_dont_close += n_fds;
+ }
+
+ if (params->bus_endpoint_fd >= 0)
+ dont_close[n_dont_close++] = params->bus_endpoint_fd;
+
+ if (runtime) {
+ if (runtime->netns_storage_socket[0] >= 0)
+ dont_close[n_dont_close++] = runtime->netns_storage_socket[0];
+ if (runtime->netns_storage_socket[1] >= 0)
+ dont_close[n_dont_close++] = runtime->netns_storage_socket[1];
+ }
+
+ return close_all_fds(dont_close, n_dont_close);
+}
+
static int exec_child(
Unit *unit,
ExecCommand *command,
@@ -1323,11 +1440,9 @@ static int exec_child(
char **files_env,
int *exit_status) {
- _cleanup_strv_free_ char **our_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL;
+ _cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL;
_cleanup_free_ char *mac_selinux_context_net = NULL;
const char *username = NULL, *home = NULL, *shell = NULL, *wd;
- unsigned n_dont_close = 0;
- int dont_close[n_fds + 4];
uid_t uid = UID_INVALID;
gid_t gid = GID_INVALID;
int i, r;
@@ -1367,22 +1482,7 @@ static int exec_child(
log_forget_fds();
- if (socket_fd >= 0)
- dont_close[n_dont_close++] = socket_fd;
- if (n_fds > 0) {
- memcpy(dont_close + n_dont_close, fds, sizeof(int) * n_fds);
- n_dont_close += n_fds;
- }
- if (params->bus_endpoint_fd >= 0)
- dont_close[n_dont_close++] = params->bus_endpoint_fd;
- if (runtime) {
- if (runtime->netns_storage_socket[0] >= 0)
- dont_close[n_dont_close++] = runtime->netns_storage_socket[0];
- if (runtime->netns_storage_socket[1] >= 0)
- dont_close[n_dont_close++] = runtime->netns_storage_socket[1];
- }
-
- r = close_all_fds(dont_close, n_dont_close);
+ r = close_remaining_fds(params, runtime, socket_fd, fds, n_fds);
if (r < 0) {
*exit_status = EXIT_FDS;
return r;
@@ -1438,21 +1538,21 @@ static int exec_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);
+ (void) fd_nonblock(socket_fd, false);
- r = setup_input(context, socket_fd, params->apply_tty_stdin);
+ r = setup_input(context, params, socket_fd);
if (r < 0) {
*exit_status = EXIT_STDIN;
return r;
}
- r = setup_output(unit, context, STDOUT_FILENO, socket_fd, basename(command->path), params->apply_tty_stdin, uid, gid);
+ r = setup_output(unit, context, params, STDOUT_FILENO, socket_fd, basename(command->path), uid, gid);
if (r < 0) {
*exit_status = EXIT_STDOUT;
return r;
}
- r = setup_output(unit, context, STDERR_FILENO, socket_fd, basename(command->path), params->apply_tty_stdin, uid, gid);
+ r = setup_output(unit, context, params, STDERR_FILENO, socket_fd, basename(command->path), uid, gid);
if (r < 0) {
*exit_status = EXIT_STDERR;
return r;
@@ -1850,15 +1950,22 @@ static int exec_child(
#endif
}
- r = build_environment(context, n_fds, params->watchdog_usec, home, username, shell, &our_env);
+ r = build_environment(context, n_fds, params->fd_names, params->watchdog_usec, home, username, shell, &our_env);
+ if (r < 0) {
+ *exit_status = EXIT_MEMORY;
+ return r;
+ }
+
+ r = build_pass_environment(context, &pass_env);
if (r < 0) {
*exit_status = EXIT_MEMORY;
return r;
}
- final_env = strv_env_merge(5,
+ final_env = strv_env_merge(6,
params->environment,
our_env,
+ pass_env,
context->environment,
files_env,
pam_env,
@@ -2016,6 +2123,7 @@ void exec_context_done(ExecContext *c) {
c->environment = strv_free(c->environment);
c->environment_files = strv_free(c->environment_files);
+ c->pass_environment = strv_free(c->pass_environment);
for (l = 0; l < ELEMENTSOF(c->rlimit); l++)
c->rlimit[l] = mfree(c->rlimit[l]);
@@ -2250,7 +2358,7 @@ static void strv_fprintf(FILE *f, char **l) {
}
void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
- char **e;
+ char **e, **d;
unsigned i;
assert(c);
@@ -2286,6 +2394,14 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
STRV_FOREACH(e, c->environment_files)
fprintf(f, "%sEnvironmentFile: %s\n", prefix, *e);
+ STRV_FOREACH(e, c->pass_environment)
+ fprintf(f, "%sPassEnvironment: %s\n", prefix, *e);
+
+ fprintf(f, "%sRuntimeDirectoryMode: %04o\n", prefix, c->runtime_directory_mode);
+
+ STRV_FOREACH(d, c->runtime_directory)
+ fprintf(f, "%sRuntimeDirectory: %s\n", prefix, *d);
+
if (c->nice_set)
fprintf(f,
"%sNice: %i\n",
@@ -2712,7 +2828,7 @@ int exec_command_append(ExecCommand *c, const char *path, ...) {
if (!l)
return -ENOMEM;
- r = strv_extend_strv(&c->argv, l);
+ r = strv_extend_strv(&c->argv, l, false);
if (r < 0)
return r;
diff --git a/src/core/execute.h b/src/core/execute.h
index 2c93044748..be5be9f531 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -27,16 +27,16 @@ typedef struct ExecContext ExecContext;
typedef struct ExecRuntime ExecRuntime;
typedef struct ExecParameters ExecParameters;
-#include <sys/capability.h>
+#include <sched.h>
#include <stdbool.h>
#include <stdio.h>
-#include <sched.h>
+#include <sys/capability.h>
-#include "list.h"
+#include "bus-endpoint.h"
#include "fdset.h"
+#include "list.h"
#include "missing.h"
#include "namespace.h"
-#include "bus-endpoint.h"
typedef enum ExecUtmpMode {
EXEC_UTMP_INIT,
@@ -99,6 +99,7 @@ struct ExecRuntime {
struct ExecContext {
char **environment;
char **environment_files;
+ char **pass_environment;
struct rlimit *rlimit[_RLIMIT_MAX];
char *working_directory, *root_directory;
@@ -203,26 +204,40 @@ struct ExecContext {
BusEndpoint *bus_endpoint;
};
-#include "cgroup.h"
#include "cgroup-util.h"
+#include "cgroup.h"
struct ExecParameters {
char **argv;
- int *fds; unsigned n_fds;
char **environment;
- bool apply_permissions;
- bool apply_chroot;
- bool apply_tty_stdin;
- bool confirm_spawn;
- bool selinux_context_net;
+
+ int *fds;
+ char **fd_names;
+ unsigned n_fds;
+
+ bool apply_permissions:1;
+ bool apply_chroot:1;
+ bool apply_tty_stdin:1;
+
+ bool confirm_spawn:1;
+ bool selinux_context_net:1;
+
+ bool cgroup_delegate:1;
CGroupMask cgroup_supported;
const char *cgroup_path;
- bool cgroup_delegate;
+
const char *runtime_prefix;
+
usec_t watchdog_usec;
+
int *idle_pipe;
+
char *bus_endpoint_path;
int bus_endpoint_fd;
+
+ int stdin_fd;
+ int stdout_fd;
+ int stderr_fd;
};
int exec_spawn(Unit *unit,
diff --git a/src/core/failure-action.c b/src/core/failure-action.c
index 3412accf3e..f67fb05af0 100644
--- a/src/core/failure-action.c
+++ b/src/core/failure-action.c
@@ -23,10 +23,11 @@
#include <sys/reboot.h>
#include <linux/reboot.h>
-#include "bus-util.h"
#include "bus-error.h"
-#include "special.h"
+#include "bus-util.h"
#include "failure-action.h"
+#include "special.h"
+#include "string-table.h"
#include "terminal-util.h"
static void log_and_status(Manager *m, const char *message) {
@@ -41,8 +42,6 @@ int failure_action(
FailureAction action,
const char *reboot_arg) {
- int r;
-
assert(m);
assert(action >= 0);
assert(action < _FAILURE_ACTION_MAX);
@@ -61,18 +60,13 @@ int failure_action(
switch (action) {
- case FAILURE_ACTION_REBOOT: {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-
+ case FAILURE_ACTION_REBOOT:
log_and_status(m, "Rebooting as result of failure.");
update_reboot_param_file(reboot_arg);
- r = manager_add_job_by_name(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE, true, &error, NULL);
- if (r < 0)
- log_error("Failed to reboot: %s.", bus_error_message(&error, r));
+ (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_REBOOT_TARGET, JOB_REPLACE, NULL);
break;
- }
case FAILURE_ACTION_REBOOT_FORCE:
log_and_status(m, "Forcibly rebooting as result of failure.");
@@ -95,17 +89,10 @@ int failure_action(
reboot(RB_AUTOBOOT);
break;
- case FAILURE_ACTION_POWEROFF: {
- _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
-
+ case FAILURE_ACTION_POWEROFF:
log_and_status(m, "Powering off as result of failure.");
-
- r = manager_add_job_by_name(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE, true, &error, NULL);
- if (r < 0)
- log_error("Failed to poweroff: %s.", bus_error_message(&error, r));
-
+ (void) manager_add_job_by_name_and_warn(m, JOB_START, SPECIAL_POWEROFF_TARGET, JOB_REPLACE, NULL);
break;
- }
case FAILURE_ACTION_POWEROFF_FORCE:
log_and_status(m, "Forcibly powering off as result of failure.");
diff --git a/src/core/hostname-setup.c b/src/core/hostname-setup.c
index 932ddbf95a..d92a9a764f 100644
--- a/src/core/hostname-setup.c
+++ b/src/core/hostname-setup.c
@@ -19,16 +19,18 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
#include <errno.h>
+#include <stdio.h>
#include <stdlib.h>
-#include "macro.h"
-#include "util.h"
-#include "log.h"
+#include "alloc-util.h"
#include "fileio.h"
-#include "hostname-util.h"
#include "hostname-setup.h"
+#include "hostname-util.h"
+#include "log.h"
+#include "macro.h"
+#include "string-util.h"
+#include "util.h"
int hostname_setup(void) {
int r;
@@ -59,8 +61,9 @@ int hostname_setup(void) {
hn = "localhost";
}
- if (sethostname_idempotent(hn) < 0)
- return log_warning_errno(errno, "Failed to set hostname to <%s>: %m", hn);
+ r = sethostname_idempotent(hn);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to set hostname to <%s>: %m", hn);
log_info("Set hostname to <%s>.", hn);
return 0;
diff --git a/src/core/ima-setup.c b/src/core/ima-setup.c
index 42a3e97459..4f42ae6f31 100644
--- a/src/core/ima-setup.c
+++ b/src/core/ima-setup.c
@@ -21,12 +21,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <errno.h>
+#include <unistd.h>
+#include "fd-util.h"
+#include "fileio.h"
#include "ima-setup.h"
-#include "util.h"
#include "log.h"
+#include "util.h"
#define IMA_SECFS_DIR "/sys/kernel/security/ima"
#define IMA_SECFS_POLICY IMA_SECFS_DIR "/policy"
diff --git a/src/core/job.c b/src/core/job.c
index 558d8d2d52..9654590635 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -23,17 +23,24 @@
#include "sd-id128.h"
#include "sd-messages.h"
-#include "set.h"
-#include "unit.h"
-#include "macro.h"
-#include "strv.h"
-#include "log.h"
-#include "dbus-job.h"
-#include "special.h"
+
+#include "alloc-util.h"
#include "async.h"
-#include "virt.h"
+#include "dbus-job.h"
#include "dbus.h"
+#include "escape.h"
+#include "job.h"
+#include "log.h"
+#include "macro.h"
+#include "parse-util.h"
+#include "set.h"
+#include "special.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
#include "terminal-util.h"
+#include "unit.h"
+#include "virt.h"
Job* job_new_raw(Unit *unit) {
Job *j;
@@ -168,7 +175,6 @@ static void job_merge_into_installed(Job *j, Job *other) {
else
assert(other->type == JOB_NOP);
- j->override = j->override || other->override;
j->irreversible = j->irreversible || other->irreversible;
j->ignore_order = j->ignore_order || other->ignore_order;
}
@@ -300,12 +306,10 @@ void job_dump(Job *j, FILE*f, const char *prefix) {
"%s-> Job %u:\n"
"%s\tAction: %s -> %s\n"
"%s\tState: %s\n"
- "%s\tForced: %s\n"
"%s\tIrreversible: %s\n",
prefix, j->id,
prefix, j->unit->id, job_type_to_string(j->type),
prefix, job_state_to_string(j->state),
- prefix, yes_no(j->override),
prefix, yes_no(j->irreversible));
}
@@ -496,17 +500,26 @@ static void job_change_type(Job *j, JobType newtype) {
}
static int job_perform_on_unit(Job **j) {
- /* While we execute this operation the job might go away (for
- * example: because it finishes immediately or is replaced by a new,
- * conflicting job.) To make sure we don't access a freed job later on
- * we store the id here, so that we can verify the job is still
- * valid. */
- Manager *m = (*j)->manager;
- Unit *u = (*j)->unit;
- JobType t = (*j)->type;
- uint32_t id = (*j)->id;
+ uint32_t id;
+ Manager *m;
+ JobType t;
+ Unit *u;
int r;
+ /* While we execute this operation the job might go away (for
+ * example: because it finishes immediately or is replaced by
+ * a new, conflicting job.) To make sure we don't access a
+ * freed job later on we store the id here, so that we can
+ * verify the job is still valid. */
+
+ assert(j);
+ assert(*j);
+
+ m = (*j)->manager;
+ u = (*j)->unit;
+ t = (*j)->type;
+ id = (*j)->id;
+
switch (t) {
case JOB_START:
r = unit_start(u);
@@ -514,6 +527,7 @@ static int job_perform_on_unit(Job **j) {
case JOB_RESTART:
t = JOB_STOP;
+ /* fall through */
case JOB_STOP:
r = unit_stop(u);
break;
@@ -613,8 +627,7 @@ int job_run_and_invalidate(Job *j) {
}
_pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobResult result) {
- const char *format;
- const UnitStatusMessageFormats *format_table;
+
static const char *const generic_finished_start_job[_JOB_RESULT_MAX] = {
[JOB_DONE] = "Started %s.",
[JOB_TIMEOUT] = "Timed out starting %s.",
@@ -640,11 +653,14 @@ _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobR
[JOB_SKIPPED] = "%s is not active.",
};
+ const UnitStatusMessageFormats *format_table;
+ const char *format;
+
assert(u);
assert(t >= 0);
assert(t < _JOB_TYPE_MAX);
- if (t == JOB_START || t == JOB_STOP || t == JOB_RESTART) {
+ if (IN_SET(t, JOB_START, JOB_STOP, JOB_RESTART)) {
format_table = &UNIT_VTABLE(u)->status_message_formats;
if (format_table) {
format = t == JOB_START ? format_table->finished_start_job[result] :
@@ -668,7 +684,6 @@ _pure_ static const char *job_get_status_message_format(Unit *u, JobType t, JobR
}
static void job_print_status_message(Unit *u, JobType t, JobResult result) {
- const char *format;
static const char* const job_result_status_table[_JOB_RESULT_MAX] = {
[JOB_DONE] = ANSI_GREEN " OK " ANSI_NORMAL,
[JOB_TIMEOUT] = ANSI_HIGHLIGHT_RED " TIME " ANSI_NORMAL,
@@ -679,10 +694,16 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
[JOB_UNSUPPORTED] = ANSI_HIGHLIGHT_YELLOW "UNSUPP" ANSI_NORMAL,
};
+ const char *format;
+
assert(u);
assert(t >= 0);
assert(t < _JOB_TYPE_MAX);
+ /* Reload status messages have traditionally not been printed to console. */
+ if (t == JOB_RELOAD)
+ return;
+
format = job_get_status_message_format(u, t, result);
if (!format)
return;
@@ -695,10 +716,10 @@ static void job_print_status_message(Unit *u, JobType t, JobResult result) {
REENABLE_WARNING;
if (t == JOB_START && result == JOB_FAILED) {
- _cleanup_free_ char *quoted = shell_maybe_quote(u->id);
+ _cleanup_free_ char *quoted;
- manager_status_printf(u->manager, STATUS_TYPE_NORMAL, NULL,
- "See 'systemctl status %s' for details.", strna(quoted));
+ quoted = shell_maybe_quote(u->id);
+ manager_status_printf(u->manager, STATUS_TYPE_NORMAL, NULL, "See 'systemctl status %s' for details.", strna(quoted));
}
}
@@ -736,13 +757,22 @@ static void job_log_status_message(Unit *u, JobType t, JobResult result) {
snprintf(buf, sizeof(buf), format, unit_description(u));
REENABLE_WARNING;
- if (t == JOB_START)
+ switch (t) {
+
+ case JOB_START:
mid = result == JOB_DONE ? SD_MESSAGE_UNIT_STARTED : SD_MESSAGE_UNIT_FAILED;
- else if (t == JOB_STOP || t == JOB_RESTART)
- mid = SD_MESSAGE_UNIT_STOPPED;
- else if (t == JOB_RELOAD)
+ break;
+
+ case JOB_RELOAD:
mid = SD_MESSAGE_UNIT_RELOADED;
- else {
+ break;
+
+ case JOB_STOP:
+ case JOB_RESTART:
+ mid = SD_MESSAGE_UNIT_STOPPED;
+ break;
+
+ default:
log_struct(job_result_log_level[result],
LOG_UNIT_ID(u),
LOG_MESSAGE("%s", buf),
@@ -766,10 +796,7 @@ static void job_emit_status_message(Unit *u, JobType t, JobResult result) {
return;
job_log_status_message(u, t, result);
-
- /* Reload status messages have traditionally not been printed to console. */
- if (t != JOB_RELOAD)
- job_print_status_message(u, t, result);
+ job_print_status_message(u, t, result);
}
static void job_fail_dependencies(Unit *u, UnitDependency d) {
@@ -834,8 +861,6 @@ int job_finish_and_invalidate(Job *j, JobResult result, bool recursive) {
job_fail_dependencies(u, UNIT_REQUIRED_BY);
job_fail_dependencies(u, UNIT_REQUISITE_OF);
job_fail_dependencies(u, UNIT_BOUND_BY);
- job_fail_dependencies(u, UNIT_REQUIRED_BY_OVERRIDABLE);
- job_fail_dependencies(u, UNIT_REQUISITE_OF_OVERRIDABLE);
} else if (t == JOB_STOP)
job_fail_dependencies(u, UNIT_CONFLICTED_BY);
}
@@ -960,7 +985,6 @@ int job_serialize(Job *j, FILE *f, FDSet *fds) {
fprintf(f, "job-id=%u\n", j->id);
fprintf(f, "job-type=%s\n", job_type_to_string(j->type));
fprintf(f, "job-state=%s\n", job_state_to_string(j->state));
- fprintf(f, "job-override=%s\n", yes_no(j->override));
fprintf(f, "job-irreversible=%s\n", yes_no(j->irreversible));
fprintf(f, "job-sent-dbus-new-signal=%s\n", yes_no(j->sent_dbus_new_signal));
fprintf(f, "job-ignore-order=%s\n", yes_no(j->ignore_order));
@@ -1028,15 +1052,6 @@ int job_deserialize(Job *j, FILE *f, FDSet *fds) {
else
job_set_state(j, s);
- } else if (streq(l, "job-override")) {
- int b;
-
- b = parse_boolean(v);
- if (b < 0)
- log_debug("Failed to parse job override flag %s", v);
- else
- j->override = j->override || b;
-
} else if (streq(l, "job-irreversible")) {
int b;
diff --git a/src/core/job.h b/src/core/job.h
index 1d1b10f1d3..118b24e5b7 100644
--- a/src/core/job.h
+++ b/src/core/job.h
@@ -23,6 +23,11 @@
#include <stdbool.h>
+#include "sd-event.h"
+
+#include "list.h"
+#include "unit-name.h"
+
typedef struct Job Job;
typedef struct JobDependency JobDependency;
typedef enum JobType JobType;
@@ -105,9 +110,7 @@ enum JobResult {
_JOB_RESULT_INVALID = -1
};
-#include "sd-event.h"
#include "unit.h"
-#include "list.h"
struct JobDependency {
/* Encodes that the 'subject' job needs the 'object' job in
@@ -160,7 +163,6 @@ struct Job {
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;
diff --git a/src/core/kill.c b/src/core/kill.c
index bddfa4460f..1466d5ce64 100644
--- a/src/core/kill.c
+++ b/src/core/kill.c
@@ -19,9 +19,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "util.h"
-#include "signal-util.h"
#include "kill.h"
+#include "signal-util.h"
+#include "string-table.h"
+#include "util.h"
void kill_context_init(KillContext *c) {
assert(c);
diff --git a/src/core/killall.c b/src/core/killall.c
index ee5d388560..77f145b4d1 100644
--- a/src/core/killall.c
+++ b/src/core/killall.c
@@ -19,17 +19,21 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/wait.h>
-#include <signal.h>
#include <errno.h>
+#include <signal.h>
+#include <sys/wait.h>
#include <unistd.h>
-#include "util.h"
-#include "killall.h"
-#include "set.h"
+#include "alloc-util.h"
+#include "fd-util.h"
#include "formats-util.h"
+#include "killall.h"
+#include "parse-util.h"
#include "process-util.h"
+#include "set.h"
+#include "string-util.h"
#include "terminal-util.h"
+#include "util.h"
#define TIMEOUT_USEC (10 * USEC_PER_SEC)
diff --git a/src/core/kmod-setup.c b/src/core/kmod-setup.c
index 2068ffd69b..a6ab8cf4b3 100644
--- a/src/core/kmod-setup.c
+++ b/src/core/kmod-setup.c
@@ -19,17 +19,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <string.h>
+#include <unistd.h>
#ifdef HAVE_KMOD
#include <libkmod.h>
#endif
-#include "macro.h"
-#include "capability.h"
#include "bus-util.h"
+#include "capability-util.h"
#include "kmod-setup.h"
+#include "macro.h"
#ifdef HAVE_KMOD
static void systemd_kmod_log(
diff --git a/src/core/load-dropin.c b/src/core/load-dropin.c
index 11566af51b..3fa66f91aa 100644
--- a/src/core/load-dropin.c
+++ b/src/core/load-dropin.c
@@ -20,13 +20,13 @@
***/
-#include "unit.h"
+#include "conf-parser.h"
#include "load-dropin.h"
+#include "load-fragment.h"
#include "log.h"
#include "strv.h"
#include "unit-name.h"
-#include "conf-parser.h"
-#include "load-fragment.h"
+#include "unit.h"
static int add_dependency_consumer(
UnitDependency dependency,
diff --git a/src/core/load-dropin.h b/src/core/load-dropin.h
index 1e018c4525..93ffcc4a72 100644
--- a/src/core/load-dropin.h
+++ b/src/core/load-dropin.h
@@ -21,8 +21,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "unit.h"
#include "dropin.h"
+#include "unit.h"
/* Read service data supplementary drop-in directories */
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 2333926e7d..c64850802e 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -33,6 +33,7 @@ $1.CPUAffinity, config_parse_exec_cpu_affinity, 0,
$1.UMask, config_parse_mode, 0, offsetof($1, exec_context.umask)
$1.Environment, config_parse_environ, 0, offsetof($1, exec_context.environment)
$1.EnvironmentFile, config_parse_unit_env_file, 0, offsetof($1, exec_context.environment_files)
+$1.PassEnvironment, config_parse_pass_environ, 0, offsetof($1, exec_context.pass_environment)
$1.StandardInput, config_parse_input, 0, offsetof($1, exec_context.std_input)
$1.StandardOutput, config_parse_output, 0, offsetof($1, exec_context.std_output)
$1.StandardError, config_parse_output, 0, offsetof($1, exec_context.std_error)
@@ -58,22 +59,22 @@ $1.RestrictAddressFamilies, config_parse_address_families, 0,
$1.SystemCallArchitectures, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.SystemCallErrorNumber, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.RestrictAddressFamilies, config_parse_warn_compat, DISABLED_CONFIGURATION, 0')
-$1.LimitCPU, config_parse_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit)
-$1.LimitFSIZE, config_parse_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit)
-$1.LimitDATA, config_parse_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit)
-$1.LimitSTACK, config_parse_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit)
-$1.LimitCORE, config_parse_limit, RLIMIT_CORE, offsetof($1, exec_context.rlimit)
-$1.LimitRSS, config_parse_limit, RLIMIT_RSS, offsetof($1, exec_context.rlimit)
+$1.LimitCPU, config_parse_sec_limit, RLIMIT_CPU, offsetof($1, exec_context.rlimit)
+$1.LimitFSIZE, config_parse_bytes_limit, RLIMIT_FSIZE, offsetof($1, exec_context.rlimit)
+$1.LimitDATA, config_parse_bytes_limit, RLIMIT_DATA, offsetof($1, exec_context.rlimit)
+$1.LimitSTACK, config_parse_bytes_limit, RLIMIT_STACK, offsetof($1, exec_context.rlimit)
+$1.LimitCORE, config_parse_bytes_limit, RLIMIT_CORE, offsetof($1, exec_context.rlimit)
+$1.LimitRSS, config_parse_bytes_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.LimitAS, config_parse_bytes_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.LimitMEMLOCK, config_parse_bytes_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.LimitMSGQUEUE, config_parse_bytes_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.LimitRTTIME, config_parse_usec_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit)
$1.ReadWriteDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_dirs)
$1.ReadOnlyDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_dirs)
$1.InaccessibleDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_dirs)
@@ -125,7 +126,7 @@ $1.BlockIODeviceWeight, config_parse_blockio_device_weight, 0,
$1.BlockIOReadBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context)
$1.BlockIOWriteBandwidth, config_parse_blockio_bandwidth, 0, offsetof($1, cgroup_context)
$1.TasksAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.tasks_accounting)
-$1.TasksMax, config_parse_tasks_max, 0, offsetof($1, cgroup_context)
+$1.TasksMax, config_parse_tasks_max, 0, offsetof($1, cgroup_context.tasks_max)
$1.Delegate, config_parse_bool, 0, offsetof($1, cgroup_context.delegate)
$1.NetClass, config_parse_netclass, 0, offsetof($1, cgroup_context)'
)m4_dnl
@@ -133,9 +134,7 @@ Unit.Description, config_parse_unit_string_printf, 0,
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
@@ -149,6 +148,8 @@ Unit.ReloadPropagatedFrom, config_parse_unit_deps, UNIT_RELOAD
Unit.PropagateReloadFrom, config_parse_unit_deps, UNIT_RELOAD_PROPAGATED_FROM, 0
Unit.PartOf, config_parse_unit_deps, UNIT_PART_OF, 0
Unit.JoinsNamespaceOf, config_parse_unit_deps, UNIT_JOINS_NAMESPACE_OF, 0
+Unit.RequiresOverridable, config_parse_obsolete_unit_deps, UNIT_REQUIRES, 0
+Unit.RequisiteOverridable, config_parse_obsolete_unit_deps, UNIT_REQUISITE, 0
Unit.RequiresMountsFor, config_parse_unit_requires_mounts_for, 0, 0
Unit.StopWhenUnneeded, config_parse_bool, 0, offsetof(Unit, stop_when_unneeded)
Unit.RefuseManualStart, config_parse_bool, 0, offsetof(Unit, refuse_manual_start)
@@ -158,7 +159,7 @@ Unit.DefaultDependencies, config_parse_bool, 0,
Unit.OnFailureJobMode, config_parse_job_mode, 0, offsetof(Unit, on_failure_job_mode)
Unit.OnFailureIsolate, config_parse_job_mode_isolate, 0, offsetof(Unit, on_failure_job_mode)
Unit.IgnoreOnIsolate, config_parse_bool, 0, offsetof(Unit, ignore_on_isolate)
-Unit.IgnoreOnSnapshot, config_parse_bool, 0, offsetof(Unit, ignore_on_snapshot)
+Unit.IgnoreOnSnapshot, config_parse_warn_compat, DISABLED_LEGACY, 0
Unit.JobTimeoutSec, config_parse_sec, 0, offsetof(Unit, job_timeout)
Unit.JobTimeoutAction, config_parse_failure_action, 0, offsetof(Unit, job_timeout_action)
Unit.JobTimeoutRebootArgument, config_parse_string, 0, offsetof(Unit, job_timeout_reboot_arg)
@@ -248,6 +249,7 @@ Socket.ListenNetlink, config_parse_socket_listen, SOCKET_SOCK
Socket.ListenSpecial, config_parse_socket_listen, SOCKET_SPECIAL, 0
Socket.ListenMessageQueue, config_parse_socket_listen, SOCKET_MQUEUE, 0
Socket.ListenUSBFunction, config_parse_socket_listen, SOCKET_USB_FUNCTION, 0
+Socket.SocketProtocol, config_parse_socket_protocol, 0, 0
Socket.BindIPv6Only, config_parse_socket_bind, 0, 0,
Socket.Backlog, config_parse_unsigned, 0, offsetof(Socket, backlog)
Socket.BindToDevice, config_parse_socket_bindtodevice, 0, 0
@@ -287,6 +289,7 @@ Socket.MessageQueueMaxMessages, config_parse_long, 0,
Socket.MessageQueueMessageSize, config_parse_long, 0, offsetof(Socket, mq_msgsize)
Socket.RemoveOnStop, config_parse_bool, 0, offsetof(Socket, remove_on_stop)
Socket.Symlinks, config_parse_unit_path_strv_printf, 0, offsetof(Socket, symlinks)
+Socket.FileDescriptorName, config_parse_fdname, 0, 0
Socket.Service, config_parse_socket_service, 0, 0
m4_ifdef(`HAVE_SMACK',
`Socket.SmackLabel, config_parse_string, 0, offsetof(Socket, smack)
@@ -342,7 +345,9 @@ Timer.OnUnitActiveSec, config_parse_timer, 0,
Timer.OnUnitInactiveSec, config_parse_timer, 0, 0
Timer.Persistent, config_parse_bool, 0, offsetof(Timer, persistent)
Timer.WakeSystem, config_parse_bool, 0, offsetof(Timer, wake_system)
+Timer.RemainAfterElapse, config_parse_bool, 0, offsetof(Timer, remain_after_elapse)
Timer.AccuracySec, config_parse_sec, 0, offsetof(Timer, accuracy_usec)
+Timer.RandomSec, config_parse_sec, 0, offsetof(Timer, random_usec)
Timer.Unit, config_parse_trigger_unit, 0, 0
m4_dnl
Path.PathExists, config_parse_path_spec, 0, 0
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index fc2755cb92..d5cf476fda 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -33,6 +33,7 @@
#include <sys/stat.h>
#include "af-list.h"
+#include "alloc-util.h"
#include "bus-error.h"
#include "bus-internal.h"
#include "bus-util.h"
@@ -42,21 +43,29 @@
#include "cpu-set-util.h"
#include "env-util.h"
#include "errno-list.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fs-util.h"
#include "ioprio.h"
+#include "load-fragment.h"
#include "log.h"
#include "missing.h"
+#include "parse-util.h"
#include "path-util.h"
+#include "process-util.h"
#ifdef HAVE_SECCOMP
#include "seccomp-util.h"
#endif
#include "securebits.h"
#include "signal-util.h"
+#include "stat-util.h"
+#include "string-util.h"
#include "strv.h"
#include "unit-name.h"
#include "unit-printf.h"
#include "unit.h"
#include "utf8.h"
-#include "load-fragment.h"
+#include "web-util.h"
int config_parse_warn_compat(
const char *unit,
@@ -89,35 +98,42 @@ int config_parse_warn_compat(
return 0;
}
-int config_parse_unit_deps(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_unit_deps(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
UnitDependency d = ltype;
Unit *u = userdata;
- const char *word, *state;
- size_t l;
+ const char *p;
assert(filename);
assert(lvalue);
assert(rvalue);
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *t = NULL, *k = NULL;
+ p = rvalue;
+ for(;;) {
+ _cleanup_free_ char *word = NULL, *k = NULL;
int r;
- t = strndup(word, l);
- if (!t)
+ r = extract_first_word(&p, &word, NULL, EXTRACT_RETAIN_ESCAPE);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Invalid syntax, ignoring: %s", rvalue);
+ break;
+ }
- r = unit_name_printf(u, t, &k);
+ r = unit_name_printf(u, word, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
continue;
@@ -127,12 +143,28 @@ int config_parse_unit_deps(const char *unit,
if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
}
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid syntax, ignoring.");
return 0;
}
+int config_parse_obsolete_unit_deps(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ log_syntax(unit, LOG_WARNING, filename, line, 0,
+ "Unit dependency type %s= is obsolete, replacing by %s=, please update your unit file", lvalue, unit_dependency_to_string(ltype));
+
+ return config_parse_unit_deps(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata);
+}
+
int config_parse_unit_string_printf(
const char *unit,
const char *filename,
@@ -389,6 +421,37 @@ int config_parse_socket_listen(const char *unit,
return 0;
}
+int config_parse_socket_protocol(const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+ Socket *s;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ s = SOCKET(data);
+
+ if (streq(rvalue, "udplite"))
+ s->socket_protocol = IPPROTO_UDPLITE;
+ else if (streq(rvalue, "sctp"))
+ s->socket_protocol = IPPROTO_SCTP;
+ else {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Socket protocol not supported, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ return 0;
+}
+
int config_parse_socket_bind(const char *unit,
const char *filename,
unsigned line,
@@ -522,9 +585,7 @@ int config_parse_exec(
assert(e);
e += ltype;
-
rvalue += strspn(rvalue, WHITESPACE);
- p = rvalue;
if (isempty(rvalue)) {
/* An empty assignment resets the list */
@@ -532,14 +593,15 @@ int config_parse_exec(
return 0;
}
+ p = rvalue;
do {
- int i;
+ _cleanup_free_ char *path = NULL, *firstword = NULL;
+ bool separate_argv0 = false, ignore = false;
+ _cleanup_free_ ExecCommand *nce = NULL;
_cleanup_strv_free_ char **n = NULL;
size_t nlen = 0, nbufsize = 0;
- _cleanup_free_ ExecCommand *nce = NULL;
- _cleanup_free_ char *path = NULL, *firstword = NULL;
char *f;
- bool separate_argv0 = false, ignore = false;
+ int i;
semicolon = false;
@@ -962,22 +1024,22 @@ int config_parse_exec_secure_bits(const char *unit,
return 0;
}
-int config_parse_bounding_set(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_bounding_set(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
uint64_t *capability_bounding_set_drop = data;
- const char *word, *state;
- size_t l;
+ uint64_t capability_bounding_set, sum = 0;
bool invert = false;
- uint64_t sum = 0;
+ const char *p;
assert(filename);
assert(lvalue);
@@ -994,46 +1056,54 @@ int config_parse_bounding_set(const char *unit,
* non-inverted everywhere to have a fully normalized
* interface. */
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *t = NULL;
- int cap;
+ p = rvalue;
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+ int cap, r;
- t = strndup(word, l);
- if (!t)
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse word, ignoring: %s", rvalue);
+ break;
+ }
- cap = capability_from_name(t);
+ cap = capability_from_name(word);
if (cap < 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding set, ignoring: %s", t);
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse capability in bounding set, ignoring: %s", word);
continue;
}
- sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
+ sum |= ((uint64_t) UINT64_C(1)) << (uint64_t) cap;
}
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
- if (invert)
- *capability_bounding_set_drop |= sum;
+ capability_bounding_set = invert ? ~sum : sum;
+ if (*capability_bounding_set_drop != 0 && capability_bounding_set != 0)
+ *capability_bounding_set_drop = ~(~*capability_bounding_set_drop | capability_bounding_set);
else
- *capability_bounding_set_drop |= ~sum;
+ *capability_bounding_set_drop = ~capability_bounding_set;
return 0;
}
-int config_parse_limit(const char *unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_limit(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
struct rlimit **rl = data;
- unsigned long long u;
+ rlim_t v;
+ int r;
assert(filename);
assert(lvalue);
@@ -1043,15 +1113,71 @@ int config_parse_limit(const char *unit,
rl += ltype;
if (streq(rvalue, "infinity"))
- u = (unsigned long long) RLIM_INFINITY;
+ v = RLIM_INFINITY;
else {
- int r;
+ uint64_t u;
+
+ /* setrlimit(2) suggests rlim_t is always 64bit on Linux. */
+ assert_cc(sizeof(rlim_t) == sizeof(uint64_t));
+
+ r = safe_atou64(rvalue, &u);
+ if (r >= 0 && u >= (uint64_t) RLIM_INFINITY)
+ r = -ERANGE;
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ v = (rlim_t) u;
+ }
+
+ if (!*rl) {
+ *rl = new(struct rlimit, 1);
+ if (!*rl)
+ return log_oom();
+ }
+
+ (*rl)->rlim_cur = (*rl)->rlim_max = v;
+ return 0;
+}
+
+int config_parse_bytes_limit(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
- r = safe_atollu(rvalue, &u);
+ struct rlimit **rl = data;
+ rlim_t bytes;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ rl += ltype;
+
+ if (streq(rvalue, "infinity"))
+ bytes = RLIM_INFINITY;
+ else {
+ uint64_t u;
+
+ r = parse_size(rvalue, 1024, &u);
+ if (r >= 0 && u >= (uint64_t) RLIM_INFINITY)
+ r = -ERANGE;
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
return 0;
}
+
+ bytes = (rlim_t) u;
}
if (!*rl) {
@@ -1060,7 +1186,108 @@ int config_parse_limit(const char *unit,
return log_oom();
}
- (*rl)->rlim_cur = (*rl)->rlim_max = (rlim_t) u;
+ (*rl)->rlim_cur = (*rl)->rlim_max = bytes;
+ return 0;
+}
+
+int config_parse_sec_limit(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ struct rlimit **rl = data;
+ rlim_t seconds;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ rl += ltype;
+
+ if (streq(rvalue, "infinity"))
+ seconds = RLIM_INFINITY;
+ else {
+ usec_t t;
+
+ r = parse_sec(rvalue, &t);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ if (t == USEC_INFINITY)
+ seconds = RLIM_INFINITY;
+ else
+ seconds = (rlim_t) (DIV_ROUND_UP(t, USEC_PER_SEC));
+ }
+
+ if (!*rl) {
+ *rl = new(struct rlimit, 1);
+ if (!*rl)
+ return log_oom();
+ }
+
+ (*rl)->rlim_cur = (*rl)->rlim_max = seconds;
+ return 0;
+}
+
+
+int config_parse_usec_limit(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ struct rlimit **rl = data;
+ rlim_t useconds;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ rl += ltype;
+
+ if (streq(rvalue, "infinity"))
+ useconds = RLIM_INFINITY;
+ else {
+ usec_t t;
+
+ r = parse_time(rvalue, &t, 1);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse resource value, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ if (t == USEC_INFINITY)
+ useconds = RLIM_INFINITY;
+ else
+ useconds = (rlim_t) t;
+ }
+
+ if (!*rl) {
+ *rl = new(struct rlimit, 1);
+ if (!*rl)
+ return log_oom();
+ }
+
+ (*rl)->rlim_cur = (*rl)->rlim_max = useconds;
return 0;
}
@@ -1475,10 +1702,10 @@ int config_parse_socket_service(
void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_free_ char *p = NULL;
Socket *s = data;
- int r;
Unit *x;
- _cleanup_free_ char *p = NULL;
+ int r;
assert(filename);
assert(lvalue);
@@ -1507,6 +1734,50 @@ int config_parse_socket_service(
return 0;
}
+int config_parse_fdname(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ _cleanup_free_ char *p = NULL;
+ Socket *s = data;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (isempty(rvalue)) {
+ s->fdname = mfree(s->fdname);
+ return 0;
+ }
+
+ r = unit_name_printf(UNIT(s), rvalue, &p);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %s", rvalue);
+ return 0;
+ }
+
+ if (!fdname_is_valid(p)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid file descriptor name, ignoring: %s", p);
+ return 0;
+ }
+
+ free(s->fdname);
+ s->fdname = p;
+ p = NULL;
+
+ return 0;
+}
+
int config_parse_service_sockets(
const char *unit,
const char *filename,
@@ -1520,8 +1791,7 @@ int config_parse_service_sockets(
void *userdata) {
Service *s = data;
- const char *word, *state;
- size_t l;
+ const char *p;
int r;
assert(filename);
@@ -1529,14 +1799,21 @@ int config_parse_service_sockets(
assert(rvalue);
assert(data);
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *t = NULL, *k = NULL;
+ p = rvalue;
+ for(;;) {
+ _cleanup_free_ char *word = NULL, *k = NULL;
- t = strndup(word, l);
- if (!t)
+ r = extract_first_word(&p, &word, NULL, 0);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage in sockets, ignoring: %s", rvalue);
+ break;
+ }
- r = unit_name_printf(UNIT(s), t, &k);
+ r = unit_name_printf(UNIT(s), word, &k);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to resolve specifiers, ignoring: %m");
continue;
@@ -1555,8 +1832,6 @@ int config_parse_service_sockets(
if (r < 0)
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to add dependency on %s, ignoring: %m", k);
}
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
@@ -1971,6 +2246,70 @@ int config_parse_environ(const char *unit,
return 0;
}
+int config_parse_pass_environ(const char *unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ const char *whole_rvalue = rvalue;
+ char*** passenv = data;
+ _cleanup_strv_free_ char **n = NULL;
+ size_t nlen = 0, nbufsize = 0;
+ int r;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if (isempty(rvalue)) {
+ /* Empty assignment resets the list */
+ *passenv = strv_free(*passenv);
+ return 0;
+ }
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+
+ r = extract_first_word(&rvalue, &word, WHITESPACE, EXTRACT_QUOTES);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r,
+ "Trailing garbage in %s, ignoring: %s", lvalue, whole_rvalue);
+ break;
+ }
+
+ if (!env_name_is_valid(word)) {
+ log_syntax(unit, LOG_ERR, filename, line, EINVAL,
+ "Invalid environment name for %s, ignoring: %s", lvalue, word);
+ continue;
+ }
+
+ if (!GREEDY_REALLOC(n, nbufsize, nlen + 2))
+ return log_oom();
+ n[nlen++] = word;
+ n[nlen] = NULL;
+ word = NULL;
+ }
+
+ if (n) {
+ r = strv_extend_strv(passenv, n, true);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
int config_parse_ip_tos(const char *unit,
const char *filename,
unsigned line,
@@ -2683,12 +3022,11 @@ int config_parse_tasks_max(
void *data,
void *userdata) {
- CGroupContext *c = data;
- uint64_t u;
+ uint64_t *tasks_max = data, u;
int r;
if (isempty(rvalue) || streq(rvalue, "infinity")) {
- c->tasks_max = (uint64_t) -1;
+ *tasks_max = (uint64_t) -1;
return 0;
}
@@ -2698,6 +3036,7 @@ int config_parse_tasks_max(
return 0;
}
+ *tasks_max = u;
return 0;
}
@@ -3148,8 +3487,8 @@ int config_parse_namespace_path_strv(
void *userdata) {
char*** sv = data;
- const char *word, *state;
- size_t l;
+ const char *prev;
+ const char *cur;
int r;
assert(filename);
@@ -3163,35 +3502,43 @@ int config_parse_namespace_path_strv(
return 0;
}
- FOREACH_WORD_QUOTED(word, l, rvalue, state) {
- _cleanup_free_ char *n;
+ prev = cur = rvalue;
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
int offset;
- n = strndup(word, l);
- if (!n)
+ r = extract_first_word(&cur, &word, NULL, EXTRACT_QUOTES);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
return log_oom();
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Trailing garbage, ignoring: %s", prev);
+ return 0;
+ }
- if (!utf8_is_valid(n)) {
- log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, rvalue);
+ if (!utf8_is_valid(word)) {
+ log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, word);
+ prev = cur;
continue;
}
- offset = n[0] == '-';
- if (!path_is_absolute(n + offset)) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", rvalue);
+ offset = word[0] == '-';
+ if (!path_is_absolute(word + offset)) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Not an absolute path, ignoring: %s", word);
+ prev = cur;
continue;
}
- path_kill_slashes(n);
+ path_kill_slashes(word + offset);
- r = strv_push(sv, n);
+ r = strv_push(sv, word);
if (r < 0)
return log_oom();
- n = NULL;
+ prev = cur;
+ word = NULL;
}
- if (!isempty(state))
- log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
return 0;
}
diff --git a/src/core/load-fragment.h b/src/core/load-fragment.h
index 6ee7c71bc4..a451fc164a 100644
--- a/src/core/load-fragment.h
+++ b/src/core/load-fragment.h
@@ -31,12 +31,14 @@ void unit_dump_config_items(FILE *f);
int config_parse_warn_compat(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_unit_deps(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_obsolete_unit_deps(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_unit_string_printf(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_unit_strv_printf(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_unit_path_printf(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_unit_path_strv_printf(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_documentation(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_socket_listen(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_socket_protocol(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_socket_bind(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_exec_nice(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_exec_oom_score_adjust(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
@@ -56,6 +58,9 @@ int config_parse_exec_capabilities(const char *unit, const char *filename, unsig
int config_parse_exec_secure_bits(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_bounding_set(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_bytes_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_sec_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_usec_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_sysv_priority(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_kill_signal(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_exec_mount_flags(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
@@ -81,6 +86,7 @@ int config_parse_syscall_filter(const char *unit, const char *filename, unsigned
int config_parse_syscall_archs(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_syscall_errno(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_environ(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_pass_environ(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_unit_slice(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_cpu_shares(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_memory_limit(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
@@ -107,6 +113,7 @@ int config_parse_protect_system(const char* unit, const char *filename, unsigned
int config_parse_bus_name(const char* unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_exec_utmp_mode(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
int config_parse_working_directory(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_fdname(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
/* gperf prototypes */
const struct ConfigPerfItem* load_fragment_gperf_lookup(const char *key, unsigned length);
diff --git a/src/core/locale-setup.c b/src/core/locale-setup.c
index 6961c26674..4c8d920389 100644
--- a/src/core/locale-setup.c
+++ b/src/core/locale-setup.c
@@ -19,16 +19,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdlib.h>
#include <errno.h>
+#include <stdlib.h>
+#include "env-util.h"
+#include "fileio.h"
#include "locale-setup.h"
+#include "locale-util.h"
+#include "string-util.h"
+#include "strv.h"
#include "util.h"
#include "virt.h"
-#include "fileio.h"
-#include "strv.h"
-#include "env-util.h"
-#include "locale-util.h"
int locale_setup(char ***environment) {
char **add;
diff --git a/src/core/loopback-setup.c b/src/core/loopback-setup.c
index 4503fc9dcc..4a57793104 100644
--- a/src/core/loopback-setup.c
+++ b/src/core/loopback-setup.c
@@ -23,9 +23,10 @@
#include <stdlib.h>
#include "sd-netlink.h"
-#include "netlink-util.h"
-#include "missing.h"
+
#include "loopback-setup.h"
+#include "missing.h"
+#include "netlink-util.h"
static int start_loopback(sd_netlink *rtnl) {
_cleanup_netlink_message_unref_ sd_netlink_message *req = NULL;
diff --git a/src/core/machine-id-setup.c b/src/core/machine-id-setup.c
index 363ffaaf05..145ba2a28d 100644
--- a/src/core/machine-id-setup.c
+++ b/src/core/machine-id-setup.c
@@ -29,15 +29,24 @@
#include "sd-id128.h"
+#include "alloc-util.h"
+#include "fd-util.h"
#include "fileio.h"
+#include "fs-util.h"
+#include "hexdecoct.h"
+#include "io-util.h"
#include "log.h"
+#include "machine-id-setup.h"
#include "macro.h"
#include "mkdir.h"
+#include "mount-util.h"
#include "path-util.h"
#include "process-util.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "umask-util.h"
#include "util.h"
#include "virt.h"
-#include "machine-id-setup.h"
static int shorten_uuid(char destination[34], const char source[36]) {
unsigned i, j;
diff --git a/src/core/macros.systemd.in b/src/core/macros.systemd.in
index bea6ef1da3..8a0e44b58c 100644
--- a/src/core/macros.systemd.in
+++ b/src/core/macros.systemd.in
@@ -1,4 +1,4 @@
-# -*- Mode: makefile; indent-tabs-mode: t -*- */
+# -*- Mode: rpm-spec; indent-tabs-mode: nil -*- */
#
# This file is part of systemd.
#
@@ -39,7 +39,7 @@ Requires(postun): systemd \
%systemd_post() \
if [ $1 -eq 1 ] ; then \
# Initial installation \
- systemctl preset %{?*} >/dev/null 2>&1 || : \
+ systemctl --no-reload preset %{?*} >/dev/null 2>&1 || : \
fi \
%{nil}
@@ -48,8 +48,7 @@ fi \
%systemd_preun() \
if [ $1 -eq 0 ] ; then \
# Package removal, not upgrade \
- systemctl --no-reload disable %{?*} > /dev/null 2>&1 || : \
- systemctl stop %{?*} > /dev/null 2>&1 || : \
+ systemctl --no-reload disable --now %{?*} > /dev/null 2>&1 || : \
fi \
%{nil}
@@ -60,14 +59,11 @@ if [ $1 -eq 0 ] ; then \
fi \
%{nil}
-%systemd_postun() \
-systemctl daemon-reload >/dev/null 2>&1 || : \
-%{nil}
+%systemd_postun() %{nil}
%systemd_user_postun() %{nil}
%systemd_postun_with_restart() \
-systemctl daemon-reload >/dev/null 2>&1 || : \
if [ $1 -ge 1 ] ; then \
# Package upgrade, not uninstall \
systemctl try-restart %{?*} >/dev/null 2>&1 || : \
diff --git a/src/core/main.c b/src/core/main.c
index 2406832694..97f904b031 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -37,23 +37,26 @@
#include <valgrind/valgrind.h>
#endif
-#include "sd-daemon.h"
#include "sd-bus.h"
+#include "sd-daemon.h"
+#include "alloc-util.h"
#include "architecture.h"
#include "build.h"
#include "bus-error.h"
#include "bus-util.h"
-#include "capability.h"
+#include "capability-util.h"
#include "clock-util.h"
#include "conf-parser.h"
#include "cpu-set-util.h"
#include "dbus-manager.h"
#include "def.h"
#include "env-util.h"
+#include "fd-util.h"
#include "fdset.h"
#include "fileio.h"
#include "formats-util.h"
+#include "fs-util.h"
#include "hostname-setup.h"
#include "ima-setup.h"
#include "killall.h"
@@ -66,15 +69,21 @@
#include "missing.h"
#include "mount-setup.h"
#include "pager.h"
+#include "parse-util.h"
+#include "proc-cmdline.h"
#include "process-util.h"
+#include "rlimit-util.h"
#include "selinux-setup.h"
#include "selinux-util.h"
#include "signal-util.h"
#include "smack-setup.h"
#include "special.h"
+#include "stat-util.h"
+#include "stdio-util.h"
#include "strv.h"
#include "switch-root.h"
#include "terminal-util.h"
+#include "user-util.h"
#include "virt.h"
#include "watchdog.h"
@@ -116,7 +125,8 @@ static FILE* arg_serialization = NULL;
static bool arg_default_cpu_accounting = false;
static bool arg_default_blockio_accounting = false;
static bool arg_default_memory_accounting = false;
-static bool arg_default_tasks_accounting = false;
+static bool arg_default_tasks_accounting = true;
+static uint64_t arg_default_tasks_max = UINT64_C(512);
static void pager_open_if_enabled(void) {
@@ -142,6 +152,8 @@ noreturn static void freeze_or_reboot(void) {
}
noreturn static void crash(int sig) {
+ struct sigaction sa;
+ pid_t pid;
if (getpid() != 1)
/* Pass this on immediately, if this is not PID 1 */
@@ -149,11 +161,10 @@ noreturn static void crash(int sig) {
else if (!arg_dump_core)
log_emergency("Caught <%s>, not dumping core.", signal_to_string(sig));
else {
- struct sigaction sa = {
+ sa = (struct sigaction) {
.sa_handler = nop_signal_handler,
.sa_flags = SA_NOCLDSTOP|SA_RESTART,
};
- pid_t pid;
/* We want to wait for the core process, hence let's enable SIGCHLD */
(void) sigaction(SIGCHLD, &sa, NULL);
@@ -209,19 +220,18 @@ noreturn static void crash(int sig) {
if (arg_crash_chvt >= 0)
(void) chvt(arg_crash_chvt);
- if (arg_crash_shell) {
- struct sigaction sa = {
- .sa_handler = SIG_IGN,
- .sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART,
- };
- pid_t pid;
+ sa = (struct sigaction) {
+ .sa_handler = SIG_IGN,
+ .sa_flags = SA_NOCLDSTOP|SA_NOCLDWAIT|SA_RESTART,
+ };
+
+ /* Let the kernel reap children for us */
+ (void) sigaction(SIGCHLD, &sa, NULL);
+ if (arg_crash_shell) {
log_notice("Executing crash shell in 10s...");
(void) sleep(10);
- /* Let the kernel reap children for us */
- (void) sigaction(SIGCHLD, &sa, NULL);
-
pid = raw_clone(SIGCHLD, NULL);
if (pid < 0)
log_emergency_errno(errno, "Failed to fork off crash shell: %m");
@@ -231,11 +241,10 @@ noreturn static void crash(int sig) {
(void) execle("/bin/sh", "/bin/sh", NULL, environ);
log_emergency_errno(errno, "execle() failed: %m");
- freeze_or_reboot();
_exit(EXIT_FAILURE);
} else {
log_info("Spawned crash shell as PID "PID_FMT".", pid);
- freeze();
+ (void) wait_for_terminate(pid, NULL);
}
}
@@ -293,20 +302,6 @@ static int parse_crash_chvt(const char *value) {
static int parse_proc_cmdline_item(const char *key, const char *value) {
- static const char * const rlmap[] = {
- "emergency", SPECIAL_EMERGENCY_TARGET,
- "-b", SPECIAL_EMERGENCY_TARGET,
- "rescue", SPECIAL_RESCUE_TARGET,
- "single", SPECIAL_RESCUE_TARGET,
- "-s", SPECIAL_RESCUE_TARGET,
- "s", SPECIAL_RESCUE_TARGET,
- "S", SPECIAL_RESCUE_TARGET,
- "1", SPECIAL_RESCUE_TARGET,
- "2", SPECIAL_MULTI_USER_TARGET,
- "3", SPECIAL_MULTI_USER_TARGET,
- "4", SPECIAL_MULTI_USER_TARGET,
- "5", SPECIAL_GRAPHICAL_TARGET,
- };
int r;
assert(key);
@@ -407,12 +402,12 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
log_set_target(LOG_TARGET_CONSOLE);
} else if (!in_initrd() && !value) {
- unsigned i;
+ const char *target;
/* SysV compatibility */
- for (i = 0; i < ELEMENTSOF(rlmap); i += 2)
- if (streq(key, rlmap[i]))
- return free_and_strdup(&arg_default_unit, rlmap[i+1]);
+ target = runlevel_to_target(key);
+ if (target)
+ return free_and_strdup(&arg_default_unit, target);
}
return 0;
@@ -521,7 +516,6 @@ static int config_parse_crash_chvt(
assert(filename);
assert(lvalue);
assert(rvalue);
- assert(data);
r = parse_crash_chvt(rvalue);
if (r < 0) {
@@ -601,7 +595,7 @@ static int config_parse_join_controllers(const char *unit,
for (a = arg_join_controllers; *a; a++) {
if (strv_overlap(*a, l)) {
- if (strv_extend_strv(&l, *a) < 0) {
+ if (strv_extend_strv(&l, *a, false) < 0) {
strv_free(l);
strv_free_free(t);
return log_oom();
@@ -664,33 +658,40 @@ static int parse_config_file(void) {
{ "Manager", "DefaultStartLimitInterval", config_parse_sec, 0, &arg_default_start_limit_interval },
{ "Manager", "DefaultStartLimitBurst", config_parse_unsigned, 0, &arg_default_start_limit_burst },
{ "Manager", "DefaultEnvironment", config_parse_environ, 0, &arg_default_environment },
- { "Manager", "DefaultLimitCPU", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_CPU] },
- { "Manager", "DefaultLimitFSIZE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_FSIZE] },
- { "Manager", "DefaultLimitDATA", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_DATA] },
- { "Manager", "DefaultLimitSTACK", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_STACK] },
- { "Manager", "DefaultLimitCORE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_CORE] },
- { "Manager", "DefaultLimitRSS", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RSS] },
+ { "Manager", "DefaultLimitCPU", config_parse_sec_limit, 0, &arg_default_rlimit[RLIMIT_CPU] },
+ { "Manager", "DefaultLimitFSIZE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_FSIZE] },
+ { "Manager", "DefaultLimitDATA", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_DATA] },
+ { "Manager", "DefaultLimitSTACK", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_STACK] },
+ { "Manager", "DefaultLimitCORE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_CORE] },
+ { "Manager", "DefaultLimitRSS", config_parse_bytes_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", "DefaultLimitAS", config_parse_bytes_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", "DefaultLimitMEMLOCK", config_parse_bytes_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", "DefaultLimitMSGQUEUE", config_parse_bytes_limit, 0, &arg_default_rlimit[RLIMIT_MSGQUEUE] },
{ "Manager", "DefaultLimitNICE", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_NICE] },
{ "Manager", "DefaultLimitRTPRIO", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTPRIO] },
- { "Manager", "DefaultLimitRTTIME", config_parse_limit, 0, &arg_default_rlimit[RLIMIT_RTTIME] },
+ { "Manager", "DefaultLimitRTTIME", config_parse_usec_limit, 0, &arg_default_rlimit[RLIMIT_RTTIME] },
{ "Manager", "DefaultCPUAccounting", config_parse_bool, 0, &arg_default_cpu_accounting },
{ "Manager", "DefaultBlockIOAccounting", config_parse_bool, 0, &arg_default_blockio_accounting },
{ "Manager", "DefaultMemoryAccounting", config_parse_bool, 0, &arg_default_memory_accounting },
{ "Manager", "DefaultTasksAccounting", config_parse_bool, 0, &arg_default_tasks_accounting },
+ { "Manager", "DefaultTasksMax", config_parse_tasks_max, 0, &arg_default_tasks_max },
{}
};
const char *fn, *conf_dirs_nulstr;
- fn = arg_running_as == MANAGER_SYSTEM ? PKGSYSCONFDIR "/system.conf" : PKGSYSCONFDIR "/user.conf";
- conf_dirs_nulstr = arg_running_as == MANAGER_SYSTEM ? CONF_DIRS_NULSTR("systemd/system.conf") : CONF_DIRS_NULSTR("systemd/user.conf");
+ fn = arg_running_as == MANAGER_SYSTEM ?
+ PKGSYSCONFDIR "/system.conf" :
+ PKGSYSCONFDIR "/user.conf";
+
+ conf_dirs_nulstr = arg_running_as == MANAGER_SYSTEM ?
+ CONF_PATHS_NULSTR("systemd/system.conf.d") :
+ CONF_PATHS_NULSTR("systemd/user.conf.d");
+
config_parse_many(fn, conf_dirs_nulstr, "Manager\0",
config_item_table_lookup, items, false, NULL);
@@ -713,6 +714,7 @@ static void manager_set_defaults(Manager *m) {
m->default_blockio_accounting = arg_default_blockio_accounting;
m->default_memory_accounting = arg_default_memory_accounting;
m->default_tasks_accounting = arg_default_tasks_accounting;
+ m->default_tasks_max = arg_default_tasks_max;
manager_set_default_rlimits(m, arg_default_rlimit);
manager_environment_add(m, NULL, arg_default_environment);
@@ -1106,33 +1108,6 @@ static int bump_rlimit_nofile(struct rlimit *saved_rlimit) {
return 0;
}
-static void test_mtab(void) {
-
- static const char ok[] =
- "/proc/self/mounts\0"
- "/proc/mounts\0"
- "../proc/self/mounts\0"
- "../proc/mounts\0";
-
- _cleanup_free_ char *p = NULL;
- int r;
-
- /* Check that /etc/mtab is a symlink to the right place or
- * non-existing. But certainly not a file, or a symlink to
- * some weird place... */
-
- r = readlink_malloc("/etc/mtab", &p);
- if (r == -ENOENT)
- return;
- if (r >= 0 && nulstr_contains(ok, p))
- return;
-
- log_error("/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.");
- freeze_or_reboot();
-}
-
static void test_usr(void) {
/* Check that /usr is not a separate fs */
@@ -1235,12 +1210,50 @@ static int status_welcome(void) {
static int write_container_id(void) {
const char *c;
+ int r;
c = getenv("container");
if (isempty(c))
return 0;
- return write_string_file("/run/systemd/container", c, WRITE_STRING_FILE_CREATE);
+ r = write_string_file("/run/systemd/container", c, WRITE_STRING_FILE_CREATE);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to write /run/systemd/container, ignoring: %m");
+
+ return 1;
+}
+
+static int bump_unix_max_dgram_qlen(void) {
+ _cleanup_free_ char *qlen = NULL;
+ unsigned long v;
+ int r;
+
+ /* Let's bump the net.unix.max_dgram_qlen sysctl. The kernel
+ * default of 16 is simply too low. We set the value really
+ * really early during boot, so that it is actually applied to
+ * all our sockets, including the $NOTIFY_SOCKET one. */
+
+ r = read_one_line_file("/proc/sys/net/unix/max_dgram_qlen", &qlen);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to read AF_UNIX datagram queue length, ignoring: %m");
+
+ r = safe_atolu(qlen, &v);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to parse AF_UNIX datagram queue length, ignoring: %m");
+
+ if (v >= DEFAULT_UNIX_MAX_DGRAM_QLEN)
+ return 0;
+
+ qlen = mfree(qlen);
+ if (asprintf(&qlen, "%lu\n", DEFAULT_UNIX_MAX_DGRAM_QLEN) < 0)
+ return log_oom();
+
+ r = write_string_file("/proc/sys/net/unix/max_dgram_qlen", qlen, 0);
+ if (r < 0)
+ return log_full_errno(IN_SET(r, -EROFS, -EPERM, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to bump AF_UNIX datagram queue length, ignoring: %m");
+
+ return 1;
}
int main(int argc, char *argv[]) {
@@ -1606,8 +1619,8 @@ int main(int argc, char *argv[]) {
hostname_setup();
machine_id_setup(NULL);
loopback_setup();
+ bump_unix_max_dgram_qlen();
- test_mtab();
test_usr();
}
@@ -1734,11 +1747,13 @@ int main(int argc, char *argv[]) {
manager_dump_units(m, stdout, "\t");
}
- r = manager_add_job(m, JOB_START, target, JOB_ISOLATE, false, &error, &default_unit_job);
+ r = manager_add_job(m, JOB_START, target, JOB_ISOLATE, &error, &default_unit_job);
if (r == -EPERM) {
log_debug("Default target could not be isolated, starting instead: %s", bus_error_message(&error, r));
- r = manager_add_job(m, JOB_START, target, JOB_REPLACE, false, &error, &default_unit_job);
+ sd_bus_error_free(&error);
+
+ r = manager_add_job(m, JOB_START, target, JOB_REPLACE, &error, &default_unit_job);
if (r < 0) {
log_emergency("Failed to start default target: %s", bus_error_message(&error, r));
error_message = "Failed to start default target";
diff --git a/src/core/manager.c b/src/core/manager.c
index 9de9691a47..edff6758c5 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -40,6 +40,7 @@
#include "sd-daemon.h"
#include "sd-messages.h"
+#include "alloc-util.h"
#include "audit-fd.h"
#include "boot-timestamps.h"
#include "bus-common-errors.h"
@@ -51,13 +52,20 @@
#include "dbus-unit.h"
#include "dbus.h"
#include "env-util.h"
+#include "escape.h"
#include "exit-status.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "fs-util.h"
#include "hashmap.h"
+#include "io-util.h"
#include "locale-setup.h"
#include "log.h"
#include "macro.h"
+#include "manager.h"
#include "missing.h"
#include "mkdir.h"
+#include "parse-util.h"
#include "path-lookup.h"
#include "path-util.h"
#include "process-util.h"
@@ -65,15 +73,20 @@
#include "rm-rf.h"
#include "signal-util.h"
#include "special.h"
+#include "stat-util.h"
+#include "string-table.h"
+#include "string-util.h"
#include "strv.h"
#include "terminal-util.h"
#include "time-util.h"
#include "transaction.h"
+#include "umask-util.h"
#include "unit-name.h"
#include "util.h"
#include "virt.h"
#include "watchdog.h"
-#include "manager.h"
+
+#define NOTIFY_RCVBUF_SIZE (8*1024*1024)
/* Initial delay and the interval for printing status messages about running jobs */
#define JOBS_IN_PROGRESS_WAIT_USEC (5*USEC_PER_SEC)
@@ -473,7 +486,7 @@ static int manager_setup_signals(Manager *m) {
* later than notify_fd processing, so that the notify
* processing can still figure out to which process/service a
* message belongs, before we reap the process. */
- r = sd_event_source_set_priority(m->signal_event_source, -5);
+ r = sd_event_source_set_priority(m->signal_event_source, SD_EVENT_PRIORITY_NORMAL-5);
if (r < 0)
return r;
@@ -495,6 +508,7 @@ static void manager_clean_environment(Manager *m) {
"MANAGERPID",
"LISTEN_PID",
"LISTEN_FDS",
+ "LISTEN_FDNAMES",
"WATCHDOG_PID",
"WATCHDOG_USEC",
NULL);
@@ -563,6 +577,8 @@ int manager_new(ManagerRunningAs running_as, bool test_run, Manager **_m) {
m->running_as = running_as;
m->exit_code = _MANAGER_EXIT_CODE_INVALID;
m->default_timer_accuracy_usec = USEC_PER_MINUTE;
+ m->default_tasks_accounting = true;
+ m->default_tasks_max = UINT64_C(512);
/* Prepare log fields we can use for structured logging */
m->unit_log_field = unit_log_fields[running_as];
@@ -677,6 +693,8 @@ static int manager_setup_notify(Manager *m) {
if (fd < 0)
return log_error_errno(errno, "Failed to allocate notification socket: %m");
+ fd_inc_rcvbuf(fd, NOTIFY_RCVBUF_SIZE);
+
if (m->running_as == MANAGER_SYSTEM)
m->notify_socket = strdup("/run/systemd/notify");
else {
@@ -718,7 +736,7 @@ static int manager_setup_notify(Manager *m) {
/* Process signals a bit earlier than SIGCHLD, so that we can
* still identify to which service an exit message belongs */
- r = sd_event_source_set_priority(m->notify_event_source, -7);
+ r = sd_event_source_set_priority(m->notify_event_source, SD_EVENT_PRIORITY_NORMAL-7);
if (r < 0)
return log_error_errno(r, "Failed to set priority of notify event source: %m");
@@ -977,8 +995,7 @@ Manager* manager_free(Manager *m) {
return NULL;
}
-int manager_enumerate(Manager *m) {
- int r = 0;
+void manager_enumerate(Manager *m) {
UnitType c;
assert(m);
@@ -986,8 +1003,6 @@ int manager_enumerate(Manager *m) {
/* Let's ask every type to load all units from disk/kernel
* that it might know */
for (c = 0; c < _UNIT_TYPE_MAX; c++) {
- int q;
-
if (!unit_type_supported(c)) {
log_debug("Unit type .%s is not supported on this system.", unit_type_to_string(c));
continue;
@@ -996,13 +1011,10 @@ int manager_enumerate(Manager *m) {
if (!unit_vtable[c]->enumerate)
continue;
- q = unit_vtable[c]->enumerate(m);
- if (q < 0)
- r = q;
+ unit_vtable[c]->enumerate(m);
}
manager_dispatch_load_queue(m);
- return r;
}
static void manager_coldplug(Manager *m) {
@@ -1084,10 +1096,9 @@ fail:
}
-static int manager_distribute_fds(Manager *m, FDSet *fds) {
- Unit *u;
+static void manager_distribute_fds(Manager *m, FDSet *fds) {
Iterator i;
- int r;
+ Unit *u;
assert(m);
@@ -1096,14 +1107,11 @@ static int manager_distribute_fds(Manager *m, FDSet *fds) {
if (fdset_size(fds) <= 0)
break;
- if (UNIT_VTABLE(u)->distribute_fds) {
- r = UNIT_VTABLE(u)->distribute_fds(u, fds);
- if (r < 0)
- return r;
- }
- }
+ if (!UNIT_VTABLE(u)->distribute_fds)
+ continue;
- return 0;
+ UNIT_VTABLE(u)->distribute_fds(u, fds);
+ }
}
int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
@@ -1136,7 +1144,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
/* First, enumerate what we can from all config files */
dual_timestamp_get(&m->units_load_start_timestamp);
- r = manager_enumerate(m);
+ manager_enumerate(m);
dual_timestamp_get(&m->units_load_finish_timestamp);
/* Second, deserialize if there is something to deserialize */
@@ -1147,11 +1155,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
* useful to allow container managers to pass some file
* descriptors to us pre-initialized. This enables
* socket-based activation of entire containers. */
- if (fdset_size(fds) > 0) {
- q = manager_distribute_fds(m, fds);
- if (q < 0 && r == 0)
- r = q;
- }
+ manager_distribute_fds(m, fds);
/* We might have deserialized the notify fd, but if we didn't
* then let's create the bus now */
@@ -1181,7 +1185,7 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
return r;
}
-int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool override, sd_bus_error *e, Job **_ret) {
+int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_error *e, Job **_ret) {
int r;
Transaction *tr;
@@ -1204,7 +1208,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove
if (!tr)
return -ENOMEM;
- r = transaction_add_job_and_dependencies(tr, type, unit, NULL, true, override, false,
+ r = transaction_add_job_and_dependencies(tr, type, unit, NULL, true, false,
mode == JOB_IGNORE_DEPENDENCIES || mode == JOB_IGNORE_REQUIREMENTS,
mode == JOB_IGNORE_DEPENDENCIES, e);
if (r < 0)
@@ -1236,7 +1240,7 @@ tr_abort:
return r;
}
-int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool override, sd_bus_error *e, Job **_ret) {
+int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, sd_bus_error *e, Job **ret) {
Unit *unit;
int r;
@@ -1249,7 +1253,23 @@ int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode
if (r < 0)
return r;
- return manager_add_job(m, type, unit, mode, override, e, _ret);
+ return manager_add_job(m, type, unit, mode, e, ret);
+}
+
+int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Job **ret) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+ int r;
+
+ assert(m);
+ assert(type < _JOB_TYPE_MAX);
+ assert(name);
+ assert(mode < _JOB_MODE_MAX);
+
+ r = manager_add_job_by_name(m, type, name, mode, &error, ret);
+ if (r < 0)
+ return log_warning_errno(r, "Failed to enqueue %s job for %s: %s", job_mode_to_string(mode), name, bus_error_message(&error, r));
+
+ return r;
}
Job *manager_get_job(Manager *m, uint32_t id) {
@@ -1476,7 +1496,7 @@ static unsigned manager_dispatch_dbus_queue(Manager *m) {
return n;
}
-static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char *buf, size_t n, FDSet *fds) {
+static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, const char *buf, size_t n, FDSet *fds) {
_cleanup_strv_free_ char **tags = NULL;
assert(m);
@@ -1497,9 +1517,33 @@ static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, char *
}
static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
+ _cleanup_fdset_free_ FDSet *fds = NULL;
Manager *m = userdata;
+
+ char buf[NOTIFY_BUFFER_MAX+1];
+ struct iovec iovec = {
+ .iov_base = buf,
+ .iov_len = sizeof(buf)-1,
+ };
+ union {
+ struct cmsghdr cmsghdr;
+ uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
+ CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)];
+ } control = {};
+ struct msghdr msghdr = {
+ .msg_iov = &iovec,
+ .msg_iovlen = 1,
+ .msg_control = &control,
+ .msg_controllen = sizeof(control),
+ };
+
+ struct cmsghdr *cmsg;
+ struct ucred *ucred = NULL;
+ bool found = false;
+ Unit *u1, *u2, *u3;
+ int r, *fd_array = NULL;
+ unsigned n_fds = 0;
ssize_t n;
- int r;
assert(m);
assert(m->notify_fd == fd);
@@ -1509,106 +1553,80 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
return 0;
}
- for (;;) {
- _cleanup_fdset_free_ FDSet *fds = NULL;
- char buf[NOTIFY_BUFFER_MAX+1];
- struct iovec iovec = {
- .iov_base = buf,
- .iov_len = sizeof(buf)-1,
- };
- union {
- struct cmsghdr cmsghdr;
- uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
- CMSG_SPACE(sizeof(int) * NOTIFY_FD_MAX)];
- } control = {};
- struct msghdr msghdr = {
- .msg_iov = &iovec,
- .msg_iovlen = 1,
- .msg_control = &control,
- .msg_controllen = sizeof(control),
- };
- struct cmsghdr *cmsg;
- struct ucred *ucred = NULL;
- bool found = false;
- Unit *u1, *u2, *u3;
- int *fd_array = NULL;
- unsigned n_fds = 0;
-
- n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
- if (n < 0) {
- if (errno == EAGAIN || errno == EINTR)
- break;
+ n = recvmsg(m->notify_fd, &msghdr, MSG_DONTWAIT|MSG_CMSG_CLOEXEC);
+ if (n < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ return 0;
- return -errno;
- }
+ return -errno;
+ }
- CMSG_FOREACH(cmsg, &msghdr) {
- if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
+ CMSG_FOREACH(cmsg, &msghdr) {
+ if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
- fd_array = (int*) CMSG_DATA(cmsg);
- n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
+ fd_array = (int*) CMSG_DATA(cmsg);
+ n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
- } else if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_CREDENTIALS &&
- cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
+ } else if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_CREDENTIALS &&
+ cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
- ucred = (struct ucred*) CMSG_DATA(cmsg);
- }
+ ucred = (struct ucred*) CMSG_DATA(cmsg);
}
+ }
- if (n_fds > 0) {
- assert(fd_array);
+ if (n_fds > 0) {
+ assert(fd_array);
- r = fdset_new_array(&fds, fd_array, n_fds);
- if (r < 0) {
- close_many(fd_array, n_fds);
- return log_oom();
- }
+ r = fdset_new_array(&fds, fd_array, n_fds);
+ if (r < 0) {
+ close_many(fd_array, n_fds);
+ return log_oom();
}
+ }
- if (!ucred || ucred->pid <= 0) {
- log_warning("Received notify message without valid credentials. Ignoring.");
- continue;
- }
+ if (!ucred || ucred->pid <= 0) {
+ log_warning("Received notify message without valid credentials. Ignoring.");
+ return 0;
+ }
- if ((size_t) n >= sizeof(buf)) {
- log_warning("Received notify message exceeded maximum size. Ignoring.");
- continue;
- }
+ if ((size_t) n >= sizeof(buf)) {
+ log_warning("Received notify message exceeded maximum size. Ignoring.");
+ return 0;
+ }
- buf[n] = 0;
+ buf[n] = 0;
- /* Notify every unit that might be interested, but try
- * to avoid notifying the same one multiple times. */
- u1 = manager_get_unit_by_pid_cgroup(m, ucred->pid);
- if (u1) {
- manager_invoke_notify_message(m, u1, ucred->pid, buf, n, fds);
- found = true;
- }
+ /* Notify every unit that might be interested, but try
+ * to avoid notifying the same one multiple times. */
+ u1 = manager_get_unit_by_pid_cgroup(m, ucred->pid);
+ if (u1) {
+ manager_invoke_notify_message(m, u1, ucred->pid, buf, n, fds);
+ found = true;
+ }
- u2 = hashmap_get(m->watch_pids1, PID_TO_PTR(ucred->pid));
- if (u2 && u2 != u1) {
- manager_invoke_notify_message(m, u2, ucred->pid, buf, n, fds);
- found = true;
- }
+ u2 = hashmap_get(m->watch_pids1, PID_TO_PTR(ucred->pid));
+ if (u2 && u2 != u1) {
+ manager_invoke_notify_message(m, u2, ucred->pid, buf, n, fds);
+ found = true;
+ }
- u3 = hashmap_get(m->watch_pids2, PID_TO_PTR(ucred->pid));
- if (u3 && u3 != u2 && u3 != u1) {
- manager_invoke_notify_message(m, u3, ucred->pid, buf, n, fds);
- found = true;
- }
+ u3 = hashmap_get(m->watch_pids2, PID_TO_PTR(ucred->pid));
+ if (u3 && u3 != u2 && u3 != u1) {
+ manager_invoke_notify_message(m, u3, ucred->pid, buf, n, fds);
+ found = true;
+ }
- if (!found)
- log_warning("Cannot find unit for notify message of PID "PID_FMT".", ucred->pid);
+ if (!found)
+ log_warning("Cannot find unit for notify message of PID "PID_FMT".", ucred->pid);
- if (fdset_size(fds) > 0)
- log_warning("Got auxiliary fds with notification message, closing all.");
- }
+ if (fdset_size(fds) > 0)
+ log_warning("Got auxiliary fds with notification message, closing all.");
return 0;
}
-static void invoke_sigchld_event(Manager *m, Unit *u, siginfo_t *si) {
+static void invoke_sigchld_event(Manager *m, Unit *u, const siginfo_t *si) {
assert(m);
assert(u);
assert(si);
@@ -1687,7 +1705,7 @@ static int manager_start_target(Manager *m, const char *name, JobMode mode) {
log_debug("Activating special unit %s", name);
- r = manager_add_job_by_name(m, JOB_START, name, mode, true, &error, NULL);
+ r = manager_add_job_by_name(m, JOB_START, name, mode, &error, NULL);
if (r < 0)
log_error("Failed to enqueue %s job: %s", name, bus_error_message(&error, r));
@@ -1990,8 +2008,7 @@ int manager_loop(Manager *m) {
m->exit_code = MANAGER_OK;
/* Release the path cache */
- set_free_free(m->unit_path_cache);
- m->unit_path_cache = NULL;
+ m->unit_path_cache = set_free_free(m->unit_path_cache);
manager_check_finished(m);
@@ -2011,7 +2028,6 @@ int manager_loop(Manager *m) {
/* 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)
@@ -2101,6 +2117,9 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
const char *msg;
int audit_fd, r;
+ if (m->running_as != MANAGER_SYSTEM)
+ return;
+
audit_fd = get_audit_fd();
if (audit_fd < 0)
return;
@@ -2110,9 +2129,6 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
if (m->n_reloading > 0)
return;
- if (m->running_as != MANAGER_SYSTEM)
- return;
-
if (u->type != UNIT_SERVICE)
return;
@@ -2542,9 +2558,7 @@ int manager_reload(Manager *m) {
manager_build_unit_path_cache(m);
/* First, enumerate what we can from all config files */
- q = manager_enumerate(m);
- if (q < 0 && r >= 0)
- r = q;
+ manager_enumerate(m);
/* Second, deserialize our stored data */
q = manager_deserialize(m, f, fds);
@@ -2761,8 +2775,7 @@ static int create_generator_dir(Manager *m, char **generator, const char *name)
return log_oom();
if (!mkdtemp(p)) {
- log_error_errno(errno, "Failed to create generator directory %s: %m",
- p);
+ log_error_errno(errno, "Failed to create generator directory %s: %m", p);
free(p);
return -errno;
}
@@ -2951,9 +2964,9 @@ void manager_set_show_status(Manager *m, ShowStatus mode) {
m->show_status = mode;
if (mode > 0)
- touch("/run/systemd/show-status");
+ (void) touch("/run/systemd/show-status");
else
- unlink("/run/systemd/show-status");
+ (void) unlink("/run/systemd/show-status");
}
static bool manager_get_show_status(Manager *m, StatusType type) {
@@ -3012,30 +3025,6 @@ void manager_status_printf(Manager *m, StatusType type, const char *status, cons
va_end(ap);
}
-int manager_get_unit_by_path(Manager *m, const char *path, const char *suffix, Unit **_found) {
- _cleanup_free_ char *p = NULL;
- Unit *found;
- int r;
-
- assert(m);
- assert(path);
- assert(suffix);
- assert(_found);
-
- r = unit_name_from_path(path, suffix, &p);
- if (r < 0)
- return r;
-
- found = manager_get_unit(m, p);
- if (!found) {
- *_found = NULL;
- return 0;
- }
-
- *_found = found;
- return 1;
-}
-
Set *manager_get_units_requiring_mounts_for(Manager *m, const char *path) {
char p[strlen(path)+1];
diff --git a/src/core/manager.h b/src/core/manager.h
index fad10aaacf..f6903a5c34 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -21,12 +21,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <libmount.h>
#include <stdbool.h>
#include <stdio.h>
-#include <libmount.h>
#include "sd-bus.h"
#include "sd-event.h"
+
#include "cgroup-util.h"
#include "fdset.h"
#include "hashmap.h"
@@ -141,8 +142,6 @@ struct Manager {
sd_event_source *jobs_in_progress_event_source;
- unsigned n_snapshots;
-
LookupPaths lookup_paths;
Set *unit_path_cache;
@@ -262,6 +261,7 @@ struct Manager {
bool default_blockio_accounting;
bool default_tasks_accounting;
+ uint64_t default_tasks_max;
usec_t default_timer_accuracy_usec;
struct rlimit *rlimit[_RLIMIT_MAX];
@@ -316,22 +316,21 @@ struct Manager {
int manager_new(ManagerRunningAs running_as, bool test_run, Manager **m);
Manager* manager_free(Manager *m);
-int manager_enumerate(Manager *m);
+void manager_enumerate(Manager *m);
int manager_startup(Manager *m, FILE *serialization, FDSet *fds);
Job *manager_get_job(Manager *m, uint32_t id);
Unit *manager_get_unit(Manager *m, const char *name);
-int manager_get_unit_by_path(Manager *m, const char *path, const char *suffix, Unit **_found);
-
int manager_get_job_from_dbus_path(Manager *m, const char *s, Job **_j);
int manager_load_unit_prepare(Manager *m, const char *name, const char *path, sd_bus_error *e, Unit **_ret);
int manager_load_unit(Manager *m, const char *name, const char *path, sd_bus_error *e, Unit **_ret);
int manager_load_unit_from_dbus_path(Manager *m, const char *s, sd_bus_error *e, Unit **_u);
-int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool force, sd_bus_error *e, Job **_ret);
-int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, bool force, sd_bus_error *e, Job **_ret);
+int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, sd_bus_error *e, Job **_ret);
+int manager_add_job_by_name(Manager *m, JobType type, const char *name, JobMode mode, sd_bus_error *e, Job **_ret);
+int manager_add_job_by_name_and_warn(Manager *m, JobType type, const char *name, JobMode mode, Job **ret);
void manager_dump_units(Manager *s, FILE *f, const char *prefix);
void manager_dump_jobs(Manager *s, FILE *f, const char *prefix);
diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c
index 9b16eaa0e2..2b8d590ed1 100644
--- a/src/core/mount-setup.c
+++ b/src/core/mount-setup.c
@@ -19,28 +19,31 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/mount.h>
#include <errno.h>
+#include <ftw.h>
#include <stdlib.h>
+#include <sys/mount.h>
#include <unistd.h>
-#include <ftw.h>
-#include "mount-setup.h"
-#include "dev-setup.h"
+#include "alloc-util.h"
#include "bus-util.h"
+#include "cgroup-util.h"
+#include "dev-setup.h"
+#include "efivars.h"
+#include "label.h"
#include "log.h"
#include "macro.h"
-#include "util.h"
-#include "label.h"
-#include "set.h"
-#include "strv.h"
+#include "missing.h"
#include "mkdir.h"
+#include "mount-setup.h"
+#include "mount-util.h"
#include "path-util.h"
-#include "missing.h"
-#include "virt.h"
-#include "efivars.h"
+#include "set.h"
#include "smack-util.h"
-#include "cgroup-util.h"
+#include "strv.h"
+#include "user-util.h"
+#include "util.h"
+#include "virt.h"
typedef enum MountMode {
MNT_NONE = 0,
diff --git a/src/core/mount.c b/src/core/mount.c
index a74f116657..9b44357e90 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -20,25 +20,33 @@
***/
#include <errno.h>
+#include <signal.h>
#include <stdio.h>
#include <sys/epoll.h>
-#include <signal.h>
-#include "manager.h"
-#include "unit.h"
-#include "mount.h"
-#include "log.h"
#include "sd-messages.h"
-#include "strv.h"
-#include "mkdir.h"
-#include "path-util.h"
-#include "mount-setup.h"
-#include "unit-name.h"
+
+#include "alloc-util.h"
#include "dbus-mount.h"
-#include "special.h"
+#include "escape.h"
#include "exit-status.h"
-#include "fstab-util.h"
#include "formats-util.h"
+#include "fstab-util.h"
+#include "log.h"
+#include "manager.h"
+#include "mkdir.h"
+#include "mount-setup.h"
+#include "mount-util.h"
+#include "mount.h"
+#include "parse-util.h"
+#include "path-util.h"
+#include "process-util.h"
+#include "special.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "unit-name.h"
+#include "unit.h"
#define RETRY_UMOUNT_MAX 32
@@ -246,9 +254,10 @@ static int mount_add_mount_links(Mount *m) {
if (!path_equal(m->where, "/")) {
/* Adds in links to other mount points that might lie further
* up in the hierarchy */
- r = path_get_parent(m->where, &parent);
- if (r < 0)
- return r;
+
+ parent = dirname_malloc(m->where);
+ if (!parent)
+ return -ENOMEM;
r = unit_require_mounts_for(UNIT(m), parent);
if (r < 0)
@@ -376,12 +385,15 @@ static bool should_umount(Mount *m) {
}
static int mount_add_default_dependencies(Mount *m) {
- const char *after, *after2, *online;
MountParameters *p;
+ const char *after;
int r;
assert(m);
+ if (!UNIT(m)->default_dependencies)
+ return 0;
+
if (UNIT(m)->manager->running_as != MANAGER_SYSTEM)
return 0;
@@ -402,30 +414,34 @@ static int mount_add_default_dependencies(Mount *m) {
return 0;
if (mount_is_network(p)) {
- after = SPECIAL_REMOTE_FS_PRE_TARGET;
- after2 = SPECIAL_NETWORK_TARGET;
- online = SPECIAL_NETWORK_ONLINE_TARGET;
- } else {
- after = SPECIAL_LOCAL_FS_PRE_TARGET;
- after2 = NULL;
- online = NULL;
- }
-
- r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, NULL, true);
- if (r < 0)
- return r;
+ /* We order ourselves after network.target. This is
+ * primarily useful at shutdown: services that take
+ * down the network should order themselves before
+ * network.target, so that they are shut down only
+ * after this mount unit is stopped. */
- if (after2) {
- r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after2, NULL, true);
+ r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, SPECIAL_NETWORK_TARGET, NULL, true);
if (r < 0)
return r;
- }
- if (online) {
- r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, online, NULL, true);
+ /* We pull in network-online.target, and order
+ * ourselves after it. This is useful at start-up to
+ * actively pull in tools that want to be started
+ * before we start mounting network file systems, and
+ * whose purpose it is to delay this until the network
+ * is "up". */
+
+ r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_WANTS, UNIT_AFTER, SPECIAL_NETWORK_ONLINE_TARGET, NULL, true);
if (r < 0)
return r;
- }
+
+ after = SPECIAL_REMOTE_FS_PRE_TARGET;
+ } else
+ after = SPECIAL_LOCAL_FS_PRE_TARGET;
+
+ r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, NULL, true);
+ if (r < 0)
+ return r;
if (should_umount(m)) {
r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true);
@@ -522,11 +538,9 @@ static int mount_add_extras(Mount *m) {
if (r < 0)
return r;
- if (u->default_dependencies) {
- r = mount_add_default_dependencies(m);
- if (r < 0)
- return r;
- }
+ r = mount_add_default_dependencies(m);
+ if (r < 0)
+ return r;
return 0;
}
@@ -621,19 +635,19 @@ static int mount_coldplug(Unit *u) {
if (new_state == m->state)
return 0;
- if (new_state == MOUNT_MOUNTING ||
- new_state == MOUNT_MOUNTING_DONE ||
- new_state == MOUNT_REMOUNTING ||
- new_state == MOUNT_UNMOUNTING ||
- new_state == MOUNT_MOUNTING_SIGTERM ||
- new_state == MOUNT_MOUNTING_SIGKILL ||
- new_state == MOUNT_UNMOUNTING_SIGTERM ||
- new_state == MOUNT_UNMOUNTING_SIGKILL ||
- new_state == MOUNT_REMOUNTING_SIGTERM ||
- new_state == MOUNT_REMOUNTING_SIGKILL) {
-
- if (m->control_pid <= 0)
- return -EBADMSG;
+ if (m->control_pid > 0 &&
+ pid_is_unwaited(m->control_pid) &&
+ IN_SET(new_state,
+ MOUNT_MOUNTING,
+ MOUNT_MOUNTING_DONE,
+ MOUNT_REMOUNTING,
+ MOUNT_UNMOUNTING,
+ MOUNT_MOUNTING_SIGTERM,
+ MOUNT_MOUNTING_SIGKILL,
+ MOUNT_UNMOUNTING_SIGTERM,
+ MOUNT_UNMOUNTING_SIGKILL,
+ MOUNT_REMOUNTING_SIGTERM,
+ MOUNT_REMOUNTING_SIGKILL)) {
r = unit_watch_pid(UNIT(m), m->control_pid);
if (r < 0)
@@ -694,6 +708,9 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
.apply_chroot = true,
.apply_tty_stdin = true,
.bus_endpoint_fd = -1,
+ .stdin_fd = -1,
+ .stdout_fd = -1,
+ .stderr_fd = -1,
};
assert(m);
@@ -849,6 +866,11 @@ fail:
mount_enter_mounted(m, MOUNT_FAILURE_RESOURCES);
}
+static int mount_get_opts(Mount *m, char **ret) {
+ return fstab_filter_options(m->parameters_fragment.options,
+ "nofail\0" "noauto\0" "auto\0", NULL, NULL, ret);
+}
+
static void mount_enter_mounting(Mount *m) {
int r;
MountParameters *p;
@@ -874,8 +896,7 @@ static void mount_enter_mounting(Mount *m) {
if (m->from_fragment) {
_cleanup_free_ char *opts = NULL;
- r = fstab_filter_options(m->parameters_fragment.options,
- "nofail\0" "noauto\0" "auto\0", NULL, NULL, &opts);
+ r = mount_get_opts(m, &opts);
if (r < 0)
goto fail;
@@ -1556,7 +1577,7 @@ static int mount_get_timeout(Unit *u, uint64_t *timeout) {
return 1;
}
-static int mount_enumerate(Manager *m) {
+static void mount_enumerate(Manager *m) {
int r;
assert(m);
@@ -1568,29 +1589,40 @@ static int mount_enumerate(Manager *m) {
m->mount_monitor = mnt_new_monitor();
if (!m->mount_monitor) {
- r = -ENOMEM;
+ log_oom();
goto fail;
}
r = mnt_monitor_enable_kernel(m->mount_monitor, 1);
- if (r < 0)
+ if (r < 0) {
+ log_error_errno(r, "Failed to enable watching of kernel mount events: %m");
goto fail;
+ }
+
r = mnt_monitor_enable_userspace(m->mount_monitor, 1, NULL);
- if (r < 0)
+ if (r < 0) {
+ log_error_errno(r, "Failed to enable watching of userspace mount events: %m");
goto fail;
+ }
/* mnt_unref_monitor() will close the fd */
fd = r = mnt_monitor_get_fd(m->mount_monitor);
- if (r < 0)
+ if (r < 0) {
+ log_error_errno(r, "Failed to acquire watch file descriptor: %m");
goto fail;
+ }
r = sd_event_add_io(m->event, &m->mount_event_source, fd, EPOLLIN, mount_dispatch_io, m);
- if (r < 0)
+ if (r < 0) {
+ log_error_errno(r, "Failed to watch mount file descriptor: %m");
goto fail;
+ }
r = sd_event_source_set_priority(m->mount_event_source, -10);
- if (r < 0)
+ if (r < 0) {
+ log_error_errno(r, "Failed to adjust mount watch priority: %m");
goto fail;
+ }
(void) sd_event_source_set_description(m->mount_event_source, "mount-monitor-dispatch");
}
@@ -1599,11 +1631,10 @@ static int mount_enumerate(Manager *m) {
if (r < 0)
goto fail;
- return 0;
+ return;
fail:
mount_shutdown(m);
- return r;
}
static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
diff --git a/src/core/mount.h b/src/core/mount.h
index 83d14ae713..9f78aa9075 100644
--- a/src/core/mount.h
+++ b/src/core/mount.h
@@ -23,8 +23,8 @@
typedef struct Mount Mount;
-#include "kill.h"
#include "execute.h"
+#include "kill.h"
typedef enum MountExecCommand {
MOUNT_EXEC_MOUNT,
diff --git a/src/core/namespace.c b/src/core/namespace.c
index 2b8b707df5..81ba09ea5d 100644
--- a/src/core/namespace.c
+++ b/src/core/namespace.c
@@ -20,23 +20,31 @@
***/
#include <errno.h>
-#include <sys/mount.h>
-#include <string.h>
+#include <sched.h>
#include <stdio.h>
-#include <unistd.h>
+#include <string.h>
+#include <sys/mount.h>
#include <sys/stat.h>
-#include <sched.h>
+#include <unistd.h>
#include <linux/fs.h>
-#include "strv.h"
-#include "util.h"
-#include "path-util.h"
-#include "missing.h"
-#include "loopback-setup.h"
+#include "alloc-util.h"
#include "dev-setup.h"
-#include "selinux-util.h"
-#include "namespace.h"
+#include "fd-util.h"
+#include "loopback-setup.h"
+#include "missing.h"
#include "mkdir.h"
+#include "mount-util.h"
+#include "namespace.h"
+#include "path-util.h"
+#include "selinux-util.h"
+#include "socket-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "umask-util.h"
+#include "user-util.h"
+#include "util.h"
typedef enum MountMode {
/* This is ordered by priority! */
diff --git a/src/core/path.c b/src/core/path.c
index 081ac2040d..02fb134bb9 100644
--- a/src/core/path.c
+++ b/src/core/path.c
@@ -19,20 +19,26 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/inotify.h>
-#include <sys/epoll.h>
#include <errno.h>
+#include <sys/epoll.h>
+#include <sys/inotify.h>
#include <unistd.h>
-#include "unit.h"
-#include "unit-name.h"
-#include "path.h"
-#include "mkdir.h"
+#include "bus-error.h"
+#include "bus-util.h"
#include "dbus-path.h"
-#include "special.h"
+#include "fd-util.h"
+#include "fs-util.h"
+#include "glob-util.h"
#include "macro.h"
-#include "bus-util.h"
-#include "bus-error.h"
+#include "mkdir.h"
+#include "path.h"
+#include "special.h"
+#include "stat-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "unit-name.h"
+#include "unit.h"
static const UnitActiveState state_translation_table[_PATH_STATE_MAX] = {
[PATH_DEAD] = UNIT_INACTIVE,
@@ -309,20 +315,20 @@ static int path_add_default_dependencies(Path *p) {
assert(p);
- r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE,
- SPECIAL_PATHS_TARGET, NULL, true);
+ if (!UNIT(p)->default_dependencies)
+ return 0;
+
+ r = unit_add_dependency_by_name(UNIT(p), UNIT_BEFORE, SPECIAL_PATHS_TARGET, NULL, true);
if (r < 0)
return r;
if (UNIT(p)->manager->running_as == MANAGER_SYSTEM) {
- r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES,
- SPECIAL_SYSINIT_TARGET, NULL, true);
+ r = unit_add_two_dependencies_by_name(UNIT(p), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
if (r < 0)
return r;
}
- return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS,
- SPECIAL_SHUTDOWN_TARGET, NULL, true);
+ return unit_add_two_dependencies_by_name(UNIT(p), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
}
static int path_load(Unit *u) {
@@ -354,11 +360,9 @@ static int path_load(Unit *u) {
if (r < 0)
return r;
- if (UNIT(p)->default_dependencies) {
- r = path_add_default_dependencies(p);
- if (r < 0)
- return r;
- }
+ r = path_add_default_dependencies(p);
+ if (r < 0)
+ return r;
}
return path_verify(p);
@@ -470,8 +474,7 @@ static void path_enter_running(Path *p) {
if (unit_stop_pending(UNIT(p)))
return;
- r = manager_add_job(UNIT(p)->manager, JOB_START, UNIT_TRIGGER(UNIT(p)),
- JOB_REPLACE, true, &error, NULL);
+ r = manager_add_job(UNIT(p)->manager, JOB_START, UNIT_TRIGGER(UNIT(p)), JOB_REPLACE, &error, NULL);
if (r < 0)
goto fail;
diff --git a/src/core/scope.c b/src/core/scope.c
index 7325e3601b..1953af1f88 100644
--- a/src/core/scope.c
+++ b/src/core/scope.c
@@ -22,14 +22,17 @@
#include <errno.h>
#include <unistd.h>
+#include "alloc-util.h"
+#include "dbus-scope.h"
+#include "load-dropin.h"
#include "log.h"
-#include "strv.h"
+#include "scope.h"
#include "special.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
#include "unit-name.h"
#include "unit.h"
-#include "scope.h"
-#include "dbus-scope.h"
-#include "load-dropin.h"
static const UnitActiveState state_translation_table[_SCOPE_STATE_MAX] = {
[SCOPE_DEAD] = UNIT_INACTIVE,
@@ -51,7 +54,6 @@ static void scope_init(Unit *u) {
s->timeout_stop_usec = u->manager->default_timeout_stop_usec;
UNIT(s)->ignore_on_isolate = true;
- UNIT(s)->ignore_on_snapshot = true;
}
static void scope_done(Unit *u) {
@@ -120,6 +122,9 @@ static int scope_add_default_dependencies(Scope *s) {
assert(s);
+ if (!UNIT(s)->default_dependencies)
+ return 0;
+
/* Make sure scopes are unloaded on shutdown */
r = unit_add_two_dependencies_by_name(
UNIT(s),
@@ -171,11 +176,9 @@ static int scope_load(Unit *u) {
if (r < 0)
return r;
- if (u->default_dependencies) {
- r = scope_add_default_dependencies(s);
- if (r < 0)
- return r;
- }
+ r = scope_add_default_dependencies(s);
+ if (r < 0)
+ return r;
return scope_verify(s);
}
@@ -399,15 +402,10 @@ static bool scope_check_gc(Unit *u) {
/* Never clean up scopes that still have a process around,
* even if the scope is formally dead. */
- if (u->cgroup_path) {
- int r;
+ if (!u->cgroup_path)
+ return false;
- r = cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path);
- if (r <= 0)
- return true;
- }
-
- return false;
+ return cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path) <= 0;
}
static void scope_notify_cgroup_empty_event(Unit *u) {
@@ -507,7 +505,7 @@ _pure_ static const char *scope_sub_state_to_string(Unit *u) {
return scope_state_to_string(SCOPE(u)->state);
}
-static int scope_enumerate(Manager *m) {
+static void scope_enumerate(Manager *m) {
Unit *u;
int r;
@@ -521,19 +519,25 @@ static int scope_enumerate(Manager *m) {
u = manager_get_unit(m, SPECIAL_INIT_SCOPE);
if (!u) {
u = unit_new(m, sizeof(Scope));
- if (!u)
- return log_oom();
+ if (!u) {
+ log_oom();
+ return;
+ }
r = unit_add_name(u, SPECIAL_INIT_SCOPE);
if (r < 0) {
unit_free(u);
- return log_error_errno(r, "Failed to add init.scope name");
+ log_error_errno(r, "Failed to add init.scope name");
+ return;
}
}
u->transient = true;
u->default_dependencies = false;
u->no_gc = true;
+ u->ignore_on_isolate = true;
+ u->refuse_manual_start = true;
+ u->refuse_manual_stop = true;
SCOPE(u)->deserialized_state = SCOPE_RUNNING;
SCOPE(u)->kill_context.kill_signal = SIGRTMIN+14;
@@ -545,8 +549,6 @@ static int scope_enumerate(Manager *m) {
unit_add_to_load_queue(u);
unit_add_to_dbus_queue(u);
-
- return 0;
}
static const char* const scope_result_table[_SCOPE_RESULT_MAX] = {
@@ -570,6 +572,7 @@ const UnitVTable scope_vtable = {
.no_alias = true,
.no_instances = true,
+ .can_transient = true,
.init = scope_init,
.load = scope_load,
@@ -604,7 +607,5 @@ const UnitVTable scope_vtable = {
.bus_set_property = bus_scope_set_property,
.bus_commit_properties = bus_scope_commit_properties,
- .can_transient = true,
-
.enumerate = scope_enumerate,
};
diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c
index 40ca0c6166..8856927c88 100644
--- a/src/core/selinux-access.c
+++ b/src/core/selinux-access.c
@@ -23,22 +23,25 @@
#ifdef HAVE_SELINUX
-#include <stdio.h>
#include <errno.h>
-#include <selinux/selinux.h>
#include <selinux/avc.h>
+#include <selinux/selinux.h>
+#include <stdio.h>
#ifdef HAVE_AUDIT
#include <libaudit.h>
#endif
#include "sd-bus.h"
+
+#include "alloc-util.h"
+#include "audit-fd.h"
#include "bus-util.h"
-#include "util.h"
#include "log.h"
+#include "path-util.h"
#include "selinux-util.h"
-#include "audit-fd.h"
+#include "stdio-util.h"
#include "strv.h"
-#include "path-util.h"
+#include "util.h"
static bool initialized = false;
@@ -178,17 +181,6 @@ static int mac_selinux_access_init(sd_bus_error *error) {
}
#endif
-void mac_selinux_access_free(void) {
-
-#ifdef HAVE_SELINUX
- if (!initialized)
- return;
-
- avc_destroy();
- initialized = false;
-#endif
-}
-
/*
This function communicates with the kernel to check whether or not it should
allow the access.
diff --git a/src/core/selinux-access.h b/src/core/selinux-access.h
index e6b4dd7fee..3566ba529f 100644
--- a/src/core/selinux-access.h
+++ b/src/core/selinux-access.h
@@ -22,11 +22,10 @@
***/
#include "sd-bus.h"
+
#include "bus-util.h"
#include "manager.h"
-void mac_selinux_access_free(void);
-
int mac_selinux_generic_access_check(sd_bus_message *message, const char *path, const char *permission, sd_bus_error *error);
#ifdef HAVE_SELINUX
diff --git a/src/core/selinux-setup.c b/src/core/selinux-setup.c
index ff1ea23528..d4757e0853 100644
--- a/src/core/selinux-setup.c
+++ b/src/core/selinux-setup.c
@@ -19,19 +19,20 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
-#include <stdio.h>
#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
#endif
+#include "log.h"
+#include "macro.h"
#include "selinux-setup.h"
#include "selinux-util.h"
-#include "macro.h"
+#include "string-util.h"
#include "util.h"
-#include "log.h"
#ifdef HAVE_SELINUX
_printf_(2,3)
diff --git a/src/core/service.c b/src/core/service.c
index cb0394f930..c27b70fa3c 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -23,31 +23,38 @@
#include <signal.h>
#include <unistd.h>
+#include "alloc-util.h"
#include "async.h"
-#include "manager.h"
-#include "unit.h"
-#include "service.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
-#include "log.h"
-#include "strv.h"
-#include "unit-name.h"
-#include "unit-printf.h"
+#include "bus-error.h"
+#include "bus-kernel.h"
+#include "bus-util.h"
#include "dbus-service.h"
-#include "special.h"
-#include "exit-status.h"
#include "def.h"
-#include "path-util.h"
-#include "util.h"
-#include "utf8.h"
#include "env-util.h"
+#include "escape.h"
+#include "exit-status.h"
+#include "fd-util.h"
#include "fileio.h"
-#include "bus-error.h"
-#include "bus-util.h"
-#include "bus-kernel.h"
#include "formats-util.h"
+#include "fs-util.h"
+#include "load-dropin.h"
+#include "load-fragment.h"
+#include "log.h"
+#include "manager.h"
+#include "parse-util.h"
+#include "path-util.h"
#include "process-util.h"
+#include "service.h"
#include "signal-util.h"
+#include "special.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
+#include "unit-name.h"
+#include "unit-printf.h"
+#include "unit.h"
+#include "utf8.h"
+#include "util.h"
static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
[SERVICE_DEAD] = UNIT_INACTIVE,
@@ -108,6 +115,7 @@ static void service_init(Unit *u) {
s->type = _SERVICE_TYPE_INVALID;
s->socket_fd = -1;
s->bus_endpoint_fd = -1;
+ s->stdin_fd = s->stdout_fd = s->stderr_fd = -1;
s->guess_main_pid = true;
RATELIMIT_INIT(s->start_limit, u->manager->default_start_limit_interval, u->manager->default_start_limit_burst);
@@ -167,7 +175,7 @@ static int service_set_main_pid(Service *s, pid_t pid) {
s->main_pid = pid;
s->main_pid_known = true;
- if (get_parent_of_pid(pid, &ppid) >= 0 && ppid != getpid()) {
+ if (get_process_ppid(pid, &ppid) >= 0 && ppid != getpid()) {
log_unit_warning(UNIT(s), "Supervising process "PID_FMT" which is not our child. We'll most likely not notice when it exits.", pid);
s->main_pid_alien = true;
} else
@@ -261,6 +269,7 @@ static void service_fd_store_unlink(ServiceFDStore *fs) {
sd_event_source_unref(fs->event_source);
}
+ free(fs->fdname);
safe_close(fs->fd);
free(fs);
}
@@ -270,11 +279,15 @@ static void service_release_resources(Unit *u) {
assert(s);
- if (!s->fd_store)
+ if (!s->fd_store && s->stdin_fd < 0 && s->stdout_fd < 0 && s->stderr_fd < 0)
return;
log_unit_debug(u, "Releasing all resources.");
+ s->stdin_fd = safe_close(s->stdin_fd);
+ s->stdout_fd = safe_close(s->stdout_fd);
+ s->stderr_fd = safe_close(s->stderr_fd);
+
while (s->fd_store)
service_fd_store_unlink(s->fd_store);
@@ -334,7 +347,7 @@ static int on_fd_store_io(sd_event_source *e, int fd, uint32_t revents, void *us
return 0;
}
-static int service_add_fd_store(Service *s, int fd) {
+static int service_add_fd_store(Service *s, int fd, const char *name) {
ServiceFDStore *fs;
int r;
@@ -361,9 +374,15 @@ static int service_add_fd_store(Service *s, int fd) {
fs->fd = fd;
fs->service = s;
+ fs->fdname = strdup(name ?: "stored");
+ if (!fs->fdname) {
+ free(fs);
+ return -ENOMEM;
+ }
r = sd_event_add_io(UNIT(s)->manager->event, &fs->event_source, fd, 0, on_fd_store_io, fs);
if (r < 0) {
+ free(fs->fdname);
free(fs);
return r;
}
@@ -376,7 +395,7 @@ static int service_add_fd_store(Service *s, int fd) {
return 1;
}
-static int service_add_fd_store_set(Service *s, FDSet *fds) {
+static int service_add_fd_store_set(Service *s, FDSet *fds, const char *name) {
int r;
assert(s);
@@ -391,7 +410,7 @@ static int service_add_fd_store_set(Service *s, FDSet *fds) {
if (fd < 0)
break;
- r = service_add_fd_store(s, fd);
+ r = service_add_fd_store(s, fd, name);
if (r < 0)
return log_unit_error_errno(UNIT(s), r, "Couldn't add fd to fd store: %m");
if (r > 0) {
@@ -401,7 +420,7 @@ static int service_add_fd_store_set(Service *s, FDSet *fds) {
}
if (fdset_size(fds) > 0)
- log_unit_warning(UNIT(s), "Tried to store more fds than FDStoreMax=%u allows, closing remaining.", s->n_fd_store_max);
+ log_unit_warning(UNIT(s), "Tried to store more fds than FileDescriptorStoreMax=%u allows, closing remaining.", s->n_fd_store_max);
return 0;
}
@@ -496,15 +515,38 @@ static int service_add_default_dependencies(Service *s) {
assert(s);
+ if (!UNIT(s)->default_dependencies)
+ return 0;
+
/* Add a number of automatic dependencies useful for the
* majority of services. */
- /* First, pull in base system */
- r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true);
+ if (UNIT(s)->manager->running_as == MANAGER_SYSTEM) {
+ /* First, pull in the really early boot stuff, and
+ * require it, so that we fail if we can't acquire
+ * it. */
+
+ r = unit_add_two_dependencies_by_name(UNIT(s), UNIT_AFTER, UNIT_REQUIRES, SPECIAL_SYSINIT_TARGET, NULL, true);
+ if (r < 0)
+ return r;
+ } else {
+
+ /* In the --user instance there's no sysinit.target,
+ * in that case require basic.target instead. */
+
+ r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_BASIC_TARGET, NULL, true);
+ if (r < 0)
+ return r;
+ }
+
+ /* Second, if the rest of the base system is in the same
+ * transaction, order us after it, but do not pull it in or
+ * even require it. */
+ r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_BASIC_TARGET, NULL, true);
if (r < 0)
return r;
- /* Second, activate normal shutdown */
+ /* Third, add us in for normal shutdown. */
return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
}
@@ -526,6 +568,43 @@ static void service_fix_output(Service *s) {
s->exec_context.std_output = UNIT(s)->manager->default_std_output;
}
+static int service_setup_bus_name(Service *s) {
+ int r;
+
+ assert(s);
+
+ if (!s->bus_name)
+ return 0;
+
+ if (is_kdbus_available()) {
+ const char *n;
+
+ n = strjoina(s->bus_name, ".busname");
+ r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, n, NULL, true);
+ if (r < 0)
+ return log_unit_error_errno(UNIT(s), r, "Failed to add dependency to .busname unit: %m");
+
+ } else {
+ /* If kdbus is not available, we know the dbus socket is required, hence pull it in, and require it */
+ r = unit_add_dependency_by_name(UNIT(s), UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true);
+ if (r < 0)
+ return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m");
+ }
+
+ /* Regardless if kdbus is used or not, we always want to be ordered against dbus.socket if both are in the transaction. */
+ r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, SPECIAL_DBUS_SOCKET, NULL, true);
+ if (r < 0)
+ return log_unit_error_errno(UNIT(s), r, "Failed to add dependency on " SPECIAL_DBUS_SOCKET ": %m");
+
+ r = unit_watch_bus_name(UNIT(s), s->bus_name);
+ if (r == -EEXIST)
+ return log_unit_error_errno(UNIT(s), r, "Two services allocated for the same bus name %s, refusing operation.", s->bus_name);
+ if (r < 0)
+ return log_unit_error_errno(UNIT(s), r, "Cannot watch bus name %s: %m", s->bus_name);
+
+ return 0;
+}
+
static int service_add_extras(Service *s) {
int r;
@@ -565,26 +644,13 @@ static int service_add_extras(Service *s) {
if (s->watchdog_usec > 0 && s->notify_access == NOTIFY_NONE)
s->notify_access = NOTIFY_MAIN;
- if (s->bus_name) {
- const char *n;
-
- n = strjoina(s->bus_name, ".busname");
- r = unit_add_dependency_by_name(UNIT(s), UNIT_AFTER, n, NULL, true);
- if (r < 0)
- return r;
-
- r = unit_watch_bus_name(UNIT(s), s->bus_name);
- if (r == -EEXIST)
- return log_unit_error_errno(UNIT(s), r, "Two services allocated for the same bus name %s, refusing operation.", s->bus_name);
- if (r < 0)
- return log_unit_error_errno(UNIT(s), r, "Cannot watch bus name %s: %m", s->bus_name);
- }
+ r = service_add_default_dependencies(s);
+ if (r < 0)
+ return r;
- if (UNIT(s)->default_dependencies) {
- r = service_add_default_dependencies(s);
- if (r < 0)
- return r;
- }
+ r = service_setup_bus_name(s);
+ if (r < 0)
+ return r;
return 0;
}
@@ -884,7 +950,6 @@ static void service_set_state(Service *s, ServiceState state) {
log_unit_debug(UNIT(s), "Changed %s -> %s", service_state_to_string(old_state), service_state_to_string(state));
unit_notify(UNIT(s), table[old_state], table[state], s->reload_result == SERVICE_SUCCESS);
- s->reload_result = SERVICE_SUCCESS;
}
static int service_coldplug(Unit *u) {
@@ -894,125 +959,143 @@ static int service_coldplug(Unit *u) {
assert(s);
assert(s->state == SERVICE_DEAD);
- if (s->deserialized_state != s->state) {
-
- if (IN_SET(s->deserialized_state,
- SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
- SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
+ if (s->deserialized_state == s->state)
+ return 0;
- usec_t k;
+ if (IN_SET(s->deserialized_state,
+ SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
+ SERVICE_RELOAD,
+ SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
+ SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
- k = IN_SET(s->deserialized_state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD) ? s->timeout_start_usec : s->timeout_stop_usec;
+ usec_t k;
- /* For the start/stop timeouts 0 means off */
- if (k > 0) {
- r = service_arm_timer(s, k);
- if (r < 0)
- return r;
- }
- }
+ k = IN_SET(s->deserialized_state, SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST, SERVICE_RELOAD) ? s->timeout_start_usec : s->timeout_stop_usec;
- if (s->deserialized_state == SERVICE_AUTO_RESTART) {
-
- /* The restart timeouts 0 means immediately */
- r = service_arm_timer(s, s->restart_usec);
+ /* For the start/stop timeouts 0 means off */
+ if (k > 0) {
+ r = service_arm_timer(s, k);
if (r < 0)
return r;
}
+ }
- if (pid_is_unwaited(s->main_pid) &&
- ((s->deserialized_state == SERVICE_START && IN_SET(s->type, SERVICE_FORKING, SERVICE_DBUS, SERVICE_ONESHOT, SERVICE_NOTIFY)) ||
- IN_SET(s->deserialized_state,
- SERVICE_START, SERVICE_START_POST,
- SERVICE_RUNNING, SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) {
- r = unit_watch_pid(UNIT(s), s->main_pid);
- if (r < 0)
- return r;
- }
+ if (s->deserialized_state == SERVICE_AUTO_RESTART) {
- if (pid_is_unwaited(s->control_pid) &&
- IN_SET(s->deserialized_state,
- SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
- SERVICE_RELOAD,
- SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
- SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
- r = unit_watch_pid(UNIT(s), s->control_pid);
- if (r < 0)
- return r;
- }
-
- if (!IN_SET(s->deserialized_state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART))
- unit_watch_all_pids(UNIT(s));
+ /* The restart timeouts 0 means immediately */
+ r = service_arm_timer(s, s->restart_usec);
+ if (r < 0)
+ return r;
+ }
- if (IN_SET(s->deserialized_state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
- service_start_watchdog(s);
+ if (s->main_pid > 0 &&
+ pid_is_unwaited(s->main_pid) &&
+ ((s->deserialized_state == SERVICE_START && IN_SET(s->type, SERVICE_FORKING, SERVICE_DBUS, SERVICE_ONESHOT, SERVICE_NOTIFY)) ||
+ IN_SET(s->deserialized_state,
+ SERVICE_START, SERVICE_START_POST,
+ SERVICE_RUNNING, SERVICE_RELOAD,
+ SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
+ SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) {
+ r = unit_watch_pid(UNIT(s), s->main_pid);
+ if (r < 0)
+ return r;
+ }
- service_set_state(s, s->deserialized_state);
+ if (s->control_pid > 0 &&
+ pid_is_unwaited(s->control_pid) &&
+ IN_SET(s->deserialized_state,
+ SERVICE_START_PRE, SERVICE_START, SERVICE_START_POST,
+ SERVICE_RELOAD,
+ SERVICE_STOP, SERVICE_STOP_SIGABRT, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
+ SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) {
+ r = unit_watch_pid(UNIT(s), s->control_pid);
+ if (r < 0)
+ return r;
}
+ if (!IN_SET(s->deserialized_state, SERVICE_DEAD, SERVICE_FAILED, SERVICE_AUTO_RESTART))
+ unit_watch_all_pids(UNIT(s));
+
+ if (IN_SET(s->deserialized_state, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD))
+ service_start_watchdog(s);
+
+ service_set_state(s, s->deserialized_state);
return 0;
}
-static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
+static int service_collect_fds(Service *s, int **fds, char ***fd_names) {
+ _cleanup_strv_free_ char **rfd_names = NULL;
_cleanup_free_ int *rfds = NULL;
- unsigned rn_fds = 0;
- Iterator i;
- int r;
- Unit *u;
+ int rn_fds = 0, r;
assert(s);
assert(fds);
- assert(n_fds);
+ assert(fd_names);
- if (s->socket_fd >= 0)
- return 0;
+ if (s->socket_fd >= 0) {
- SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) {
- int *cfds;
- unsigned cn_fds;
- Socket *sock;
+ /* Pass the per-connection socket */
- if (u->type != UNIT_SOCKET)
- continue;
+ rfds = new(int, 1);
+ if (!rfds)
+ return -ENOMEM;
+ rfds[0] = s->socket_fd;
- sock = SOCKET(u);
+ rfd_names = strv_new("connection", NULL);
+ if (!rfd_names)
+ return -ENOMEM;
- r = socket_collect_fds(sock, &cfds, &cn_fds);
- if (r < 0)
- return r;
+ rn_fds = 1;
+ } else {
+ Iterator i;
+ Unit *u;
- if (cn_fds <= 0) {
- free(cfds);
- continue;
- }
+ /* Pass all our configured sockets for singleton services */
- if (!rfds) {
- rfds = cfds;
- rn_fds = cn_fds;
- } else {
- int *t;
+ SET_FOREACH(u, UNIT(s)->dependencies[UNIT_TRIGGERED_BY], i) {
+ _cleanup_free_ int *cfds = NULL;
+ Socket *sock;
+ int cn_fds;
- t = realloc(rfds, (rn_fds + cn_fds) * sizeof(int));
- if (!t) {
- free(cfds);
- return -ENOMEM;
- }
+ if (u->type != UNIT_SOCKET)
+ continue;
+
+ sock = SOCKET(u);
+
+ cn_fds = socket_collect_fds(sock, &cfds);
+ if (cn_fds < 0)
+ return cn_fds;
+
+ if (cn_fds <= 0)
+ continue;
- memcpy(t + rn_fds, cfds, cn_fds * sizeof(int));
- rfds = t;
- rn_fds += cn_fds;
+ if (!rfds) {
+ rfds = cfds;
+ rn_fds = cn_fds;
- free(cfds);
+ cfds = NULL;
+ } else {
+ int *t;
+ t = realloc(rfds, (rn_fds + cn_fds) * sizeof(int));
+ if (!t)
+ return -ENOMEM;
+
+ memcpy(t + rn_fds, cfds, cn_fds * sizeof(int));
+
+ rfds = t;
+ rn_fds += cn_fds;
+ }
+
+ r = strv_extend_n(&rfd_names, socket_fdname(sock), cn_fds);
+ if (r < 0)
+ return r;
}
}
if (s->n_fd_store > 0) {
ServiceFDStore *fs;
+ char **nl;
int *t;
t = realloc(rfds, (rn_fds + s->n_fd_store) * sizeof(int));
@@ -1020,15 +1103,32 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
return -ENOMEM;
rfds = t;
- LIST_FOREACH(fd_store, fs, s->fd_store)
- rfds[rn_fds++] = fs->fd;
+
+ nl = realloc(rfd_names, (rn_fds + s->n_fd_store + 1) * sizeof(char*));
+ if (!nl)
+ return -ENOMEM;
+
+ rfd_names = nl;
+
+ LIST_FOREACH(fd_store, fs, s->fd_store) {
+ rfds[rn_fds] = fs->fd;
+ rfd_names[rn_fds] = strdup(strempty(fs->fdname));
+ if (!rfd_names[rn_fds])
+ return -ENOMEM;
+
+ rn_fds++;
+ }
+
+ rfd_names[rn_fds] = NULL;
}
*fds = rfds;
- *n_fds = rn_fds;
+ *fd_names = rfd_names;
rfds = NULL;
- return 0;
+ rfd_names = NULL;
+
+ return rn_fds;
}
static int service_spawn(
@@ -1042,23 +1142,25 @@ static int service_spawn(
bool is_control,
pid_t *_pid) {
- pid_t pid;
- int r;
- int *fds = NULL;
- _cleanup_free_ int *fdsbuf = NULL;
- unsigned n_fds = 0, n_env = 0;
+ _cleanup_strv_free_ char **argv = NULL, **final_env = NULL, **our_env = NULL, **fd_names = NULL;
_cleanup_free_ char *bus_endpoint_path = NULL;
- _cleanup_strv_free_ char
- **argv = NULL, **final_env = NULL, **our_env = NULL;
+ _cleanup_free_ int *fds = NULL;
+ unsigned n_fds = 0, n_env = 0;
const char *path;
+ pid_t pid;
+
ExecParameters exec_params = {
- .apply_permissions = apply_permissions,
- .apply_chroot = apply_chroot,
- .apply_tty_stdin = apply_tty_stdin,
- .bus_endpoint_fd = -1,
- .selinux_context_net = s->socket_fd_selinux_context_net
+ .apply_permissions = apply_permissions,
+ .apply_chroot = apply_chroot,
+ .apply_tty_stdin = apply_tty_stdin,
+ .bus_endpoint_fd = -1,
+ .stdin_fd = -1,
+ .stdout_fd = -1,
+ .stderr_fd = -1,
};
+ int r;
+
assert(s);
assert(c);
assert(_pid);
@@ -1078,16 +1180,11 @@ static int service_spawn(
s->exec_context.std_output == EXEC_OUTPUT_SOCKET ||
s->exec_context.std_error == EXEC_OUTPUT_SOCKET) {
- if (s->socket_fd >= 0) {
- fds = &s->socket_fd;
- n_fds = 1;
- } else {
- r = service_collect_fds(s, &fdsbuf, &n_fds);
- if (r < 0)
- goto fail;
+ r = service_collect_fds(s, &fds, &fd_names);
+ if (r < 0)
+ goto fail;
- fds = fdsbuf;
- }
+ n_fds = r;
}
if (timeout > 0) {
@@ -1125,7 +1222,7 @@ static int service_spawn(
goto fail;
}
- if (UNIT_DEREF(s->accept_socket)) {
+ if (s->socket_fd >= 0) {
union sockaddr_union sa;
socklen_t salen = sizeof(sa);
@@ -1173,7 +1270,7 @@ static int service_spawn(
if (is_control && UNIT(s)->cgroup_path) {
path = strjoina(UNIT(s)->cgroup_path, "/control");
- cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
+ (void) cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
} else
path = UNIT(s)->cgroup_path;
@@ -1191,6 +1288,7 @@ static int service_spawn(
exec_params.argv = argv;
exec_params.fds = fds;
+ exec_params.fd_names = fd_names;
exec_params.n_fds = n_fds;
exec_params.environment = final_env;
exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn;
@@ -1200,8 +1298,12 @@ static int service_spawn(
exec_params.runtime_prefix = manager_get_runtime_prefix(UNIT(s)->manager);
exec_params.watchdog_usec = s->watchdog_usec;
exec_params.bus_endpoint_path = bus_endpoint_path;
+ exec_params.selinux_context_net = s->socket_fd_selinux_context_net;
if (s->type == SERVICE_IDLE)
exec_params.idle_pipe = UNIT(s)->manager->idle_pipe;
+ exec_params.stdin_fd = s->stdin_fd;
+ exec_params.stdout_fd = s->stdout_fd;
+ exec_params.stderr_fd = s->stderr_fd;
r = exec_spawn(UNIT(s),
c,
@@ -1747,7 +1849,7 @@ static void service_enter_restart(Service *s) {
* 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);
+ r = manager_add_job(UNIT(s)->manager, JOB_RESTART, UNIT(s), JOB_FAIL, &error, NULL);
if (r < 0)
goto fail;
@@ -1778,6 +1880,7 @@ static void service_enter_reload(Service *s) {
assert(s);
service_unwatch_control_pid(s);
+ s->reload_result = SERVICE_SUCCESS;
s->control_command = s->exec_command[SERVICE_EXEC_RELOAD];
if (s->control_command) {
@@ -2001,6 +2104,7 @@ _pure_ static bool service_can_reload(Unit *u) {
static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
Service *s = SERVICE(u);
ServiceFDStore *fs;
+ int r;
assert(u);
assert(f);
@@ -2019,12 +2123,9 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
unit_serialize_item(u, f, "main-pid-known", yes_no(s->main_pid_known));
unit_serialize_item(u, f, "bus-name-good", yes_no(s->bus_name_good));
- if (s->status_text) {
- _cleanup_free_ char *c = NULL;
-
- c = cescape(s->status_text);
- unit_serialize_item(u, f, "status-text", strempty(c));
- }
+ r = unit_serialize_item_escaped(u, f, "status-text", s->status_text);
+ if (r < 0)
+ return r;
/* FIXME: There's a minor uncleanliness here: if there are
* multiple commands attached here, we will start from the
@@ -2032,34 +2133,34 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
if (s->control_command_id >= 0)
unit_serialize_item(u, f, "control-command", service_exec_command_to_string(s->control_command_id));
- if (s->socket_fd >= 0) {
- int copy;
-
- copy = fdset_put_dup(fds, s->socket_fd);
- if (copy < 0)
- return copy;
-
- unit_serialize_item_format(u, f, "socket-fd", "%i", copy);
- }
-
- if (s->bus_endpoint_fd >= 0) {
- int copy;
-
- copy = fdset_put_dup(fds, s->bus_endpoint_fd);
- if (copy < 0)
- return copy;
+ r = unit_serialize_item_fd(u, f, fds, "stdin-fd", s->stdin_fd);
+ if (r < 0)
+ return r;
+ r = unit_serialize_item_fd(u, f, fds, "stdout-fd", s->stdout_fd);
+ if (r < 0)
+ return r;
+ r = unit_serialize_item_fd(u, f, fds, "stderr-fd", s->stderr_fd);
+ if (r < 0)
+ return r;
- unit_serialize_item_format(u, f, "endpoint-fd", "%i", copy);
- }
+ r = unit_serialize_item_fd(u, f, fds, "socket-fd", s->socket_fd);
+ if (r < 0)
+ return r;
+ r = unit_serialize_item_fd(u, f, fds, "endpoint-fd", s->bus_endpoint_fd);
+ if (r < 0)
+ return r;
LIST_FOREACH(fd_store, fs, s->fd_store) {
+ _cleanup_free_ char *c = NULL;
int copy;
copy = fdset_put_dup(fds, fs->fd);
if (copy < 0)
return copy;
- unit_serialize_item_format(u, f, "fd-store-fd", "%i", copy);
+ c = cescape(fs->fdname);
+
+ unit_serialize_item_format(u, f, "fd-store-fd", "%i %s", copy, strempty(c));
}
if (s->main_exec_status.pid > 0) {
@@ -2076,8 +2177,7 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
if (dual_timestamp_is_set(&s->watchdog_timestamp))
dual_timestamp_serialize(f, "watchdog-timestamp", &s->watchdog_timestamp);
- if (s->forbid_restart)
- unit_serialize_item(u, f, "forbid-restart", yes_no(s->forbid_restart));
+ unit_serialize_item(u, f, "forbid-restart", yes_no(s->forbid_restart));
return 0;
}
@@ -2189,12 +2289,24 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
s->bus_endpoint_fd = fdset_remove(fds, fd);
}
} else if (streq(key, "fd-store-fd")) {
+ const char *fdv;
+ size_t pf;
int fd;
- if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+ pf = strcspn(value, WHITESPACE);
+ fdv = strndupa(value, pf);
+
+ if (safe_atoi(fdv, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
log_unit_debug(u, "Failed to parse fd-store-fd value: %s", value);
else {
- r = service_add_fd_store(s, fd);
+ _cleanup_free_ char *t = NULL;
+ const char *fdn;
+
+ fdn = value + pf;
+ fdn += strspn(fdn, WHITESPACE);
+ (void) cunescape(fdn, 0, &t);
+
+ r = service_add_fd_store(s, fd, t);
if (r < 0)
log_unit_error_errno(u, r, "Failed to add fd to store: %m");
else if (r > 0)
@@ -2236,6 +2348,33 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
log_unit_debug(u, "Failed to parse forbid-restart value: %s", value);
else
s->forbid_restart = b;
+ } else if (streq(key, "stdin-fd")) {
+ int fd;
+
+ if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+ log_unit_debug(u, "Failed to parse stdin-fd value: %s", value);
+ else {
+ asynchronous_close(s->stdin_fd);
+ s->stdin_fd = fdset_remove(fds, fd);
+ }
+ } else if (streq(key, "stdout-fd")) {
+ int fd;
+
+ if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+ log_unit_debug(u, "Failed to parse stdout-fd value: %s", value);
+ else {
+ asynchronous_close(s->stdout_fd);
+ s->stdout_fd = fdset_remove(fds, fd);
+ }
+ } else if (streq(key, "stderr-fd")) {
+ int fd;
+
+ if (safe_atoi(value, &fd) < 0 || fd < 0 || !fdset_contains(fds, fd))
+ log_unit_debug(u, "Failed to parse stderr-fd value: %s", value);
+ else {
+ asynchronous_close(s->stderr_fd);
+ s->stderr_fd = fdset_remove(fds, fd);
+ }
} else
log_unit_debug(u, "Unknown serialization key: %s", key);
@@ -2273,14 +2412,6 @@ static bool service_check_gc(Unit *u) {
return false;
}
-_pure_ static bool service_check_snapshot(Unit *u) {
- Service *s = SERVICE(u);
-
- assert(s);
-
- return s->socket_fd < 0;
-}
-
static int service_retry_pid_file(Service *s) {
int r;
@@ -2948,8 +3079,17 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds)
if (strv_find(tags, "WATCHDOG=1"))
service_reset_watchdog(s);
- if (strv_find(tags, "FDSTORE=1"))
- service_add_fd_store_set(s, fds);
+ if (strv_find(tags, "FDSTORE=1")) {
+ const char *name;
+
+ name = strv_find_startswith(tags, "FDNAME=");
+ if (name && !fdname_is_valid(name)) {
+ log_unit_warning(u, "Passed FDNAME= name is invalid, ignoring.");
+ name = NULL;
+ }
+
+ service_add_fd_store_set(s, fds, name);
+ }
/* Notify clients about changed status or main pid */
if (notify_dbus)
@@ -3193,7 +3333,6 @@ const UnitVTable service_vtable = {
.sub_state_to_string = service_sub_state_to_string,
.check_gc = service_check_gc,
- .check_snapshot = service_check_snapshot,
.sigchld_event = service_sigchld_event,
diff --git a/src/core/service.h b/src/core/service.h
index a8d42706bd..d0faad88e0 100644
--- a/src/core/service.h
+++ b/src/core/service.h
@@ -24,10 +24,10 @@
typedef struct Service Service;
typedef struct ServiceFDStore ServiceFDStore;
+#include "exit-status.h"
+#include "kill.h"
#include "path.h"
#include "ratelimit.h"
-#include "kill.h"
-#include "exit-status.h"
typedef enum ServiceRestart {
SERVICE_RESTART_NO,
@@ -97,6 +97,7 @@ struct ServiceFDStore {
Service *service;
int fd;
+ char *fdname;
sd_event_source *event_source;
LIST_FIELDS(ServiceFDStore, fd_store);
@@ -194,6 +195,10 @@ struct Service {
char *usb_function_descriptors;
char *usb_function_strings;
+
+ int stdin_fd;
+ int stdout_fd;
+ int stderr_fd;
};
extern const UnitVTable service_vtable;
diff --git a/src/core/show-status.c b/src/core/show-status.c
index 02b1be73e3..e4e12a3365 100644
--- a/src/core/show-status.c
+++ b/src/core/show-status.c
@@ -19,7 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "alloc-util.h"
+#include "fd-util.h"
+#include "io-util.h"
+#include "parse-util.h"
#include "show-status.h"
+#include "string-util.h"
+#include "terminal-util.h"
#include "util.h"
int parse_show_status(const char *v, ShowStatus *ret) {
@@ -40,3 +46,81 @@ int parse_show_status(const char *v, ShowStatus *ret) {
*ret = r ? SHOW_STATUS_YES : SHOW_STATUS_NO;
return 0;
}
+
+int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) {
+ static const char status_indent[] = " "; /* "[" STATUS "] " */
+ _cleanup_free_ char *s = NULL;
+ _cleanup_close_ int fd = -1;
+ struct iovec iovec[6] = {};
+ int n = 0;
+ static bool prev_ephemeral;
+
+ assert(format);
+
+ /* This is independent of logging, as status messages are
+ * optional and go exclusively to the console. */
+
+ if (vasprintf(&s, format, ap) < 0)
+ return log_oom();
+
+ fd = open_terminal("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
+ if (fd < 0)
+ return fd;
+
+ if (ellipse) {
+ char *e;
+ size_t emax, sl;
+ int c;
+
+ c = fd_columns(fd);
+ if (c <= 0)
+ c = 80;
+
+ sl = status ? sizeof(status_indent)-1 : 0;
+
+ emax = c - sl - 1;
+ if (emax < 3)
+ emax = 3;
+
+ e = ellipsize(s, emax, 50);
+ if (e) {
+ free(s);
+ s = e;
+ }
+ }
+
+ if (prev_ephemeral)
+ IOVEC_SET_STRING(iovec[n++], "\r" ANSI_ERASE_TO_END_OF_LINE);
+ prev_ephemeral = ephemeral;
+
+ if (status) {
+ if (!isempty(status)) {
+ IOVEC_SET_STRING(iovec[n++], "[");
+ IOVEC_SET_STRING(iovec[n++], status);
+ IOVEC_SET_STRING(iovec[n++], "] ");
+ } else
+ IOVEC_SET_STRING(iovec[n++], status_indent);
+ }
+
+ IOVEC_SET_STRING(iovec[n++], s);
+ if (!ephemeral)
+ IOVEC_SET_STRING(iovec[n++], "\n");
+
+ if (writev(fd, iovec, n) < 0)
+ return -errno;
+
+ return 0;
+}
+
+int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) {
+ va_list ap;
+ int r;
+
+ assert(format);
+
+ va_start(ap, format);
+ r = status_vprintf(status, ellipse, ephemeral, format, ap);
+ va_end(ap);
+
+ return r;
+}
diff --git a/src/core/show-status.h b/src/core/show-status.h
index a2b2153746..c79d4acb66 100644
--- a/src/core/show-status.h
+++ b/src/core/show-status.h
@@ -21,6 +21,10 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include <stdbool.h>
+
+#include "macro.h"
+
/* Manager status */
typedef enum ShowStatus {
@@ -32,3 +36,6 @@ typedef enum ShowStatus {
} ShowStatus;
int parse_show_status(const char *v, ShowStatus *ret);
+
+int status_vprintf(const char *status, bool ellipse, bool ephemeral, const char *format, va_list ap) _printf_(4,0);
+int status_printf(const char *status, bool ellipse, bool ephemeral, const char *format, ...) _printf_(4,5);
diff --git a/src/core/shutdown.c b/src/core/shutdown.c
index 27c581d9c1..3a95b5fd72 100644
--- a/src/core/shutdown.c
+++ b/src/core/shutdown.c
@@ -19,31 +19,34 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <sys/mman.h>
-#include <sys/reboot.h>
-#include <linux/reboot.h>
-#include <sys/stat.h>
-#include <sys/mount.h>
#include <errno.h>
-#include <unistd.h>
+#include <getopt.h>
+#include <linux/reboot.h>
#include <signal.h>
#include <stdbool.h>
#include <stdlib.h>
-#include <getopt.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/reboot.h>
+#include <sys/stat.h>
+#include <unistd.h>
-#include "missing.h"
-#include "log.h"
+#include "alloc-util.h"
+#include "cgroup-util.h"
+#include "def.h"
#include "fileio.h"
+#include "killall.h"
+#include "log.h"
+#include "missing.h"
+#include "parse-util.h"
+#include "process-util.h"
+#include "string-util.h"
+#include "switch-root.h"
+#include "terminal-util.h"
#include "umount.h"
#include "util.h"
#include "virt.h"
#include "watchdog.h"
-#include "killall.h"
-#include "cgroup-util.h"
-#include "def.h"
-#include "switch-root.h"
-#include "process-util.h"
-#include "terminal-util.h"
#define FINALIZE_ATTEMPTS 50
diff --git a/src/core/slice.c b/src/core/slice.c
index 063024134a..06ac6f8450 100644
--- a/src/core/slice.c
+++ b/src/core/slice.c
@@ -21,13 +21,15 @@
#include <errno.h>
+#include "alloc-util.h"
+#include "dbus-slice.h"
#include "log.h"
-#include "strv.h"
+#include "slice.h"
#include "special.h"
+#include "string-util.h"
+#include "strv.h"
#include "unit-name.h"
#include "unit.h"
-#include "slice.h"
-#include "dbus-slice.h"
static const UnitActiveState state_translation_table[_SLICE_STATE_MAX] = {
[SLICE_DEAD] = UNIT_INACTIVE,
@@ -83,6 +85,9 @@ static int slice_add_default_dependencies(Slice *s) {
assert(s);
+ if (!UNIT(s)->default_dependencies)
+ return 0;
+
/* Make sure slices are unloaded on shutdown */
r = unit_add_two_dependencies_by_name(
UNIT(s),
@@ -94,7 +99,6 @@ static int slice_add_default_dependencies(Slice *s) {
return 0;
}
-
static int slice_verify(Slice *s) {
_cleanup_free_ char *parent = NULL;
int r;
@@ -142,11 +146,9 @@ static int slice_load(Unit *u) {
if (r < 0)
return r;
- if (u->default_dependencies) {
- r = slice_add_default_dependencies(s);
- if (r < 0)
- return r;
- }
+ r = slice_add_default_dependencies(s);
+ if (r < 0)
+ return r;
}
return slice_verify(s);
@@ -253,7 +255,7 @@ _pure_ static const char *slice_sub_state_to_string(Unit *u) {
return slice_state_to_string(SLICE(u)->state);
}
-static int slice_enumerate(Manager *m) {
+static void slice_enumerate(Manager *m) {
Unit *u;
int r;
@@ -262,18 +264,24 @@ static int slice_enumerate(Manager *m) {
u = manager_get_unit(m, SPECIAL_ROOT_SLICE);
if (!u) {
u = unit_new(m, sizeof(Slice));
- if (!u)
- return log_oom();
+ if (!u) {
+ log_oom();
+ return;
+ }
r = unit_add_name(u, SPECIAL_ROOT_SLICE);
if (r < 0) {
unit_free(u);
- return log_error_errno(r, "Failed to add -.slice name");
+ log_error_errno(r, "Failed to add -.slice name");
+ return;
}
}
u->default_dependencies = false;
u->no_gc = true;
+ u->ignore_on_isolate = true;
+ u->refuse_manual_start = true;
+ u->refuse_manual_stop = true;
SLICE(u)->deserialized_state = SLICE_ACTIVE;
if (!u->description)
@@ -283,8 +291,6 @@ static int slice_enumerate(Manager *m) {
unit_add_to_load_queue(u);
unit_add_to_dbus_queue(u);
-
- return 0;
}
const UnitVTable slice_vtable = {
@@ -299,6 +305,7 @@ const UnitVTable slice_vtable = {
.no_alias = true,
.no_instances = true,
+ .can_transient = true,
.load = slice_load,
diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c
index 761582c7a2..0661ff9ecd 100644
--- a/src/core/smack-setup.c
+++ b/src/core/smack-setup.c
@@ -21,18 +21,22 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <stdio.h>
+#include <dirent.h>
#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
#include <fcntl.h>
-#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "alloc-util.h"
+#include "dirent-util.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "log.h"
#include "macro.h"
#include "smack-setup.h"
+#include "string-util.h"
#include "util.h"
-#include "fileio.h"
-#include "log.h"
#ifdef HAVE_SMACK
diff --git a/src/core/snapshot.c b/src/core/snapshot.c
deleted file mode 100644
index 867f3765e7..0000000000
--- a/src/core/snapshot.c
+++ /dev/null
@@ -1,299 +0,0 @@
-/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
-
-/***
- This file is part of systemd.
-
- Copyright 2010 Lennart Poettering
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
-
-#include <errno.h>
-
-#include "unit.h"
-#include "snapshot.h"
-#include "unit-name.h"
-#include "dbus-snapshot.h"
-#include "bus-common-errors.h"
-
-static const UnitActiveState state_translation_table[_SNAPSHOT_STATE_MAX] = {
- [SNAPSHOT_DEAD] = UNIT_INACTIVE,
- [SNAPSHOT_ACTIVE] = UNIT_ACTIVE
-};
-
-static void snapshot_init(Unit *u) {
- Snapshot *s = SNAPSHOT(u);
-
- assert(s);
- assert(UNIT(s)->load_state == UNIT_STUB);
-
- UNIT(s)->ignore_on_isolate = true;
- UNIT(s)->ignore_on_snapshot = true;
- UNIT(s)->allow_isolate = true;
-}
-
-static void snapshot_set_state(Snapshot *s, SnapshotState state) {
- SnapshotState old_state;
- assert(s);
-
- old_state = s->state;
- s->state = state;
-
- if (state != old_state)
- log_unit_debug(UNIT(s), "Changed %s -> %s", snapshot_state_to_string(old_state), snapshot_state_to_string(state));
-
- unit_notify(UNIT(s), state_translation_table[old_state], state_translation_table[state], true);
-}
-
-static int snapshot_load(Unit *u) {
- Snapshot *s = SNAPSHOT(u);
-
- assert(u);
- assert(u->load_state == UNIT_STUB);
-
- /* Make sure that only snapshots created via snapshot_create()
- * can be loaded */
- if (!u->transient && UNIT(s)->manager->n_reloading <= 0)
- return -ENOENT;
-
- u->load_state = UNIT_LOADED;
- return 0;
-}
-
-static int snapshot_coldplug(Unit *u) {
- Snapshot *s = SNAPSHOT(u);
-
- assert(s);
- assert(s->state == SNAPSHOT_DEAD);
-
- if (s->deserialized_state != s->state)
- snapshot_set_state(s, s->deserialized_state);
-
- return 0;
-}
-
-static void snapshot_dump(Unit *u, FILE *f, const char *prefix) {
- Snapshot *s = SNAPSHOT(u);
-
- assert(s);
- assert(f);
-
- fprintf(f,
- "%sSnapshot State: %s\n"
- "%sClean Up: %s\n",
- prefix, snapshot_state_to_string(s->state),
- prefix, yes_no(s->cleanup));
-}
-
-static int snapshot_start(Unit *u) {
- Snapshot *s = SNAPSHOT(u);
-
- assert(s);
- assert(s->state == SNAPSHOT_DEAD);
-
- snapshot_set_state(s, SNAPSHOT_ACTIVE);
-
- if (s->cleanup)
- unit_add_to_cleanup_queue(u);
-
- return 1;
-}
-
-static int snapshot_stop(Unit *u) {
- Snapshot *s = SNAPSHOT(u);
-
- assert(s);
- assert(s->state == SNAPSHOT_ACTIVE);
-
- snapshot_set_state(s, SNAPSHOT_DEAD);
- return 1;
-}
-
-static int snapshot_serialize(Unit *u, FILE *f, FDSet *fds) {
- Snapshot *s = SNAPSHOT(u);
- Unit *other;
- Iterator i;
-
- assert(s);
- assert(f);
- assert(fds);
-
- unit_serialize_item(u, f, "state", snapshot_state_to_string(s->state));
- unit_serialize_item(u, f, "cleanup", yes_no(s->cleanup));
- SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
- unit_serialize_item(u, f, "wants", other->id);
-
- return 0;
-}
-
-static int snapshot_deserialize_item(Unit *u, const char *key, const char *value, FDSet *fds) {
- Snapshot *s = SNAPSHOT(u);
- int r;
-
- assert(u);
- assert(key);
- assert(value);
- assert(fds);
-
- if (streq(key, "state")) {
- SnapshotState state;
-
- state = snapshot_state_from_string(value);
- if (state < 0)
- log_unit_debug(u, "Failed to parse state value: %s", value);
- else
- s->deserialized_state = state;
-
- } else if (streq(key, "cleanup")) {
-
- r = parse_boolean(value);
- if (r < 0)
- log_unit_debug(u, "Failed to parse cleanup value: %s", value);
- else
- s->cleanup = r;
-
- } else if (streq(key, "wants")) {
-
- r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_WANTS, value, NULL, true);
- if (r < 0)
- return r;
- } else
- log_unit_debug(u, "Unknown serialization key: %s", key);
-
- return 0;
-}
-
-_pure_ static UnitActiveState snapshot_active_state(Unit *u) {
- assert(u);
-
- return state_translation_table[SNAPSHOT(u)->state];
-}
-
-_pure_ static const char *snapshot_sub_state_to_string(Unit *u) {
- assert(u);
-
- return snapshot_state_to_string(SNAPSHOT(u)->state);
-}
-
-int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e, Snapshot **_s) {
- _cleanup_free_ char *n = NULL;
- Unit *other, *u = NULL;
- Iterator i;
- int r;
- const char *k;
-
- assert(m);
- assert(_s);
-
- if (name) {
- if (!unit_name_is_valid(name, UNIT_NAME_PLAIN))
- return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s is not valid.", name);
-
- if (!endswith(name, ".snapshot"))
- return sd_bus_error_setf(e, SD_BUS_ERROR_INVALID_ARGS, "Unit name %s lacks snapshot suffix.", name);
-
- if (manager_get_unit(m, name))
- return sd_bus_error_setf(e, BUS_ERROR_UNIT_EXISTS, "Snapshot %s exists already.", name);
-
- } else {
-
- for (;;) {
- if (asprintf(&n, "snapshot-%u.snapshot", ++ m->n_snapshots) < 0)
- return -ENOMEM;
-
- if (!manager_get_unit(m, n)) {
- name = n;
- break;
- }
-
- n = mfree(n);
- }
- }
-
- r = manager_load_unit_prepare(m, name, NULL, e, &u);
- if (r < 0)
- goto fail;
-
- u->transient = true;
- manager_dispatch_load_queue(m);
- assert(u->load_state == UNIT_LOADED);
-
- HASHMAP_FOREACH_KEY(other, k, m->units, i) {
-
- if (other->ignore_on_snapshot ||
- other->transient)
- continue;
-
- if (k != other->id)
- continue;
-
- if (UNIT_VTABLE(other)->check_snapshot)
- if (!UNIT_VTABLE(other)->check_snapshot(other))
- continue;
-
- if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
- continue;
-
- r = unit_add_two_dependencies(u, UNIT_AFTER, UNIT_WANTS, other, true);
- if (r < 0)
- goto fail;
- }
-
- SNAPSHOT(u)->cleanup = cleanup;
- *_s = SNAPSHOT(u);
-
- log_unit_info(u, "Created snapshot.");
-
- return 0;
-
-fail:
- if (u)
- unit_add_to_cleanup_queue(u);
-
- return r;
-}
-
-void snapshot_remove(Snapshot *s) {
- assert(s);
-
- log_unit_info(UNIT(s), "Removing snapshot.");
-
- unit_add_to_cleanup_queue(UNIT(s));
-}
-
-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_vtable = bus_snapshot_vtable
-};
diff --git a/src/core/snapshot.h b/src/core/snapshot.h
deleted file mode 100644
index 97747e18bd..0000000000
--- a/src/core/snapshot.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 Snapshot Snapshot;
-
-struct Snapshot {
- Unit meta;
-
- SnapshotState state, deserialized_state;
-
- bool cleanup;
-};
-
-extern const UnitVTable snapshot_vtable;
-
-int snapshot_create(Manager *m, const char *name, bool cleanup, sd_bus_error *e, Snapshot **s);
-void snapshot_remove(Snapshot *s);
diff --git a/src/core/socket.c b/src/core/socket.c
index 3250e7efc6..687675b24e 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -31,27 +31,34 @@
#include "sd-event.h"
+#include "alloc-util.h"
#include "bus-error.h"
#include "bus-util.h"
#include "copy.h"
#include "dbus-socket.h"
#include "def.h"
#include "exit-status.h"
+#include "fd-util.h"
#include "formats-util.h"
#include "label.h"
#include "log.h"
#include "missing.h"
#include "mkdir.h"
+#include "parse-util.h"
#include "path-util.h"
+#include "process-util.h"
#include "selinux-util.h"
#include "signal-util.h"
#include "smack-util.h"
#include "socket.h"
#include "special.h"
+#include "string-table.h"
+#include "string-util.h"
#include "strv.h"
#include "unit-name.h"
#include "unit-printf.h"
#include "unit.h"
+#include "user-util.h"
static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = {
[SOCKET_DEAD] = UNIT_INACTIVE,
@@ -107,11 +114,9 @@ static void socket_unwatch_control_pid(Socket *s) {
}
static void socket_cleanup_fd_list(SocketPort *p) {
- int k = p->n_auxiliary_fds;
-
- while (k--)
- safe_close(p->auxiliary_fds[k]);
+ assert(p);
+ close_many(p->auxiliary_fds, p->n_auxiliary_fds);
p->auxiliary_fds = mfree(p->auxiliary_fds);
p->n_auxiliary_fds = 0;
}
@@ -291,6 +296,9 @@ static int socket_add_default_dependencies(Socket *s) {
int r;
assert(s);
+ if (!UNIT(s)->default_dependencies)
+ return 0;
+
r = unit_add_dependency_by_name(UNIT(s), UNIT_BEFORE, SPECIAL_SOCKETS_TARGET, NULL, true);
if (r < 0)
return r;
@@ -360,11 +368,9 @@ static int socket_add_extras(Socket *s) {
return r;
}
- if (u->default_dependencies) {
- r = socket_add_default_dependencies(s);
- if (r < 0)
- return r;
- }
+ r = socket_add_default_dependencies(s);
+ if (r < 0)
+ return r;
return 0;
}
@@ -508,6 +514,7 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
"%sTCPCongestion: %s\n"
"%sRemoveOnStop: %s\n"
"%sWritable: %s\n"
+ "%sFDName: %s\n"
"%sSELinuxContextFromNet: %s\n",
prefix, socket_state_to_string(s->state),
prefix, socket_result_to_string(s->result),
@@ -525,6 +532,7 @@ static void socket_dump(Unit *u, FILE *f, const char *prefix) {
prefix, strna(s->tcp_congestion),
prefix, yes_no(s->remove_on_stop),
prefix, yes_no(s->writable),
+ prefix, socket_fdname(s),
prefix, yes_no(s->selinux_context_from_net));
if (s->control_pid > 0)
@@ -1028,8 +1036,6 @@ static int fifo_address_create(
fail:
mac_selinux_create_file_clear();
- safe_close(fd);
-
return r;
}
@@ -1167,9 +1173,9 @@ static int usbffs_dispatch_eps(SocketPort *p) {
_cleanup_free_ char *path = NULL;
int r, i, n, k;
- r = path_get_parent(p->path, &path);
- if (r < 0)
- return r;
+ path = dirname_malloc(p->path);
+ if (!path)
+ return -ENOMEM;
r = scandir(path, &ent, usbffs_select_ep, alphasort);
if (r < 0)
@@ -1260,6 +1266,19 @@ static int socket_open_fds(Socket *s) {
know_label = true;
}
+ /* Apply the socket protocol */
+ switch(p->address.type) {
+ case SOCK_STREAM:
+ case SOCK_SEQPACKET:
+ if (p->socket->socket_protocol == IPPROTO_SCTP)
+ p->address.protocol = p->socket->socket_protocol;
+ break;
+ case SOCK_DGRAM:
+ if (p->socket->socket_protocol == IPPROTO_UDPLITE)
+ p->address.protocol = p->socket->socket_protocol;
+ break;
+ }
+
r = socket_address_listen(
&p->address,
SOCK_CLOEXEC|SOCK_NONBLOCK,
@@ -1450,7 +1469,9 @@ static int socket_coldplug(Unit *u) {
if (s->deserialized_state == s->state)
return 0;
- if (IN_SET(s->deserialized_state,
+ if (s->control_pid > 0 &&
+ pid_is_unwaited(s->control_pid) &&
+ IN_SET(s->deserialized_state,
SOCKET_START_PRE,
SOCKET_START_CHOWN,
SOCKET_START_POST,
@@ -1461,9 +1482,6 @@ static int socket_coldplug(Unit *u) {
SOCKET_FINAL_SIGTERM,
SOCKET_FINAL_SIGKILL)) {
- if (s->control_pid <= 0)
- return -EBADMSG;
-
r = unit_watch_pid(UNIT(s), s->control_pid);
if (r < 0)
return r;
@@ -1505,6 +1523,9 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
.apply_chroot = true,
.apply_tty_stdin = true,
.bus_endpoint_fd = -1,
+ .stdin_fd = -1,
+ .stdout_fd = -1,
+ .stderr_fd = -1,
};
assert(s);
@@ -1913,7 +1934,7 @@ static void socket_enter_running(Socket *s, int cfd) {
goto fail;
}
- r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT_DEREF(s->service), JOB_REPLACE, true, &error, NULL);
+ r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT_DEREF(s->service), JOB_REPLACE, &error, NULL);
if (r < 0)
goto fail;
}
@@ -1971,7 +1992,7 @@ static void socket_enter_running(Socket *s, int cfd) {
cfd = -1;
s->n_connections ++;
- r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, true, &error, NULL);
+ r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(service), JOB_REPLACE, &error, NULL);
if (r < 0)
goto fail;
@@ -2325,7 +2346,7 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
return 0;
}
-static int socket_distribute_fds(Unit *u, FDSet *fds) {
+static void socket_distribute_fds(Unit *u, FDSet *fds) {
Socket *s = SOCKET(u);
SocketPort *p;
@@ -2349,8 +2370,6 @@ static int socket_distribute_fds(Unit *u, FDSet *fds) {
}
}
}
-
- return 0;
}
_pure_ static UnitActiveState socket_active_state(Unit *u) {
@@ -2630,49 +2649,43 @@ static int socket_dispatch_timer(sd_event_source *source, usec_t usec, void *use
return 0;
}
-int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds) {
- int *rfds;
- unsigned rn_fds, k;
- int i;
+int socket_collect_fds(Socket *s, int **fds) {
+ int *rfds, k = 0, n = 0;
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++;
- rn_fds += p->n_auxiliary_fds;
+ n++;
+ n += p->n_auxiliary_fds;
}
- if (rn_fds <= 0) {
+ if (n <= 0) {
*fds = NULL;
- *n_fds = 0;
return 0;
}
- rfds = new(int, rn_fds);
+ rfds = new(int, n);
if (!rfds)
return -ENOMEM;
- k = 0;
LIST_FOREACH(port, p, s->ports) {
+ int i;
+
if (p->fd >= 0)
rfds[k++] = p->fd;
for (i = 0; i < p->n_auxiliary_fds; ++i)
rfds[k++] = p->auxiliary_fds[i];
}
- assert(k == rn_fds);
+ assert(k == n);
*fds = rfds;
- *n_fds = rn_fds;
-
- return 0;
+ return n;
}
static void socket_reset_failed(Unit *u) {
@@ -2768,6 +2781,19 @@ static int socket_get_timeout(Unit *u, uint64_t *timeout) {
return 1;
}
+char *socket_fdname(Socket *s) {
+ assert(s);
+
+ /* Returns the name to use for $LISTEN_NAMES. If the user
+ * didn't specify anything specifically, use the socket unit's
+ * name as fallback. */
+
+ if (s->fdname)
+ return s->fdname;
+
+ return UNIT(s)->id;
+}
+
static const char* const socket_exec_command_table[_SOCKET_EXEC_COMMAND_MAX] = {
[SOCKET_EXEC_START_PRE] = "StartPre",
[SOCKET_EXEC_START_CHOWN] = "StartChown",
diff --git a/src/core/socket.h b/src/core/socket.h
index d20dc8d81a..08033287a6 100644
--- a/src/core/socket.h
+++ b/src/core/socket.h
@@ -23,9 +23,9 @@
typedef struct Socket Socket;
-#include "socket-util.h"
#include "mount.h"
#include "service.h"
+#include "socket-util.h"
typedef enum SocketExecCommand {
SOCKET_EXEC_START_PRE,
@@ -120,6 +120,8 @@ struct Socket {
bool remove_on_stop;
bool writable;
+ int socket_protocol;
+
/* Socket options */
bool keep_alive;
bool no_delay;
@@ -154,16 +156,22 @@ struct Socket {
char *user, *group;
bool reset_cpu_usage:1;
+
+ char *fdname;
};
/* Called from the service code when collecting fds */
-int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds);
+int socket_collect_fds(Socket *s, int **fds);
/* Called from the service code when a per-connection service ended */
void socket_connection_unref(Socket *s);
void socket_free_ports(Socket *s);
+int socket_instantiate_service(Socket *s);
+
+char *socket_fdname(Socket *s);
+
extern const UnitVTable socket_vtable;
const char* socket_exec_command_to_string(SocketExecCommand i) _const_;
@@ -173,5 +181,3 @@ const char* socket_result_to_string(SocketResult i) _const_;
SocketResult socket_result_from_string(const char *s) _pure_;
const char* socket_port_type_to_string(SocketPort *p) _pure_;
-
-int socket_instantiate_service(Socket *s);
diff --git a/src/core/swap.c b/src/core/swap.c
index 1f94d32318..ee0838e676 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -20,22 +20,30 @@
***/
#include <errno.h>
-#include <unistd.h>
#include <sys/epoll.h>
#include <sys/stat.h>
-#include <libudev.h>
+#include <unistd.h>
-#include "unit.h"
-#include "swap.h"
-#include "unit-name.h"
+#include "libudev.h"
+
+#include "alloc-util.h"
#include "dbus-swap.h"
-#include "special.h"
+#include "escape.h"
#include "exit-status.h"
+#include "fd-util.h"
+#include "formats-util.h"
+#include "fstab-util.h"
+#include "parse-util.h"
#include "path-util.h"
-#include "virt.h"
+#include "process-util.h"
+#include "special.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "swap.h"
#include "udev-util.h"
-#include "fstab-util.h"
-#include "formats-util.h"
+#include "unit-name.h"
+#include "unit.h"
+#include "virt.h"
static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = {
[SWAP_DEAD] = UNIT_INACTIVE,
@@ -205,6 +213,9 @@ static int swap_add_device_links(Swap *s) {
static int swap_add_default_dependencies(Swap *s) {
assert(s);
+ if (!UNIT(s)->default_dependencies)
+ return 0;
+
if (UNIT(s)->manager->running_as != MANAGER_SYSTEM)
return 0;
@@ -323,11 +334,9 @@ static int swap_load(Unit *u) {
if (r < 0)
return r;
- if (UNIT(s)->default_dependencies) {
- r = swap_add_default_dependencies(s);
- if (r < 0)
- return r;
- }
+ r = swap_add_default_dependencies(s);
+ if (r < 0)
+ return r;
}
return swap_verify(s);
@@ -520,16 +529,16 @@ static int swap_coldplug(Unit *u) {
if (new_state == s->state)
return 0;
- if (new_state == SWAP_ACTIVATING ||
- new_state == SWAP_ACTIVATING_SIGTERM ||
- new_state == SWAP_ACTIVATING_SIGKILL ||
- new_state == SWAP_ACTIVATING_DONE ||
- new_state == SWAP_DEACTIVATING ||
- new_state == SWAP_DEACTIVATING_SIGTERM ||
- new_state == SWAP_DEACTIVATING_SIGKILL) {
-
- if (s->control_pid <= 0)
- return -EBADMSG;
+ if (s->control_pid > 0 &&
+ pid_is_unwaited(s->control_pid) &&
+ IN_SET(new_state,
+ SWAP_ACTIVATING,
+ SWAP_ACTIVATING_SIGTERM,
+ SWAP_ACTIVATING_SIGKILL,
+ SWAP_ACTIVATING_DONE,
+ SWAP_DEACTIVATING,
+ SWAP_DEACTIVATING_SIGTERM,
+ SWAP_DEACTIVATING_SIGKILL)) {
r = unit_watch_pid(UNIT(s), s->control_pid);
if (r < 0)
@@ -597,6 +606,9 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
.apply_chroot = true,
.apply_tty_stdin = true,
.bus_endpoint_fd = -1,
+ .stdin_fd = -1,
+ .stdout_fd = -1,
+ .stderr_fd = -1,
};
assert(s);
@@ -1195,7 +1207,7 @@ static Unit *swap_following(Unit *u) {
if (other->from_fragment)
return UNIT(other);
- /* Otherwise make everybody follow the unit that's named after
+ /* Otherwise, make everybody follow the unit that's named after
* the swap device in the kernel */
if (streq_ptr(s->what, s->devnode))
@@ -1257,26 +1269,36 @@ static void swap_shutdown(Manager *m) {
m->swaps_by_devnode = hashmap_free(m->swaps_by_devnode);
}
-static int swap_enumerate(Manager *m) {
+static void swap_enumerate(Manager *m) {
int r;
assert(m);
if (!m->proc_swaps) {
m->proc_swaps = fopen("/proc/swaps", "re");
- if (!m->proc_swaps)
- return errno == ENOENT ? 0 : -errno;
+ if (!m->proc_swaps) {
+ if (errno == ENOENT)
+ log_debug("Not swap enabled, skipping enumeration");
+ else
+ log_error_errno(errno, "Failed to open /proc/swaps: %m");
+
+ return;
+ }
r = sd_event_add_io(m->event, &m->swap_event_source, fileno(m->proc_swaps), EPOLLPRI, swap_dispatch_io, m);
- if (r < 0)
+ if (r < 0) {
+ log_error_errno(r, "Failed to watch /proc/swaps: %m");
goto fail;
+ }
/* Dispatch this before we dispatch SIGCHLD, so that
* we always get the events from /proc/swaps before
* the SIGCHLD of /sbin/swapon. */
r = sd_event_source_set_priority(m->swap_event_source, -10);
- if (r < 0)
+ if (r < 0) {
+ log_error_errno(r, "Failed to change /proc/swaps priority: %m");
goto fail;
+ }
(void) sd_event_source_set_description(m->swap_event_source, "swap-proc");
}
@@ -1285,11 +1307,10 @@ static int swap_enumerate(Manager *m) {
if (r < 0)
goto fail;
- return 0;
+ return;
fail:
swap_shutdown(m);
- return r;
}
int swap_process_device_new(Manager *m, struct udev_device *dev) {
diff --git a/src/core/swap.h b/src/core/swap.h
index 7f29603c32..303b926568 100644
--- a/src/core/swap.h
+++ b/src/core/swap.h
@@ -22,7 +22,7 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <libudev.h>
+#include "libudev.h"
typedef struct Swap Swap;
diff --git a/src/core/system.conf b/src/core/system.conf
index c30c595413..e2ded27333 100644
--- a/src/core/system.conf
+++ b/src/core/system.conf
@@ -40,6 +40,8 @@
#DefaultCPUAccounting=no
#DefaultBlockIOAccounting=no
#DefaultMemoryAccounting=no
+#DefaultTasksAccounting=yes
+#DefaultTasksMax=512
#DefaultLimitCPU=
#DefaultLimitFSIZE=
#DefaultLimitDATA=
diff --git a/src/core/target.c b/src/core/target.c
index a905a1adf6..14f9b2e26a 100644
--- a/src/core/target.c
+++ b/src/core/target.c
@@ -19,13 +19,13 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-
-#include "unit.h"
-#include "target.h"
-#include "log.h"
#include "dbus-target.h"
+#include "log.h"
#include "special.h"
+#include "string-util.h"
#include "unit-name.h"
+#include "unit.h"
+#include "target.h"
static const UnitActiveState state_translation_table[_TARGET_STATE_MAX] = {
[TARGET_DEAD] = UNIT_INACTIVE,
@@ -52,9 +52,7 @@ 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
diff --git a/src/core/timer.c b/src/core/timer.c
index 800e58261c..6b0f8e8616 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -21,13 +21,21 @@
#include <errno.h>
-#include "unit.h"
-#include "unit-name.h"
-#include "timer.h"
+#include "alloc-util.h"
+#include "bus-error.h"
+#include "bus-util.h"
#include "dbus-timer.h"
+#include "fs-util.h"
+#include "parse-util.h"
+#include "random-util.h"
#include "special.h"
-#include "bus-util.h"
-#include "bus-error.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "timer.h"
+#include "unit-name.h"
+#include "unit.h"
+#include "user-util.h"
+#include "virt.h"
static const UnitActiveState state_translation_table[_TIMER_STATE_MAX] = {
[TIMER_DEAD] = UNIT_INACTIVE,
@@ -48,6 +56,7 @@ static void timer_init(Unit *u) {
t->next_elapse_monotonic_or_boottime = USEC_INFINITY;
t->next_elapse_realtime = USEC_INFINITY;
t->accuracy_usec = u->manager->default_timer_accuracy_usec;
+ t->remain_after_elapse = true;
}
void timer_free_values(Timer *t) {
@@ -95,6 +104,9 @@ static int timer_add_default_dependencies(Timer *t) {
assert(t);
+ if (!UNIT(t)->default_dependencies)
+ return 0;
+
r = unit_add_dependency_by_name(UNIT(t), UNIT_BEFORE, SPECIAL_TIMERS_TARGET, NULL, true);
if (r < 0)
return r;
@@ -185,11 +197,9 @@ static int timer_load(Unit *u) {
if (r < 0)
return r;
- if (u->default_dependencies) {
- r = timer_add_default_dependencies(t);
- if (r < 0)
- return r;
- }
+ r = timer_add_default_dependencies(t);
+ if (r < 0)
+ return r;
}
return timer_verify(t);
@@ -209,13 +219,15 @@ static void timer_dump(Unit *u, FILE *f, const char *prefix) {
"%sUnit: %s\n"
"%sPersistent: %s\n"
"%sWakeSystem: %s\n"
- "%sAccuracy: %s\n",
+ "%sAccuracy: %s\n"
+ "%sRemainAfterElapse: %s\n",
prefix, timer_state_to_string(t->state),
prefix, timer_result_to_string(t->result),
prefix, trigger ? trigger->id : "n/a",
prefix, yes_no(t->persistent),
prefix, yes_no(t->wake_system),
- prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1));
+ prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1),
+ prefix, yes_no(t->remain_after_elapse));
LIST_FOREACH(value, v, t->values) {
@@ -267,13 +279,13 @@ static int timer_coldplug(Unit *u) {
assert(t);
assert(t->state == TIMER_DEAD);
- if (t->deserialized_state != t->state) {
+ if (t->deserialized_state == t->state)
+ return 0;
- if (t->deserialized_state == TIMER_WAITING)
- timer_enter_waiting(t, false);
- else
- timer_set_state(t, t->deserialized_state);
- }
+ if (t->deserialized_state == TIMER_WAITING)
+ timer_enter_waiting(t, false);
+ else
+ timer_set_state(t, t->deserialized_state);
return 0;
}
@@ -287,6 +299,23 @@ static void timer_enter_dead(Timer *t, TimerResult f) {
timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
}
+static void timer_enter_elapsed(Timer *t, bool leave_around) {
+ assert(t);
+
+ /* If a unit is marked with RemainAfterElapse=yes we leave it
+ * around even after it elapsed once, so that starting it
+ * later again does not necessarily mean immediate
+ * retriggering. We unconditionally leave units with
+ * TIMER_UNIT_ACTIVE or TIMER_UNIT_INACTIVE triggers around,
+ * since they might be restarted automatically at any time
+ * later on. */
+
+ if (t->remain_after_elapse || leave_around)
+ timer_set_state(t, TIMER_ELAPSED);
+ else
+ timer_enter_dead(t, TIMER_SUCCESS);
+}
+
static usec_t monotonic_to_boottime(usec_t t) {
usec_t a, b;
@@ -302,10 +331,33 @@ static usec_t monotonic_to_boottime(usec_t t) {
return 0;
}
+static void add_random(Timer *t, usec_t *v) {
+ char s[FORMAT_TIMESPAN_MAX];
+ usec_t add;
+
+ assert(t);
+ assert(*v);
+
+ if (t->random_usec == 0)
+ return;
+ if (*v == USEC_INFINITY)
+ return;
+
+ add = random_u64() % t->random_usec;
+
+ if (*v + add < *v) /* overflow */
+ *v = (usec_t) -2; /* Highest possible value, that is not USEC_INFINITY */
+ else
+ *v += add;
+
+ log_unit_info(UNIT(t), "Adding %s random time.", format_timespan(s, sizeof(s), add, 0));
+}
+
static void timer_enter_waiting(Timer *t, bool initial) {
bool found_monotonic = false, found_realtime = false;
usec_t ts_realtime, ts_monotonic;
usec_t base = 0;
+ bool leave_around = false;
TimerValue *v;
int r;
@@ -353,16 +405,20 @@ static void timer_enter_waiting(Timer *t, bool initial) {
break;
case TIMER_BOOT:
- /* CLOCK_MONOTONIC equals the uptime on Linux */
- base = 0;
- break;
-
+ if (detect_container() <= 0) {
+ /* CLOCK_MONOTONIC equals the uptime on Linux */
+ base = 0;
+ break;
+ }
+ /* In a container we don't want to include the time the host
+ * was already up when the container started, so count from
+ * our own startup. Fall through. */
case TIMER_STARTUP:
base = UNIT(t)->manager->userspace_timestamp.monotonic;
break;
case TIMER_UNIT_ACTIVE:
-
+ leave_around = true;
base = UNIT_TRIGGER(UNIT(t))->inactive_exit_timestamp.monotonic;
if (base <= 0)
@@ -374,7 +430,7 @@ static void timer_enter_waiting(Timer *t, bool initial) {
break;
case TIMER_UNIT_INACTIVE:
-
+ leave_around = true;
base = UNIT_TRIGGER(UNIT(t))->inactive_enter_timestamp.monotonic;
if (base <= 0)
@@ -411,14 +467,18 @@ static void timer_enter_waiting(Timer *t, bool initial) {
if (!found_monotonic && !found_realtime) {
log_unit_debug(UNIT(t), "Timer is elapsed.");
- timer_set_state(t, TIMER_ELAPSED);
+ timer_enter_elapsed(t, leave_around);
return;
}
if (found_monotonic) {
char buf[FORMAT_TIMESPAN_MAX];
+ usec_t left;
- log_unit_debug(UNIT(t), "Monotonic timer elapses in %s.", format_timespan(buf, sizeof(buf), t->next_elapse_monotonic_or_boottime > ts_monotonic ? t->next_elapse_monotonic_or_boottime - ts_monotonic : 0, 0));
+ add_random(t, &t->next_elapse_monotonic_or_boottime);
+
+ left = t->next_elapse_monotonic_or_boottime > ts_monotonic ? t->next_elapse_monotonic_or_boottime - ts_monotonic : 0;
+ log_unit_debug(UNIT(t), "Monotonic timer elapses in %s.", format_timespan(buf, sizeof(buf), left, 0));
if (t->monotonic_event_source) {
r = sd_event_source_set_time(t->monotonic_event_source, t->next_elapse_monotonic_or_boottime);
@@ -451,6 +511,9 @@ static void timer_enter_waiting(Timer *t, bool initial) {
if (found_realtime) {
char buf[FORMAT_TIMESTAMP_MAX];
+
+ add_random(t, &t->next_elapse_realtime);
+
log_unit_debug(UNIT(t), "Realtime timer elapses at %s.", format_timestamp(buf, sizeof(buf), t->next_elapse_realtime));
if (t->realtime_event_source) {
@@ -499,15 +562,14 @@ static void timer_enter_running(Timer *t) {
if (unit_stop_pending(UNIT(t)))
return;
- r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_TRIGGER(UNIT(t)),
- JOB_REPLACE, true, &error, NULL);
+ r = manager_add_job(UNIT(t)->manager, JOB_START, UNIT_TRIGGER(UNIT(t)), JOB_REPLACE, &error, NULL);
if (r < 0)
goto fail;
dual_timestamp_get(&t->last_trigger);
if (t->stamp_path)
- touch_file(t->stamp_path, true, t->last_trigger.realtime, UID_INVALID, GID_INVALID, 0);
+ touch_file(t->stamp_path, true, t->last_trigger.realtime, UID_INVALID, GID_INVALID, MODE_INVALID);
timer_set_state(t, TIMER_RUNNING);
return;
@@ -543,7 +605,7 @@ static int timer_start(Unit *u) {
/* The timer has never run before,
* make sure a stamp file exists.
*/
- touch_file(t->stamp_path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, 0);
+ touch_file(t->stamp_path, true, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);
}
t->result = TIMER_SUCCESS;
diff --git a/src/core/timer.h b/src/core/timer.h
index ac5af6a93c..0599f07818 100644
--- a/src/core/timer.h
+++ b/src/core/timer.h
@@ -58,6 +58,7 @@ struct Timer {
Unit meta;
usec_t accuracy_usec;
+ usec_t random_usec;
LIST_HEAD(TimerValue, values);
usec_t next_elapse_realtime;
@@ -73,6 +74,7 @@ struct Timer {
bool persistent;
bool wake_system;
+ bool remain_after_elapse;
char *stamp_path;
};
diff --git a/src/core/transaction.c b/src/core/transaction.c
index d1c1b9a3cd..15e79d00b3 100644
--- a/src/core/transaction.c
+++ b/src/core/transaction.c
@@ -19,13 +19,14 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <unistd.h>
#include <fcntl.h>
+#include <unistd.h>
+#include "alloc-util.h"
#include "bus-common-errors.h"
#include "bus-error.h"
-#include "transaction.h"
#include "terminal-util.h"
+#include "transaction.h"
static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependencies);
@@ -98,9 +99,7 @@ static void transaction_merge_and_delete_job(Transaction *tr, Job *j, Job *other
j->type = t;
j->state = JOB_WAITING;
- j->override = j->override || other->override;
j->irreversible = j->irreversible || other->irreversible;
-
j->matters_to_anchor = j->matters_to_anchor || other->matters_to_anchor;
/* Patch us in as new owner of the JobDependency objects */
@@ -744,7 +743,7 @@ int transaction_activate(Transaction *tr, Manager *m, JobMode mode, sd_bus_error
return 0;
}
-static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, bool override, bool *is_new) {
+static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, bool *is_new) {
Job *j, *f;
assert(tr);
@@ -773,7 +772,6 @@ static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, b
j->generation = 0;
j->marker = NULL;
j->matters_to_anchor = false;
- j->override = override;
j->irreversible = tr->irreversible;
LIST_PREPEND(transaction, f, j);
@@ -832,7 +830,6 @@ int transaction_add_job_and_dependencies(
Unit *unit,
Job *by,
bool matters,
- bool override,
bool conflicts,
bool ignore_requirements,
bool ignore_order,
@@ -894,7 +891,7 @@ int transaction_add_job_and_dependencies(
/* First add the job. */
- ret = transaction_add_one_job(tr, type, unit, override, &is_new);
+ ret = transaction_add_one_job(tr, type, unit, &is_new);
if (!ret)
return -ENOMEM;
@@ -917,7 +914,7 @@ int transaction_add_job_and_dependencies(
* 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);
+ r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, false, false, ignore_order, e);
if (r < 0) {
log_unit_warning(dep, "Cannot add dependency job for, ignoring: %s", bus_error_message(e, r));
sd_bus_error_free(e);
@@ -930,7 +927,7 @@ int transaction_add_job_and_dependencies(
/* 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);
+ r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, false, false, ignore_order, e);
if (r < 0) {
if (r != -EBADR)
goto fail;
@@ -940,7 +937,7 @@ int transaction_add_job_and_dependencies(
}
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);
+ r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, false, false, ignore_order, e);
if (r < 0) {
if (r != -EBADR)
goto fail;
@@ -949,19 +946,8 @@ int transaction_add_job_and_dependencies(
}
}
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) {
- r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, !override, override, false, false, ignore_order, e);
- if (r < 0) {
- log_unit_full(dep,
- r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, r,
- "Cannot add dependency job, ignoring: %s",
- bus_error_message(e, r));
- sd_bus_error_free(e);
- }
- }
-
SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) {
- r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, false, ignore_order, e);
+ r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, ignore_order, e);
if (r < 0) {
log_unit_full(dep,
r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, r,
@@ -972,7 +958,7 @@ int transaction_add_job_and_dependencies(
}
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);
+ r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, false, false, ignore_order, e);
if (r < 0) {
if (r != -EBADR)
goto fail;
@@ -981,19 +967,8 @@ int transaction_add_job_and_dependencies(
}
}
- SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) {
- r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e);
- if (r < 0) {
- log_unit_full(dep,
- r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, r,
- "Cannot add dependency job, ignoring: %s",
- bus_error_message(e, r));
- sd_bus_error_free(e);
- }
- }
-
SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i) {
- r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e);
+ r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, true, false, ignore_order, e);
if (r < 0) {
if (r != -EBADR)
goto fail;
@@ -1003,7 +978,7 @@ int transaction_add_job_and_dependencies(
}
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);
+ r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, false, false, ignore_order, e);
if (r < 0) {
log_unit_warning(dep,
"Cannot add dependency job, ignoring: %s",
@@ -1038,7 +1013,7 @@ int transaction_add_job_and_dependencies(
if (nt == JOB_NOP)
continue;
- r = transaction_add_job_and_dependencies(tr, nt, dep, ret, true, override, false, false, ignore_order, e);
+ r = transaction_add_job_and_dependencies(tr, nt, dep, ret, true, false, false, ignore_order, e);
if (r < 0) {
if (r != -EBADR)
goto fail;
@@ -1051,7 +1026,7 @@ int transaction_add_job_and_dependencies(
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);
+ r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, false, false, ignore_order, e);
if (r < 0) {
log_unit_warning(dep,
"Cannot add dependency reload job, ignoring: %s",
@@ -1096,7 +1071,7 @@ int transaction_add_isolate_jobs(Transaction *tr, Manager *m) {
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);
+ r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, tr->anchor_job, true, false, false, false, NULL);
if (r < 0)
log_unit_warning_errno(u, r, "Cannot add isolate job, ignoring: %m");
}
diff --git a/src/core/transaction.h b/src/core/transaction.h
index d949b21b8d..5c4a13edab 100644
--- a/src/core/transaction.h
+++ b/src/core/transaction.h
@@ -23,10 +23,10 @@
typedef struct Transaction Transaction;
-#include "unit.h"
-#include "manager.h"
-#include "job.h"
#include "hashmap.h"
+#include "job.h"
+#include "manager.h"
+#include "unit.h"
struct Transaction {
/* Jobs to be added */
@@ -44,7 +44,6 @@ int transaction_add_job_and_dependencies(
Unit *unit,
Job *by,
bool matters,
- bool override,
bool conflicts,
bool ignore_requirements,
bool ignore_order,
diff --git a/src/core/triggers.systemd.in b/src/core/triggers.systemd.in
new file mode 100644
index 0000000000..141f42dbcf
--- /dev/null
+++ b/src/core/triggers.systemd.in
@@ -0,0 +1,26 @@
+# -*- Mode: rpm-spec; indent-tabs-mode: nil -*- */
+#
+# This file is part of systemd.
+#
+# Copyright 2015 Zbigniew Jędrzejewski-Szmek
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# systemd is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with systemd; If not, see <http://www.gnu.org/licenses/>.
+
+# The contents of this are an example to be copied into systemd.spec.
+
+%transfiletriggerin -- @systemunitdir@ /etc/systemd/system
+systemctl daemon-reload &>/dev/null || :
+
+%transfiletriggerun -- @systemunitdir@ /etc/systemd/system
+systemctl daemon-reload &>/dev/null || :
diff --git a/src/core/umount.c b/src/core/umount.c
index 22dbe67259..9d1f7660db 100644
--- a/src/core/umount.c
+++ b/src/core/umount.c
@@ -21,23 +21,30 @@
#include <errno.h>
#include <fcntl.h>
+#include <linux/dm-ioctl.h>
+#include <linux/loop.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/swap.h>
-#include <linux/loop.h>
-#include <linux/dm-ioctl.h>
+#include "libudev.h"
+
+#include "alloc-util.h"
+#include "escape.h"
+#include "fd-util.h"
+#include "fstab-util.h"
#include "list.h"
#include "mount-setup.h"
-#include "umount.h"
#include "path-util.h"
+#include "string-util.h"
+#include "udev-util.h"
+#include "umount.h"
#include "util.h"
#include "virt.h"
-#include "libudev.h"
-#include "udev-util.h"
typedef struct MountPoint {
char *path;
+ char *options;
dev_t devnum;
LIST_FIELDS(struct MountPoint, mount_point);
} MountPoint;
@@ -71,7 +78,7 @@ static int mount_points_list_get(MountPoint **head) {
return -errno;
for (i = 1;; i++) {
- _cleanup_free_ char *path = NULL;
+ _cleanup_free_ char *path = NULL, *options = NULL;
char *p = NULL;
MountPoint *m;
int k;
@@ -82,15 +89,15 @@ static int mount_points_list_get(MountPoint **head) {
"%*s " /* (3) major:minor */
"%*s " /* (4) root */
"%ms " /* (5) mount point */
- "%*s" /* (6) mount options */
+ "%*s" /* (6) mount flags */
"%*[^-]" /* (7) optional fields */
"- " /* (8) separator */
"%*s " /* (9) file system type */
"%*s" /* (10) mount source */
- "%*s" /* (11) mount options 2 */
+ "%ms" /* (11) mount options */
"%*[^\n]", /* some rubbish at the end */
- &path);
- if (k != 1) {
+ &path, &options);
+ if (k != 2) {
if (k == EOF)
break;
@@ -125,6 +132,9 @@ static int mount_points_list_get(MountPoint **head) {
}
m->path = p;
+ m->options = options;
+ options = NULL;
+
LIST_PREPEND(mount_point, *head, m);
}
@@ -369,6 +379,14 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_e
benefits, but might confuse the host, as we remount
the superblock here, not the bind mound. */
if (detect_container() <= 0) {
+ _cleanup_free_ char *options = NULL;
+ /* MS_REMOUNT requires that the data parameter
+ * should be the same from the original mount
+ * except for the desired changes. Since we want
+ * to remount read-only, we should filter out
+ * rw (and ro too, because it confuses the kernel) */
+ (void) fstab_filter_options(m->options, "rw\0ro\0", NULL, NULL, &options);
+
/* We always try to remount directories
* read-only first, before we go on and umount
* them.
@@ -385,7 +403,8 @@ static int mount_points_list_umount(MountPoint **head, bool *changed, bool log_e
* alias read-only we hence should be
* relatively safe regarding keeping the fs we
* can otherwise not see dirty. */
- (void) mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, NULL);
+ log_info("Remounting '%s' read-only with options '%s'.", m->path, options);
+ (void) mount(NULL, m->path, NULL, MS_REMOUNT|MS_RDONLY, options);
}
/* Skip / and /usr since we cannot unmount that
diff --git a/src/core/unit-printf.c b/src/core/unit-printf.c
index 0889769d03..f587a5a141 100644
--- a/src/core/unit-printf.c
+++ b/src/core/unit-printf.c
@@ -19,14 +19,17 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include "unit.h"
+#include "alloc-util.h"
+#include "cgroup-util.h"
+#include "formats-util.h"
+#include "macro.h"
#include "specifier.h"
+#include "string-util.h"
#include "strv.h"
#include "unit-name.h"
#include "unit-printf.h"
-#include "macro.h"
-#include "cgroup-util.h"
-#include "formats-util.h"
+#include "unit.h"
+#include "user-util.h"
static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) {
Unit *u = userdata;
@@ -63,10 +66,7 @@ static int specifier_instance_unescaped(char specifier, void *data, void *userda
assert(u);
- if (!u->instance)
- return -EINVAL;
-
- return unit_name_unescape(u->instance, ret);
+ return unit_name_unescape(strempty(u->instance), ret);
}
static int specifier_filename(char specifier, void *data, void *userdata, char **ret) {
@@ -128,6 +128,8 @@ static int specifier_cgroup_slice(char specifier, void *data, void *userdata, ch
n = unit_default_cgroup_path(slice);
} else
n = strdup(u->manager->cgroup_root);
+ if (!n)
+ return -ENOMEM;
*ret = n;
return 0;
@@ -157,162 +159,43 @@ static int specifier_runtime(char specifier, void *data, void *userdata, char **
}
static int specifier_user_name(char specifier, void *data, void *userdata, char **ret) {
- char *printed = NULL;
- Unit *u = userdata;
- ExecContext *c;
- int r = 0;
-
- assert(u);
-
- c = unit_get_exec_context(u);
- if (!c)
- return -EINVAL;
-
- if (u->manager->running_as == MANAGER_SYSTEM) {
-
- /* We cannot use NSS from PID 1, hence try to make the
- * best of it in that case, and fail if we can't help
- * it */
+ char *t;
- if (!c->user || streq(c->user, "root") || streq(c->user, "0"))
- printed = strdup(specifier == 'u' ? "root" : "0");
- else {
- if (specifier == 'u')
- printed = strdup(c->user);
- else {
- uid_t uid;
+ /* If we are UID 0 (root), this will not result in NSS,
+ * otherwise it might. This is good, as we want to be able to
+ * run this in PID 1, where our user ID is 0, but where NSS
+ * lookups are not allowed. */
- r = parse_uid(c->user, &uid);
- if (r < 0)
- return -ENODATA;
-
- r = asprintf(&printed, UID_FMT, uid);
- }
- }
-
- } else {
- _cleanup_free_ char *tmp = NULL;
- const char *username = NULL;
- uid_t uid;
-
- if (c->user)
- username = c->user;
- else
- /* get USER env from env or our own uid */
- username = tmp = getusername_malloc();
-
- /* fish username from passwd */
- r = get_user_creds(&username, &uid, NULL, NULL, NULL);
- if (r < 0)
- return r;
-
- if (specifier == 'u')
- printed = strdup(username);
- else
- r = asprintf(&printed, UID_FMT, uid);
- }
-
- if (r < 0 || !printed)
+ t = getusername_malloc();
+ if (!t)
return -ENOMEM;
- *ret = printed;
+ *ret = t;
return 0;
}
-static int specifier_user_home(char specifier, void *data, void *userdata, char **ret) {
- Unit *u = userdata;
- ExecContext *c;
- char *n;
- int r;
-
- assert(u);
-
- c = unit_get_exec_context(u);
- if (!c)
- return -EOPNOTSUPP;
-
- if (u->manager->running_as == MANAGER_SYSTEM) {
+static int specifier_user_id(char specifier, void *data, void *userdata, char **ret) {
- /* We cannot use NSS from PID 1, hence try to make the
- * best of it if we can, but fail if we can't */
-
- if (!c->user || streq(c->user, "root") || streq(c->user, "0"))
- n = strdup("/root");
- else
- return -EOPNOTSUPP;
-
- } else {
-
- /* return HOME if set, otherwise from passwd */
- if (!c || !c->user) {
- r = get_home_dir(&n);
- if (r < 0)
- return r;
- } else {
- const char *username, *home;
-
- username = c->user;
- r = get_user_creds(&username, NULL, NULL, &home, NULL);
- if (r < 0)
- return r;
-
- n = strdup(home);
- }
- }
-
- if (!n)
+ if (asprintf(ret, UID_FMT, getuid()) < 0)
return -ENOMEM;
- *ret = n;
return 0;
}
-static int specifier_user_shell(char specifier, void *data, void *userdata, char **ret) {
- Unit *u = userdata;
- ExecContext *c;
- char *n;
- int r;
-
- assert(u);
-
- c = unit_get_exec_context(u);
- if (!c)
- return -EOPNOTSUPP;
-
- if (u->manager->running_as == MANAGER_SYSTEM) {
-
- /* We cannot use NSS from PID 1, hence try to make the
- * best of it if we can, but fail if we can't */
-
- if (!c->user || streq(c->user, "root") || streq(c->user, "0"))
- n = strdup("/bin/sh");
- else
- return -EOPNOTSUPP;
-
- } else {
+static int specifier_user_home(char specifier, void *data, void *userdata, char **ret) {
- /* return /bin/sh for root, otherwise the value from passwd */
- if (!c->user) {
- r = get_shell(&n);
- if (r < 0)
- return r;
- } else {
- const char *username, *shell;
+ /* On PID 1 (which runs as root) this will not result in NSS,
+ * which is good. See above */
- username = c->user;
- r = get_user_creds(&username, NULL, NULL, NULL, &shell);
- if (r < 0)
- return r;
+ return get_home_dir(ret);
+}
- n = strdup(shell);
- }
- }
+static int specifier_user_shell(char specifier, void *data, void *userdata, char **ret) {
- if (!n)
- return -ENOMEM;
+ /* On PID 1 (which runs as root) this will not result in NSS,
+ * which is good. See above */
- *ret = n;
- return 0;
+ return get_shell(ret);
}
int unit_name_printf(Unit *u, const char* format, char **ret) {
@@ -352,10 +235,10 @@ int unit_full_printf(Unit *u, const char *format, char **ret) {
* %r where units in this slice are placed in the cgroup tree
* %R the root of this systemd's instance tree
* %t the runtime directory to place sockets in (e.g. "/run" or $XDG_RUNTIME_DIR)
- * %U the UID of the configured user or running user
- * %u the username of the configured user or running user
- * %h the homedir of the configured user or running user
- * %s the shell of the configured user or running user
+ * %U the UID of the running user
+ * %u the username of the running user
+ * %h the homedir of the running user
+ * %s the shell of the running user
* %m the machine ID of the running system
* %H the host name of the running system
* %b the boot ID of the running system
@@ -375,7 +258,8 @@ int unit_full_printf(Unit *u, const char *format, char **ret) {
{ 'r', specifier_cgroup_slice, NULL },
{ 'R', specifier_cgroup_root, NULL },
{ 't', specifier_runtime, NULL },
- { 'U', specifier_user_name, NULL },
+
+ { 'U', specifier_user_id, NULL },
{ 'u', specifier_user_name, NULL },
{ 'h', specifier_user_home, NULL },
{ 's', specifier_user_shell, NULL },
diff --git a/src/core/unit.c b/src/core/unit.c
index 33c0317ce0..0a02e38aa8 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -20,43 +20,49 @@
***/
#include <errno.h>
-#include <string.h>
#include <stdlib.h>
-#include <unistd.h>
+#include <string.h>
#include <sys/stat.h>
+#include <unistd.h>
#include "sd-id128.h"
#include "sd-messages.h"
-#include "set.h"
-#include "macro.h"
-#include "strv.h"
-#include "path-util.h"
-#include "log.h"
+
+#include "alloc-util.h"
+#include "bus-common-errors.h"
+#include "bus-util.h"
#include "cgroup-util.h"
-#include "missing.h"
-#include "mkdir.h"
+#include "dbus-unit.h"
+#include "dbus.h"
+#include "dropin.h"
+#include "escape.h"
+#include "execute.h"
#include "fileio-label.h"
#include "formats-util.h"
+#include "load-dropin.h"
+#include "load-fragment.h"
+#include "log.h"
+#include "macro.h"
+#include "missing.h"
+#include "mkdir.h"
+#include "parse-util.h"
+#include "path-util.h"
#include "process-util.h"
-#include "virt.h"
-#include "bus-common-errors.h"
-#include "bus-util.h"
-#include "dropin.h"
-#include "unit-name.h"
+#include "set.h"
#include "special.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "unit-name.h"
#include "unit.h"
-#include "load-fragment.h"
-#include "load-dropin.h"
-#include "dbus.h"
-#include "dbus-unit.h"
-#include "execute.h"
+#include "user-util.h"
+#include "virt.h"
const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX] = {
[UNIT_SERVICE] = &service_vtable,
[UNIT_SOCKET] = &socket_vtable,
[UNIT_BUSNAME] = &busname_vtable,
[UNIT_TARGET] = &target_vtable,
- [UNIT_SNAPSHOT] = &snapshot_vtable,
[UNIT_DEVICE] = &device_vtable,
[UNIT_MOUNT] = &mount_vtable,
[UNIT_AUTOMOUNT] = &automount_vtable,
@@ -126,6 +132,9 @@ static void unit_init(Unit *u) {
cc->blockio_accounting = u->manager->default_blockio_accounting;
cc->memory_accounting = u->manager->default_memory_accounting;
cc->tasks_accounting = u->manager->default_tasks_accounting;
+
+ if (u->type != UNIT_SLICE)
+ cc->tasks_max = u->manager->default_tasks_max;
}
ec = unit_get_exec_context(u);
@@ -308,9 +317,6 @@ bool unit_check_gc(Unit *u) {
if (state != UNIT_INACTIVE)
return true;
- if (UNIT_VTABLE(u)->no_gc)
- return true;
-
if (u->no_gc)
return true;
@@ -412,12 +418,11 @@ static void unit_remove_transient(Unit *u) {
STRV_FOREACH(i, u->dropin_paths) {
_cleanup_free_ char *p = NULL;
- int r;
(void) unlink(*i);
- r = path_get_parent(*i, &p);
- if (r >= 0)
+ p = dirname_malloc(*i);
+ if (p)
(void) rmdir(p);
}
}
@@ -992,15 +997,13 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
"%s\tRefuseManualStop: %s\n"
"%s\tDefaultDependencies: %s\n"
"%s\tOnFailureJobMode: %s\n"
- "%s\tIgnoreOnIsolate: %s\n"
- "%s\tIgnoreOnSnapshot: %s\n",
+ "%s\tIgnoreOnIsolate: %s\n",
prefix, yes_no(u->stop_when_unneeded),
prefix, yes_no(u->refuse_manual_start),
prefix, yes_no(u->refuse_manual_stop),
prefix, yes_no(u->default_dependencies),
prefix, job_mode_to_string(u->on_failure_job_mode),
- prefix, yes_no(u->ignore_on_isolate),
- prefix, yes_no(u->ignore_on_snapshot));
+ prefix, yes_no(u->ignore_on_isolate));
if (UNIT_VTABLE(u)->dump)
UNIT_VTABLE(u)->dump(u, f, prefix2);
@@ -1098,9 +1101,7 @@ static int unit_add_target_dependencies(Unit *u) {
static const UnitDependency deps[] = {
UNIT_REQUIRED_BY,
- UNIT_REQUIRED_BY_OVERRIDABLE,
UNIT_REQUISITE_OF,
- UNIT_REQUISITE_OF_OVERRIDABLE,
UNIT_WANTED_BY,
UNIT_BOUND_BY
};
@@ -1147,13 +1148,23 @@ static int unit_add_mount_dependencies(Unit *u) {
char prefix[strlen(*i) + 1];
PATH_FOREACH_PREFIX_MORE(prefix, *i) {
+ _cleanup_free_ char *p = NULL;
Unit *m;
- r = manager_get_unit_by_path(u->manager, prefix, ".mount", &m);
+ r = unit_name_from_path(prefix, ".mount", &p);
if (r < 0)
return r;
- if (r == 0)
+
+ m = manager_get_unit(u->manager, p);
+ if (!m) {
+ /* Make sure to load the mount unit if
+ * it exists. If so the dependencies
+ * on this unit will be added later
+ * during the loading of the mount
+ * unit. */
+ (void) manager_load_unit_prepare(u->manager, p, NULL, NULL, &m);
continue;
+ }
if (m == u)
continue;
@@ -1336,12 +1347,18 @@ static bool unit_assert_test(Unit *u) {
return u->assert_result;
}
+void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) {
+ DISABLE_WARNING_FORMAT_NONLITERAL;
+ manager_status_printf(u->manager, STATUS_TYPE_NORMAL, status, unit_status_msg_format, unit_description(u));
+ REENABLE_WARNING;
+}
+
_pure_ static const char* unit_get_status_message_format(Unit *u, JobType t) {
const char *format;
const UnitStatusMessageFormats *format_table;
assert(u);
- assert(t == JOB_START || t == JOB_STOP || t == JOB_RELOAD);
+ assert(IN_SET(t, JOB_START, JOB_STOP, JOB_RELOAD));
if (t != JOB_RELOAD) {
format_table = &UNIT_VTABLE(u)->status_message_formats;
@@ -1366,6 +1383,10 @@ static void unit_status_print_starting_stopping(Unit *u, JobType t) {
assert(u);
+ /* Reload status messages have traditionally not been printed to console. */
+ if (!IN_SET(t, JOB_START, JOB_STOP))
+ return;
+
format = unit_get_status_message_format(u, t);
DISABLE_WARNING_FORMAT_NONLITERAL;
@@ -1380,7 +1401,7 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
assert(u);
- if (t != JOB_START && t != JOB_STOP && t != JOB_RELOAD)
+ if (!IN_SET(t, JOB_START, JOB_STOP, JOB_RELOAD))
return;
if (log_on_console())
@@ -1412,12 +1433,12 @@ static void unit_status_log_starting_stopping_reloading(Unit *u, JobType t) {
}
void unit_status_emit_starting_stopping_reloading(Unit *u, JobType t) {
+ assert(u);
+ assert(t >= 0);
+ assert(t < _JOB_TYPE_MAX);
unit_status_log_starting_stopping_reloading(u, t);
-
- /* Reload status messages have traditionally not been printed to console. */
- if (t != JOB_RELOAD)
- unit_status_print_starting_stopping(u, t);
+ unit_status_print_starting_stopping(u, t);
}
/* Errors:
@@ -1592,11 +1613,11 @@ bool unit_can_reload(Unit *u) {
static void unit_check_unneeded(Unit *u) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
+
static const UnitDependency needed_dependencies[] = {
UNIT_REQUIRED_BY,
- UNIT_REQUIRED_BY_OVERRIDABLE,
UNIT_REQUISITE_OF,
- UNIT_REQUISITE_OF_OVERRIDABLE,
UNIT_WANTED_BY,
UNIT_BOUND_BY,
};
@@ -1633,12 +1654,13 @@ static void unit_check_unneeded(Unit *u) {
log_unit_info(u, "Unit not needed anymore. Stopping.");
/* Ok, nobody needs us anymore. Sniff. Then let's commit suicide */
- r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, true, NULL, NULL);
+ r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, &error, NULL);
if (r < 0)
- log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %m");
+ log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %s", bus_error_message(&error, r));
}
static void unit_check_binds_to(Unit *u) {
+ _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
bool stop = false;
Unit *other;
Iterator i;
@@ -1678,9 +1700,9 @@ static void unit_check_binds_to(Unit *u) {
log_unit_info(u, "Unit is bound to inactive unit %s. Stopping, too.", other->id);
/* A unit we need to run is gone. Sniff. Let's stop this. */
- r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, true, NULL, NULL);
+ r = manager_add_job(u->manager, JOB_STOP, u, JOB_FAIL, &error, NULL);
if (r < 0)
- log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %m");
+ log_unit_warning_errno(u, r, "Failed to enqueue stop job, ignoring: %s", bus_error_message(&error, r));
}
static void retroactively_start_dependencies(Unit *u) {
@@ -1693,30 +1715,25 @@ static void retroactively_start_dependencies(Unit *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);
+ manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL);
SET_FOREACH(other, u->dependencies[UNIT_BINDS_TO], i)
if (!set_get(u->dependencies[UNIT_AFTER], other) &&
!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
- manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, 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);
+ manager_add_job(u->manager, JOB_START, other, JOB_REPLACE, NULL, NULL);
SET_FOREACH(other, u->dependencies[UNIT_WANTS], i)
if (!set_get(u->dependencies[UNIT_AFTER], other) &&
!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(other)))
- manager_add_job(u->manager, JOB_START, other, JOB_FAIL, false, NULL, NULL);
+ manager_add_job(u->manager, JOB_START, other, JOB_FAIL, NULL, NULL);
SET_FOREACH(other, u->dependencies[UNIT_CONFLICTS], i)
if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
- manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL);
+ manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL);
SET_FOREACH(other, u->dependencies[UNIT_CONFLICTED_BY], i)
if (!UNIT_IS_INACTIVE_OR_DEACTIVATING(unit_active_state(other)))
- manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, true, NULL, NULL);
+ manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL);
}
static void retroactively_stop_dependencies(Unit *u) {
@@ -1729,7 +1746,7 @@ static void retroactively_stop_dependencies(Unit *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);
+ manager_add_job(u->manager, JOB_STOP, other, JOB_REPLACE, NULL, NULL);
}
static void check_unneeded_dependencies(Unit *u) {
@@ -1743,18 +1760,12 @@ static void check_unneeded_dependencies(Unit *u) {
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);
@@ -1774,7 +1785,7 @@ void unit_start_on_failure(Unit *u) {
SET_FOREACH(other, u->dependencies[UNIT_ON_FAILURE], i) {
int r;
- r = manager_add_job(u->manager, JOB_START, other, u->on_failure_job_mode, true, NULL, NULL);
+ r = manager_add_job(u->manager, JOB_START, other, u->on_failure_job_mode, NULL, NULL);
if (r < 0)
log_unit_error_errno(u, r, "Failed to enqueue OnFailure= job: %m");
}
@@ -2122,16 +2133,12 @@ int unit_add_dependency(Unit *u, UnitDependency d, Unit *other, bool add_referen
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_REQUISITE_OF,
- [UNIT_REQUISITE_OVERRIDABLE] = UNIT_REQUISITE_OF_OVERRIDABLE,
[UNIT_BINDS_TO] = UNIT_BOUND_BY,
[UNIT_PART_OF] = UNIT_CONSISTS_OF,
[UNIT_REQUIRED_BY] = UNIT_REQUIRES,
- [UNIT_REQUIRED_BY_OVERRIDABLE] = UNIT_REQUIRES_OVERRIDABLE,
[UNIT_REQUISITE_OF] = UNIT_REQUISITE,
- [UNIT_REQUISITE_OF_OVERRIDABLE] = UNIT_REQUISITE_OVERRIDABLE,
[UNIT_WANTED_BY] = UNIT_WANTS,
[UNIT_BOUND_BY] = UNIT_BINDS_TO,
[UNIT_CONSISTS_OF] = UNIT_PART_OF,
@@ -2310,47 +2317,9 @@ int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency
return unit_add_two_dependencies(u, d, e, other, add_reference);
}
-int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *path, bool add_reference) {
- _cleanup_free_ char *buf = NULL;
- Unit *other;
- int r;
-
- assert(u);
- assert(name || path);
-
- r = resolve_template(u, name, path, &buf, &name);
- if (r < 0)
- return r;
-
- r = manager_load_unit(u->manager, name, path, NULL, &other);
- if (r < 0)
- return r;
-
- return unit_add_dependency(other, d, u, add_reference);
-}
-
-int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference) {
- _cleanup_free_ char *buf = NULL;
- Unit *other;
- int r;
-
- assert(u);
- assert(name || path);
-
- r = resolve_template(u, name, path, &buf, &name);
- if (r < 0)
- return r;
-
- r = manager_load_unit(u->manager, name, path, NULL, &other);
- if (r < 0)
- return r;
-
- return unit_add_two_dependencies(other, d, e, u, add_reference);
-}
-
int set_unit_path(const char *p) {
/* This is mostly for debug purposes */
- if (setenv("SYSTEMD_UNIT_PATH", p, 0) < 0)
+ if (setenv("SYSTEMD_UNIT_PATH", p, 1) < 0)
return -errno;
return 0;
@@ -2498,26 +2467,23 @@ static int signal_name_owner_changed(sd_bus_message *message, void *userdata, sd
return 0;
}
-int unit_install_bus_match(sd_bus *bus, Unit *u, const char *name) {
- _cleanup_free_ char *match = NULL;
- Manager *m = u->manager;
+int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name) {
+ const char *match;
- assert(m);
+ assert(u);
+ assert(bus);
+ assert(name);
if (u->match_bus_slot)
return -EBUSY;
- match = strjoin("type='signal',"
+ match = strjoina("type='signal',"
"sender='org.freedesktop.DBus',"
"path='/org/freedesktop/DBus',"
"interface='org.freedesktop.DBus',"
"member='NameOwnerChanged',"
- "arg0='",
- name,
- "'",
+ "arg0='", name, "'",
NULL);
- if (!match)
- return -ENOMEM;
return sd_bus_add_match(bus, &u->match_bus_slot, match, signal_name_owner_changed, u);
}
@@ -2534,9 +2500,9 @@ int unit_watch_bus_name(Unit *u, const char *name) {
if (u->manager->api_bus) {
/* If the bus is already available, install the match directly.
* Otherwise, just put the name in the list. bus_setup_api() will take care later. */
- r = unit_install_bus_match(u->manager->api_bus, u, name);
+ r = unit_install_bus_match(u, u->manager->api_bus, name);
if (r < 0)
- return log_warning_errno(r, "Failed to subscribe to NameOwnerChanged signal: %m");
+ return log_warning_errno(r, "Failed to subscribe to NameOwnerChanged signal for '%s': %m", name);
}
r = hashmap_put(u->manager->watch_bus, name, u);
@@ -2624,6 +2590,62 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
return 0;
}
+int unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) {
+ assert(u);
+ assert(f);
+ assert(key);
+
+ if (!value)
+ return 0;
+
+ fputs(key, f);
+ fputc('=', f);
+ fputs(value, f);
+ fputc('\n', f);
+
+ return 1;
+}
+
+int unit_serialize_item_escaped(Unit *u, FILE *f, const char *key, const char *value) {
+ _cleanup_free_ char *c = NULL;
+
+ assert(u);
+ assert(f);
+ assert(key);
+
+ if (!value)
+ return 0;
+
+ c = cescape(value);
+ if (!c)
+ return -ENOMEM;
+
+ fputs(key, f);
+ fputc('=', f);
+ fputs(c, f);
+ fputc('\n', f);
+
+ return 1;
+}
+
+int unit_serialize_item_fd(Unit *u, FILE *f, FDSet *fds, const char *key, int fd) {
+ int copy;
+
+ assert(u);
+ assert(f);
+ assert(key);
+
+ if (fd < 0)
+ return 0;
+
+ copy = fdset_put_dup(fds, fd);
+ if (copy < 0)
+ return copy;
+
+ fprintf(f, "%s=%i\n", key, copy);
+ return 1;
+}
+
void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *format, ...) {
va_list ap;
@@ -2642,15 +2664,6 @@ void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *f
fputc('\n', f);
}
-void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value) {
- assert(u);
- assert(f);
- assert(key);
- assert(value);
-
- fprintf(f, "%s=%s\n", key, value);
-}
-
int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
ExecRuntime **rt = NULL;
size_t offset;
@@ -2868,7 +2881,7 @@ int unit_add_node_link(Unit *u, const char *what, bool wants) {
}
int unit_coldplug(Unit *u) {
- int r;
+ int r = 0, q = 0;
assert(u);
@@ -2879,26 +2892,18 @@ int unit_coldplug(Unit *u) {
u->coldplugged = true;
- if (UNIT_VTABLE(u)->coldplug) {
+ if (UNIT_VTABLE(u)->coldplug)
r = UNIT_VTABLE(u)->coldplug(u);
- if (r < 0)
- return r;
- }
- if (u->job) {
- r = job_coldplug(u->job);
- if (r < 0)
- return r;
- }
+ if (u->job)
+ q = job_coldplug(u->job);
- return 0;
-}
+ if (r < 0)
+ return r;
+ if (q < 0)
+ return q;
-void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) {
- DISABLE_WARNING_FORMAT_NONLITERAL;
- manager_status_printf(u->manager, STATUS_TYPE_NORMAL,
- status, unit_status_msg_format, unit_description(u));
- REENABLE_WARNING;
+ return 0;
}
bool unit_need_daemon_reload(Unit *u) {
@@ -3130,12 +3135,19 @@ int unit_following_set(Unit *u, Set **s) {
}
UnitFileState unit_get_unit_file_state(Unit *u) {
+ int r;
+
assert(u);
- if (u->unit_file_state < 0 && u->fragment_path)
- u->unit_file_state = unit_file_get_state(
+ if (u->unit_file_state < 0 && u->fragment_path) {
+ r = unit_file_get_state(
u->manager->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER,
- NULL, basename(u->fragment_path));
+ NULL,
+ basename(u->fragment_path),
+ &u->unit_file_state);
+ if (r < 0)
+ u->unit_file_state = UNIT_FILE_BAD;
+ }
return u->unit_file_state;
}
@@ -3146,7 +3158,8 @@ int unit_get_unit_file_preset(Unit *u) {
if (u->unit_file_preset < 0 && u->fragment_path)
u->unit_file_preset = unit_file_query_preset(
u->manager->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER,
- NULL, basename(u->fragment_path));
+ NULL,
+ basename(u->fragment_path));
return u->unit_file_preset;
}
@@ -3311,19 +3324,6 @@ static int unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode, bool transient,
return 0;
}
-static int unit_drop_in_file(Unit *u, UnitSetPropertiesMode mode, const char *name, char **p, char **q) {
- _cleanup_free_ char *dir = NULL;
- int r;
-
- assert(u);
-
- r = unit_drop_in_dir(u, mode, u->transient, &dir);
- if (r < 0)
- return r;
-
- return drop_in_file(dir, u->id, 50, name, p, q);
-}
-
int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) {
_cleanup_free_ char *dir = NULL, *p = NULL, *q = NULL;
@@ -3422,28 +3422,6 @@ int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const
return unit_write_drop_in_private(u, mode, name, p);
}
-int unit_remove_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name) {
- _cleanup_free_ char *p = NULL, *q = NULL;
- int r;
-
- assert(u);
-
- if (!IN_SET(mode, UNIT_PERSISTENT, UNIT_RUNTIME))
- return 0;
-
- r = unit_drop_in_file(u, mode, name, &p, &q);
- if (r < 0)
- return r;
-
- if (unlink(q) < 0)
- r = errno == ENOENT ? 0 : -errno;
- else
- r = 1;
-
- rmdir(p);
- return r;
-}
-
int unit_make_transient(Unit *u) {
assert(u);
@@ -3453,7 +3431,15 @@ int unit_make_transient(Unit *u) {
u->load_state = UNIT_STUB;
u->load_error = 0;
u->transient = true;
+
u->fragment_path = mfree(u->fragment_path);
+ u->source_path = mfree(u->source_path);
+ u->dropin_paths = strv_free(u->dropin_paths);
+ u->fragment_mtime = u->source_mtime = u->dropin_mtime = 0;
+
+ unit_add_to_dbus_queue(u);
+ unit_add_to_gc_queue(u);
+ unit_add_to_load_queue(u);
return 0;
}
@@ -3729,3 +3715,21 @@ int unit_fail_if_symlink(Unit *u, const char* where) {
return -ELOOP;
}
+
+bool unit_is_pristine(Unit *u) {
+ assert(u);
+
+ /* Check if the unit already exists or is already around,
+ * in a number of different ways. Note that to cater for unit
+ * types such as slice, we are generally fine with units that
+ * are marked UNIT_LOADED even even though nothing was
+ * actually loaded, as those unit types don't require a file
+ * on disk to validly load. */
+
+ return !(!IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_LOADED) ||
+ u->fragment_path ||
+ u->source_path ||
+ !strv_isempty(u->dropin_paths) ||
+ u->job ||
+ u->merged_into);
+}
diff --git a/src/core/unit.h b/src/core/unit.h
index e8d5f86eca..1681bbf53b 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -30,11 +30,11 @@ typedef struct UnitVTable UnitVTable;
typedef struct UnitRef UnitRef;
typedef struct UnitStatusMessageFormats UnitStatusMessageFormats;
-#include "list.h"
#include "condition.h"
+#include "failure-action.h"
#include "install.h"
+#include "list.h"
#include "unit-name.h"
-#include "failure-action.h"
typedef enum KillOperation {
KILL_TERMINATE,
@@ -203,9 +203,6 @@ struct Unit {
/* Ignore this unit when isolating */
bool ignore_on_isolate;
- /* Ignore this unit when snapshotting */
- bool ignore_on_snapshot;
-
/* Did the last condition check succeed? */
bool condition_result;
bool assert_result;
@@ -245,17 +242,16 @@ typedef enum UnitSetPropertiesMode {
UNIT_PERSISTENT = 2,
} UnitSetPropertiesMode;
-#include "socket.h"
+#include "automount.h"
#include "busname.h"
-#include "target.h"
-#include "snapshot.h"
#include "device.h"
-#include "automount.h"
-#include "swap.h"
-#include "timer.h"
-#include "slice.h"
#include "path.h"
#include "scope.h"
+#include "slice.h"
+#include "socket.h"
+#include "swap.h"
+#include "target.h"
+#include "timer.h"
struct UnitVTable {
/* How much memory does an object of this unit type need */
@@ -322,7 +318,7 @@ struct UnitVTable {
int (*deserialize_item)(Unit *u, const char *key, const char *data, FDSet *fds);
/* Try to match up fds with what we need for this unit */
- int (*distribute_fds)(Unit *u, FDSet *fds);
+ void (*distribute_fds)(Unit *u, FDSet *fds);
/* Boils down the more complex internal state of this unit to
* a simpler one that the engine can understand */
@@ -343,9 +339,6 @@ struct UnitVTable {
* shall release its runtime resources */
void (*release_resources)(Unit *u);
- /* Return true when this unit is suitable for snapshotting */
- bool (*check_snapshot)(Unit *u);
-
/* Invoked on every child that died */
void (*sigchld_event)(Unit *u, pid_t pid, int code, int status);
@@ -389,7 +382,7 @@ struct UnitVTable {
* 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);
+ void (*enumerate)(Manager *m);
/* Type specific cleanups. */
void (*shutdown)(Manager *m);
@@ -410,9 +403,6 @@ struct UnitVTable {
/* Instances make no sense for this type */
bool no_instances:1;
- /* Exclude from automatic gc */
- bool no_gc:1;
-
/* True if transient units of this type are OK */
bool can_transient:1;
};
@@ -443,7 +433,6 @@ DEFINE_CAST(SERVICE, Service);
DEFINE_CAST(SOCKET, Socket);
DEFINE_CAST(BUSNAME, BusName);
DEFINE_CAST(TARGET, Target);
-DEFINE_CAST(SNAPSHOT, Snapshot);
DEFINE_CAST(DEVICE, Device);
DEFINE_CAST(MOUNT, Mount);
DEFINE_CAST(AUTOMOUNT, Automount);
@@ -464,9 +453,6 @@ int unit_add_two_dependencies(Unit *u, UnitDependency d, UnitDependency e, Unit
int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference);
int unit_add_two_dependencies_by_name(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference);
-int unit_add_dependency_by_name_inverse(Unit *u, UnitDependency d, const char *name, const char *filename, bool add_reference);
-int unit_add_two_dependencies_by_name_inverse(Unit *u, UnitDependency d, UnitDependency e, const char *name, const char *path, bool add_reference);
-
int unit_add_exec_dependencies(Unit *u, ExecContext *c);
int unit_choose_id(Unit *u, const char *name);
@@ -520,7 +506,7 @@ void unit_unwatch_all_pids(Unit *u);
void unit_tidy_watch_pids(Unit *u, pid_t except1, pid_t except2);
-int unit_install_bus_match(sd_bus *bus, Unit *u, const char *name);
+int unit_install_bus_match(Unit *u, sd_bus *bus, const char *name);
int unit_watch_bus_name(Unit *u, const char *name);
void unit_unwatch_bus_name(Unit *u, const char *name);
@@ -533,11 +519,15 @@ char *unit_dbus_path(Unit *u);
int unit_load_related_unit(Unit *u, const char *type, Unit **_found);
bool unit_can_serialize(Unit *u) _pure_;
+
int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs);
-void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_(4,5);
-void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value);
int unit_deserialize(Unit *u, FILE *f, FDSet *fds);
+int unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value);
+int unit_serialize_item_escaped(Unit *u, FILE *f, const char *key, const char *value);
+int unit_serialize_item_fd(Unit *u, FILE *f, FDSet *fds, const char *key, int fd);
+void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_(4,5);
+
int unit_add_node_link(Unit *u, const char *what, bool wants);
int unit_coldplug(Unit *u);
@@ -588,8 +578,6 @@ int unit_write_drop_in_format(Unit *u, UnitSetPropertiesMode mode, const char *n
int unit_write_drop_in_private(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data);
int unit_write_drop_in_private_format(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *format, ...) _printf_(4,5);
-int unit_remove_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name);
-
int unit_kill_context(Unit *u, KillContext *c, KillOperation k, pid_t main_pid, pid_t control_pid, bool main_pid_alien);
int unit_make_transient(Unit *u);
@@ -598,6 +586,8 @@ int unit_require_mounts_for(Unit *u, const char *path);
bool unit_type_supported(UnitType t);
+bool unit_is_pristine(Unit *u);
+
static inline bool unit_supported(Unit *u) {
return unit_type_supported(u->type);
}