summaryrefslogtreecommitdiff
path: root/src/grp-system
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@sbcglobal.net>2016-09-14 18:33:57 -0400
committerLuke Shumaker <lukeshu@sbcglobal.net>2016-09-14 18:33:57 -0400
commit3c72c8d3ee67388336aca58c5afa3fb93a9c24c0 (patch)
treed072df7fee0f5906fad88c08398b2fe887cbc064 /src/grp-system
parente51613a3291342c6006edda8783755fb8994fd75 (diff)
parent6ba6ca19507add38549e07058c57489a8cd98cd1 (diff)
Merge branch 'notsystemd/postmove' into notsystemd/master
# Conflicts: # src/grp-journal/systemd-journald/Makefile # src/grp-login/systemd-logind/Makefile # src/grp-machine/grp-import/systemd-export/Makefile # src/grp-machine/grp-import/systemd-import/Makefile # src/grp-machine/grp-import/systemd-pull/Makefile # src/grp-machine/systemd-machined/Makefile # src/grp-network/libnetworkd-core/Makefile # src/grp-resolve/libbasic-dns/Makefile # src/grp-resolve/systemd-resolved/Makefile # src/grp-utils/systemd-path/Makefile # src/libshared/src/Makefile # src/libsystemd-network/include/systemd-network/sd-ndisc.h # src/libsystemd/Makefile # src/libsystemd/src/test.mk # src/libudev/Makefile # src/systemd-dbus1-generator/Makefile # src/systemd-nspawn/nspawn.c Signed-off-by: Luke Shumaker <lukeshu@sbcglobal.net>
Diffstat (limited to 'src/grp-system')
-rw-r--r--src/grp-system/grp-utils/systemd-analyze/analyze.c8
-rw-r--r--src/grp-system/grp-utils/systemd-delta/Makefile2
-rw-r--r--src/grp-system/grp-utils/systemd-fstab-generator/Makefile2
-rw-r--r--src/grp-system/grp-utils/systemd-fstab-generator/fstab-generator.c78
-rw-r--r--src/grp-system/grp-utils/systemd-run/Makefile2
-rw-r--r--src/grp-system/grp-utils/systemd-run/run.c2
-rw-r--r--src/grp-system/grp-utils/systemd-run/systemd-run.completion.bash4
-rw-r--r--src/grp-system/grp-utils/systemd-run/systemd-run.completion.zsh4
-rw-r--r--src/grp-system/grp-utils/systemd-sysv-generator/sysv-generator.c101
-rw-r--r--src/grp-system/kernel-command-line.xml4
-rw-r--r--src/grp-system/libcore/Makefile2
-rw-r--r--src/grp-system/libcore/automount.c20
-rw-r--r--src/grp-system/libcore/busname.c7
-rw-r--r--src/grp-system/libcore/cgroup.c242
-rw-r--r--src/grp-system/libcore/cgroup.h5
-rw-r--r--src/grp-system/libcore/dbus-cgroup.c119
-rw-r--r--src/grp-system/libcore/dbus-execute.c95
-rw-r--r--src/grp-system/libcore/dbus-kill.c8
-rw-r--r--src/grp-system/libcore/dbus-manager.c1
-rw-r--r--src/grp-system/libcore/dbus-scope.c4
-rw-r--r--src/grp-system/libcore/dbus-service.c6
-rw-r--r--src/grp-system/libcore/dbus-timer.c12
-rw-r--r--src/grp-system/libcore/dbus-unit.c8
-rw-r--r--src/grp-system/libcore/execute.c348
-rw-r--r--src/grp-system/libcore/execute.h19
-rw-r--r--src/grp-system/libcore/killall.c7
-rw-r--r--src/grp-system/libcore/kmod-setup.c3
-rw-r--r--src/grp-system/libcore/load-fragment-gperf.gperf.m416
-rw-r--r--src/grp-system/libcore/load-fragment.c193
-rw-r--r--src/grp-system/libcore/machine-id-setup.c226
-rw-r--r--src/grp-system/libcore/machine-id-setup.h2
-rw-r--r--src/grp-system/libcore/manager.c74
-rw-r--r--src/grp-system/libcore/manager.h2
-rw-r--r--src/grp-system/libcore/mount-setup.c16
-rw-r--r--src/grp-system/libcore/mount.c1
-rw-r--r--src/grp-system/libcore/namespace.c51
-rw-r--r--src/grp-system/libcore/namespace.h6
-rw-r--r--src/grp-system/libcore/scope.c21
-rw-r--r--src/grp-system/libcore/scope.h2
-rw-r--r--src/grp-system/libcore/selinux-access.c2
-rw-r--r--src/grp-system/libcore/selinux-setup.c2
-rw-r--r--src/grp-system/libcore/service.c80
-rw-r--r--src/grp-system/libcore/service.h2
-rw-r--r--src/grp-system/libcore/socket.c16
-rw-r--r--src/grp-system/libcore/transaction.c7
-rw-r--r--src/grp-system/libcore/unit.c117
-rw-r--r--src/grp-system/libcore/unit.h4
-rw-r--r--src/grp-system/systemctl/Makefile2
-rw-r--r--src/grp-system/systemctl/systemctl.c790
-rw-r--r--src/grp-system/systemctl/systemctl.xml294
-rw-r--r--src/grp-system/systemd-shutdown/Makefile2
-rw-r--r--src/grp-system/systemd-shutdown/shutdown.c20
-rw-r--r--src/grp-system/systemd-shutdown/systemd-shutdown.xml1
-rw-r--r--src/grp-system/systemd/Makefile3
-rw-r--r--src/grp-system/systemd/macros.systemd.in8
-rw-r--r--src/grp-system/systemd/main.c82
-rw-r--r--src/grp-system/systemd/system.conf2
-rw-r--r--src/grp-system/systemd/systemd-system.conf.xml9
-rw-r--r--src/grp-system/systemd/systemd.exec.xml213
-rw-r--r--src/grp-system/systemd/systemd.generator.xml8
-rw-r--r--src/grp-system/systemd/systemd.netdev.xml54
-rw-r--r--src/grp-system/systemd/systemd.network.xml149
-rw-r--r--src/grp-system/systemd/systemd.nspawn.xml27
-rw-r--r--src/grp-system/systemd/systemd.offline-updates.xml2
-rw-r--r--src/grp-system/systemd/systemd.resource-control.xml118
-rw-r--r--src/grp-system/systemd/systemd.service.xml24
-rw-r--r--src/grp-system/systemd/systemd.special.xml22
-rw-r--r--src/grp-system/systemd/systemd.target.xml19
-rw-r--r--src/grp-system/systemd/systemd.time.xml17
-rw-r--r--src/grp-system/systemd/systemd.timer.xml2
-rw-r--r--src/grp-system/systemd/systemd.unit.xml2
-rw-r--r--src/grp-system/systemd/systemd.xml14
72 files changed, 2498 insertions, 1339 deletions
diff --git a/src/grp-system/grp-utils/systemd-analyze/analyze.c b/src/grp-system/grp-utils/systemd-analyze/analyze.c
index 41d3f0799a..e79a109651 100644
--- a/src/grp-system/grp-utils/systemd-analyze/analyze.c
+++ b/src/grp-system/grp-utils/systemd-analyze/analyze.c
@@ -759,9 +759,9 @@ static int list_dependencies_print(const char *name, unsigned int level, unsigne
if (times) {
if (times->time)
- printf("%s%s @%s +%s%s", ANSI_HIGHLIGHT_RED, name,
+ printf("%s%s @%s +%s%s", ansi_highlight_red(), name,
format_timespan(ts, sizeof(ts), times->activating - boot->userspace_time, USEC_PER_MSEC),
- format_timespan(ts2, sizeof(ts2), times->time, USEC_PER_MSEC), ANSI_NORMAL);
+ format_timespan(ts2, sizeof(ts2), times->time, USEC_PER_MSEC), ansi_normal());
else if (times->activated > boot->userspace_time)
printf("%s @%s", name, format_timespan(ts, sizeof(ts), times->activated - boot->userspace_time, USEC_PER_MSEC));
else
@@ -927,8 +927,8 @@ static int list_dependencies(sd_bus *bus, const char *name) {
if (times) {
if (times->time)
- printf("%s%s +%s%s\n", ANSI_HIGHLIGHT_RED, id,
- format_timespan(ts, sizeof(ts), times->time, USEC_PER_MSEC), ANSI_NORMAL);
+ printf("%s%s +%s%s\n", ansi_highlight_red(), id,
+ format_timespan(ts, sizeof(ts), times->time, USEC_PER_MSEC), ansi_normal());
else if (times->activated > boot->userspace_time)
printf("%s @%s\n", id, format_timespan(ts, sizeof(ts), times->activated - boot->userspace_time, USEC_PER_MSEC));
else
diff --git a/src/grp-system/grp-utils/systemd-delta/Makefile b/src/grp-system/grp-utils/systemd-delta/Makefile
index 4f5610d27a..7273647c52 100644
--- a/src/grp-system/grp-utils/systemd-delta/Makefile
+++ b/src/grp-system/grp-utils/systemd-delta/Makefile
@@ -28,6 +28,6 @@ systemd_delta_SOURCES = \
src/delta/delta.c
systemd_delta_LDADD = \
- libshared.la
+ libsystemd-shared.la
include $(topsrcdir)/build-aux/Makefile.tail.mk
diff --git a/src/grp-system/grp-utils/systemd-fstab-generator/Makefile b/src/grp-system/grp-utils/systemd-fstab-generator/Makefile
index 4f19808477..43475f69e1 100644
--- a/src/grp-system/grp-utils/systemd-fstab-generator/Makefile
+++ b/src/grp-system/grp-utils/systemd-fstab-generator/Makefile
@@ -29,6 +29,6 @@ systemd_fstab_generator_SOURCES = \
src/core/mount-setup.c
systemd_fstab_generator_LDADD = \
- libshared.la
+ libsystemd-shared.la
include $(topsrcdir)/build-aux/Makefile.tail.mk
diff --git a/src/grp-system/grp-utils/systemd-fstab-generator/fstab-generator.c b/src/grp-system/grp-utils/systemd-fstab-generator/fstab-generator.c
index 49c8487935..70866cacda 100644
--- a/src/grp-system/grp-utils/systemd-fstab-generator/fstab-generator.c
+++ b/src/grp-system/grp-utils/systemd-fstab-generator/fstab-generator.c
@@ -86,13 +86,12 @@ static int add_swap(
return log_oom();
f = fopen(unit, "wxe");
- if (!f) {
- if (errno == EEXIST)
- log_error("Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
- else
- log_error_errno(errno, "Failed to create unit file %s: %m", unit);
- return -errno;
- }
+ if (!f)
+ return log_error_errno(errno,
+ errno == EEXIST ?
+ "Failed to create swap unit file %s, as it already exists. Duplicate entry in /etc/fstab?" :
+ "Failed to create unit file %s: %m",
+ unit);
fprintf(f,
"# Automatically generated by systemd-fstab-generator\n\n"
@@ -282,13 +281,12 @@ static int add_mount(
return log_oom();
f = fopen(unit, "wxe");
- if (!f) {
- if (errno == EEXIST)
- log_error("Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?", unit);
- else
- log_error_errno(errno, "Failed to create unit file %s: %m", unit);
- return -errno;
- }
+ if (!f)
+ return log_error_errno(errno,
+ errno == EEXIST ?
+ "Failed to create mount unit file %s, as it already exists. Duplicate entry in /etc/fstab?" :
+ "Failed to create unit file %s: %m",
+ unit);
fprintf(f,
"# Automatically generated by systemd-fstab-generator\n\n"
@@ -418,8 +416,7 @@ static int parse_fstab(bool initrd) {
if (errno == ENOENT)
return 0;
- log_error_errno(errno, "Failed to open %s: %m", fstab_path);
- return -errno;
+ return log_error_errno(errno, "Failed to open %s: %m", fstab_path);
}
while ((me = getmntent(f))) {
@@ -497,6 +494,18 @@ static int add_sysroot_mount(void) {
return 0;
}
+ if (streq(arg_root_what, "gpt-auto")) {
+ /* This is handled by the gpt-auto generator */
+ log_debug("Skipping root directory handling, as gpt-auto was requested.");
+ return 0;
+ }
+
+ if (path_equal(arg_root_what, "/dev/nfs")) {
+ /* This is handled by the kernel or the initrd */
+ log_debug("Skipping root directory handling, as /dev/nfs was requested.");
+ return 0;
+ }
+
what = fstab_node_to_udev_node(arg_root_what);
if (!what)
return log_oom();
@@ -521,10 +530,10 @@ static int add_sysroot_mount(void) {
"/sysroot",
arg_root_fstype,
opts,
- is_device_path(what) ? 1 : 0,
- false,
- false,
- false,
+ is_device_path(what) ? 1 : 0, /* passno */
+ false, /* noauto off */
+ false, /* nofail off */
+ false, /* automount off */
SPECIAL_INITRD_ROOT_FS_TARGET,
"/proc/cmdline");
}
@@ -537,22 +546,20 @@ static int add_sysroot_usr_mount(void) {
return 0;
if (arg_root_what && !arg_usr_what) {
+ /* Copy over the root device, in case the /usr mount just differs in a mount option (consider btrfs subvolumes) */
arg_usr_what = strdup(arg_root_what);
-
if (!arg_usr_what)
return log_oom();
}
if (arg_root_fstype && !arg_usr_fstype) {
arg_usr_fstype = strdup(arg_root_fstype);
-
if (!arg_usr_fstype)
return log_oom();
}
if (arg_root_options && !arg_usr_options) {
arg_usr_options = strdup(arg_root_options);
-
if (!arg_usr_options)
return log_oom();
}
@@ -561,10 +568,8 @@ static int add_sysroot_usr_mount(void) {
return 0;
what = fstab_node_to_udev_node(arg_usr_what);
- if (!path_is_absolute(what)) {
- log_debug("Skipping entry what=%s where=/sysroot/usr type=%s", what, strna(arg_usr_fstype));
- return -1;
- }
+ if (!what)
+ return log_oom();
if (!arg_usr_options)
opts = arg_root_rw > 0 ? "rw" : "ro";
@@ -578,10 +583,10 @@ static int add_sysroot_usr_mount(void) {
"/sysroot/usr",
arg_usr_fstype,
opts,
- 1,
- false,
- false,
- false,
+ is_device_path(what) ? 1 : 0, /* passno */
+ false, /* noauto off */
+ false, /* nofail off */
+ false, /* automount off */
SPECIAL_INITRD_FS_TARGET,
"/proc/cmdline");
}
@@ -676,10 +681,15 @@ int main(int argc, char *argv[]) {
/* Always honour root= and usr= in the kernel command line if we are in an initrd */
if (in_initrd()) {
+ int k;
+
r = add_sysroot_mount();
- if (r == 0)
- r = add_sysroot_usr_mount();
- }
+
+ k = add_sysroot_usr_mount();
+ if (k < 0)
+ r = k;
+ } else
+ r = 0;
/* Honour /etc/fstab only when that's enabled */
if (arg_fstab_enabled) {
diff --git a/src/grp-system/grp-utils/systemd-run/Makefile b/src/grp-system/grp-utils/systemd-run/Makefile
index 17d21167bc..9664591eb6 100644
--- a/src/grp-system/grp-utils/systemd-run/Makefile
+++ b/src/grp-system/grp-utils/systemd-run/Makefile
@@ -28,6 +28,6 @@ systemd_run_SOURCES = \
src/run/run.c
systemd_run_LDADD = \
- libshared.la
+ libsystemd-shared.la
include $(topsrcdir)/build-aux/Makefile.tail.mk
diff --git a/src/grp-system/grp-utils/systemd-run/run.c b/src/grp-system/grp-utils/systemd-run/run.c
index 10b6b4440f..4aaf446177 100644
--- a/src/grp-system/grp-utils/systemd-run/run.c
+++ b/src/grp-system/grp-utils/systemd-run/run.c
@@ -187,7 +187,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "+hrH:M:p:tq", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "+hrH:M:E:p:tq", options, NULL)) >= 0)
switch (c) {
diff --git a/src/grp-system/grp-utils/systemd-run/systemd-run.completion.bash b/src/grp-system/grp-utils/systemd-run/systemd-run.completion.bash
index 8152b021e7..022331e6a9 100644
--- a/src/grp-system/grp-utils/systemd-run/systemd-run.completion.bash
+++ b/src/grp-system/grp-utils/systemd-run/systemd-run.completion.bash
@@ -84,8 +84,8 @@ _systemd_run() {
LimitNICE= LimitRTPRIO= LimitRTTIME= PrivateTmp= PrivateDevices=
PrivateNetwork= NoNewPrivileges= WorkingDirectory= RootDirectory=
TTYPath= SyslogIdentifier= SyslogLevelPrefix= SyslogLevel=
- SyslogFacility= TimerSlackNSec= OOMScoreAdjust= ReadWriteDirectories=
- ReadOnlyDirectories= InaccessibleDirectories= EnvironmentFile=
+ SyslogFacility= TimerSlackNSec= OOMScoreAdjust= ReadWritePaths=
+ ReadOnlyPaths= InaccessiblePaths= EnvironmentFile=
ProtectSystem= ProtectHome= RuntimeDirectory= PassEnvironment='
COMPREPLY=( $(compgen -W '$comps' -- "$cur") )
diff --git a/src/grp-system/grp-utils/systemd-run/systemd-run.completion.zsh b/src/grp-system/grp-utils/systemd-run/systemd-run.completion.zsh
index c425085cd8..6362b97766 100644
--- a/src/grp-system/grp-utils/systemd-run/systemd-run.completion.zsh
+++ b/src/grp-system/grp-utils/systemd-run/systemd-run.completion.zsh
@@ -37,8 +37,8 @@ _arguments \
LimitNICE= LimitRTPRIO= LimitRTTIME= PrivateTmp= PrivateDevices= \
PrivateNetwork= NoNewPrivileges= WorkingDirectory= RootDirectory= \
TTYPath= SyslogIdentifier= SyslogLevelPrefix= SyslogLevel= \
- SyslogFacility= TimerSlackNSec= OOMScoreAdjust= ReadWriteDirectories= \
- ReadOnlyDirectories= InaccessibleDirectories= EnvironmentFile= \
+ SyslogFacility= TimerSlackNSec= OOMScoreAdjust= ReadWritePaths= \
+ ReadOnlyPaths= InaccessiblePaths= EnvironmentFile= \
ProtectSystem= ProtectHome= RuntimeDirectory= PassEnvironment= \
))' \
'--description=[Description for unit]:description' \
diff --git a/src/grp-system/grp-utils/systemd-sysv-generator/sysv-generator.c b/src/grp-system/grp-utils/systemd-sysv-generator/sysv-generator.c
index 0fb1f0b8a3..de973034be 100644
--- a/src/grp-system/grp-utils/systemd-sysv-generator/sysv-generator.c
+++ b/src/grp-system/grp-utils/systemd-sysv-generator/sysv-generator.c
@@ -42,32 +42,19 @@
#include "shared/install.h"
#include "shared/path-lookup.h"
-typedef enum RunlevelType {
- RUNLEVEL_UP,
- RUNLEVEL_DOWN
-} RunlevelType;
-
static const struct {
const char *path;
const char *target;
- const RunlevelType type;
} rcnd_table[] = {
/* Standard SysV runlevels for start-up */
- { "rc1.d", SPECIAL_RESCUE_TARGET, RUNLEVEL_UP },
- { "rc2.d", SPECIAL_MULTI_USER_TARGET, RUNLEVEL_UP },
- { "rc3.d", SPECIAL_MULTI_USER_TARGET, RUNLEVEL_UP },
- { "rc4.d", SPECIAL_MULTI_USER_TARGET, RUNLEVEL_UP },
- { "rc5.d", SPECIAL_GRAPHICAL_TARGET, RUNLEVEL_UP },
-
- /* Standard SysV runlevels for shutdown */
- { "rc0.d", SPECIAL_POWEROFF_TARGET, RUNLEVEL_DOWN },
- { "rc6.d", SPECIAL_REBOOT_TARGET, RUNLEVEL_DOWN }
-
- /* Note that the order here matters, as we read the
- directories in this order, and we want to make sure that
- sysv_start_priority is known when we first load the
- unit. And that value we only know from S links. Hence
- UP must be read before DOWN */
+ { "rc1.d", SPECIAL_RESCUE_TARGET },
+ { "rc2.d", SPECIAL_MULTI_USER_TARGET },
+ { "rc3.d", SPECIAL_MULTI_USER_TARGET },
+ { "rc4.d", SPECIAL_MULTI_USER_TARGET },
+ { "rc5.d", SPECIAL_GRAPHICAL_TARGET },
+
+ /* We ignore the SysV runlevels for shutdown here, as SysV services get default dependencies anyway, and that
+ * means they are shut down anyway at system power off if running. */
};
static const char *arg_dest = "/tmp";
@@ -82,7 +69,6 @@ typedef struct SysvStub {
char **after;
char **wants;
char **wanted_by;
- char **conflicts;
bool has_lsb;
bool reload;
bool loaded;
@@ -100,7 +86,6 @@ static void free_sysvstub(SysvStub *s) {
strv_free(s->after);
strv_free(s->wants);
strv_free(s->wanted_by);
- strv_free(s->conflicts);
free(s);
}
@@ -199,8 +184,6 @@ static int generate_unit_file(SysvStub *s) {
fprintf(f, "After=%s\n", *p);
STRV_FOREACH(p, s->wants)
fprintf(f, "Wants=%s\n", *p);
- STRV_FOREACH(p, s->conflicts)
- fprintf(f, "Conflicts=%s\n", *p);
fprintf(f,
"\n[Service]\n"
@@ -527,9 +510,7 @@ static int load_sysv(SysvStub *s) {
t[k-1] = 0;
}
- j = strstrip(t+12);
- if (isempty(j))
- j = NULL;
+ j = empty_to_null(strstrip(t+12));
r = free_and_strdup(&chkconfig_description, j);
if (r < 0)
@@ -605,9 +586,7 @@ static int load_sysv(SysvStub *s) {
state = LSB_DESCRIPTION;
- j = strstrip(t+12);
- if (isempty(j))
- j = NULL;
+ j = empty_to_null(strstrip(t+12));
r = free_and_strdup(&long_description, j);
if (r < 0)
@@ -618,9 +597,7 @@ static int load_sysv(SysvStub *s) {
state = LSB;
- j = strstrip(t+18);
- if (isempty(j))
- j = NULL;
+ j = empty_to_null(strstrip(t+18));
r = free_and_strdup(&short_description, j);
if (r < 0)
@@ -841,7 +818,6 @@ static int enumerate_sysv(const LookupPaths *lp, Hashmap *all_services) {
static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_services) {
Set *runlevel_services[ELEMENTSOF(rcnd_table)] = {};
- _cleanup_set_free_ Set *shutdown_services = NULL;
_cleanup_strv_free_ char **sysvrcnd_path = NULL;
SysvStub *service;
unsigned i;
@@ -880,7 +856,7 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic
_cleanup_free_ char *name = NULL, *fpath = NULL;
int a, b;
- if (de->d_name[0] != 'S' && de->d_name[0] != 'K')
+ if (de->d_name[0] != 'S')
continue;
if (strlen(de->d_name) < 4)
@@ -910,43 +886,23 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic
continue;
}
- if (de->d_name[0] == 'S') {
-
- if (rcnd_table[i].type == RUNLEVEL_UP)
- service->sysv_start_priority = MAX(a*10 + b, service->sysv_start_priority);
+ service->sysv_start_priority = MAX(a*10 + b, service->sysv_start_priority);
- r = set_ensure_allocated(&runlevel_services[i], NULL);
- if (r < 0) {
- log_oom();
- goto finish;
- }
-
- r = set_put(runlevel_services[i], service);
- if (r < 0) {
- log_oom();
- goto finish;
- }
-
- } else if (de->d_name[0] == 'K' &&
- (rcnd_table[i].type == RUNLEVEL_DOWN)) {
-
- r = set_ensure_allocated(&shutdown_services, NULL);
- if (r < 0) {
- log_oom();
- goto finish;
- }
+ r = set_ensure_allocated(&runlevel_services[i], NULL);
+ if (r < 0) {
+ log_oom();
+ goto finish;
+ }
- r = set_put(shutdown_services, service);
- if (r < 0) {
- log_oom();
- goto finish;
- }
+ r = set_put(runlevel_services[i], service);
+ if (r < 0) {
+ log_oom();
+ goto finish;
}
}
}
}
-
for (i = 0; i < ELEMENTSOF(rcnd_table); i ++)
SET_FOREACH(service, runlevel_services[i], j) {
r = strv_extend(&service->before, rcnd_table[i].target);
@@ -961,19 +917,6 @@ static int set_dependencies_from_rcnd(const LookupPaths *lp, Hashmap *all_servic
}
}
- SET_FOREACH(service, shutdown_services, j) {
- r = strv_extend(&service->before, SPECIAL_SHUTDOWN_TARGET);
- if (r < 0) {
- log_oom();
- goto finish;
- }
- r = strv_extend(&service->conflicts, SPECIAL_SHUTDOWN_TARGET);
- if (r < 0) {
- log_oom();
- goto finish;
- }
- }
-
r = 0;
finish:
diff --git a/src/grp-system/kernel-command-line.xml b/src/grp-system/kernel-command-line.xml
index 9c04849f66..3ecc969c10 100644
--- a/src/grp-system/kernel-command-line.xml
+++ b/src/grp-system/kernel-command-line.xml
@@ -146,7 +146,9 @@
<varlistentry>
<term><varname>-b</varname></term>
+ <term><varname>rd.emergency</varname></term>
<term><varname>emergency</varname></term>
+ <term><varname>rd.rescue</varname></term>
<term><varname>rescue</varname></term>
<term><varname>single</varname></term>
<term><varname>s</varname></term>
@@ -158,7 +160,7 @@
<term><varname>5</varname></term>
<listitem>
<para>Parameters understood by the system and service
- manager, as compatibility options. For details, see
+ manager, as compatibility and convenience options. For details, see
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>.</para>
</listitem>
</varlistentry>
diff --git a/src/grp-system/libcore/Makefile b/src/grp-system/libcore/Makefile
index 1f19355412..b31d00fcdb 100644
--- a/src/grp-system/libcore/Makefile
+++ b/src/grp-system/libcore/Makefile
@@ -156,7 +156,7 @@ libcore_la_CFLAGS = \
$(SECCOMP_CFLAGS)
libcore_la_LIBADD = \
- libshared.la \
+ libsystemd-shared.la \
$(PAM_LIBS) \
$(AUDIT_LIBS) \
$(KMOD_LIBS) \
diff --git a/src/grp-system/libcore/automount.c b/src/grp-system/libcore/automount.c
index 726a044030..30c30469ca 100644
--- a/src/grp-system/libcore/automount.c
+++ b/src/grp-system/libcore/automount.c
@@ -100,9 +100,6 @@ static void unmount_autofs(Automount *a) {
if (a->pipe_fd < 0)
return;
- automount_send_ready(a, a->tokens, -EHOSTDOWN);
- automount_send_ready(a, a->expire_tokens, -EHOSTDOWN);
-
a->pipe_event_source = sd_event_source_unref(a->pipe_event_source);
a->pipe_fd = safe_close(a->pipe_fd);
@@ -111,6 +108,9 @@ static void unmount_autofs(Automount *a) {
if (a->where &&
(UNIT(a)->manager->exit_code != MANAGER_RELOAD &&
UNIT(a)->manager->exit_code != MANAGER_REEXECUTE)) {
+ automount_send_ready(a, a->tokens, -EHOSTDOWN);
+ automount_send_ready(a, a->expire_tokens, -EHOSTDOWN);
+
r = repeat_unmount(a->where, MNT_DETACH);
if (r < 0)
log_error_errno(r, "Failed to unmount: %m");
@@ -504,6 +504,20 @@ static void automount_trigger_notify(Unit *u, Unit *other) {
automount_set_state(a, AUTOMOUNT_RUNNING);
}
+ if (IN_SET(MOUNT(other)->state,
+ MOUNT_MOUNTING, MOUNT_MOUNTING_DONE,
+ MOUNT_MOUNTED, MOUNT_REMOUNTING,
+ MOUNT_MOUNTING_SIGTERM, MOUNT_MOUNTING_SIGKILL,
+ MOUNT_REMOUNTING_SIGTERM, MOUNT_REMOUNTING_SIGKILL,
+ MOUNT_UNMOUNTING_SIGTERM, MOUNT_UNMOUNTING_SIGKILL,
+ MOUNT_FAILED)) {
+
+ (void) automount_send_ready(a, a->expire_tokens, -ENODEV);
+ }
+
+ if (MOUNT(other)->state == MOUNT_DEAD)
+ (void) automount_send_ready(a, a->expire_tokens, 0);
+
/* The mount is in some unhappy state now, let's unfreeze any waiting clients */
if (IN_SET(MOUNT(other)->state,
MOUNT_DEAD, MOUNT_UNMOUNTING,
diff --git a/src/grp-system/libcore/busname.c b/src/grp-system/libcore/busname.c
index 5d85c20730..f21a2d23c1 100644
--- a/src/grp-system/libcore/busname.c
+++ b/src/grp-system/libcore/busname.c
@@ -999,12 +999,7 @@ static int busname_get_timeout(Unit *u, usec_t *timeout) {
}
static bool busname_supported(void) {
- static int supported = -1;
-
- if (supported < 0)
- supported = is_kdbus_available();
-
- return supported;
+ return false;
}
static int busname_control_pid(Unit *u) {
diff --git a/src/grp-system/libcore/cgroup.c b/src/grp-system/libcore/cgroup.c
index df850ec68f..0c1365f329 100644
--- a/src/grp-system/libcore/cgroup.c
+++ b/src/grp-system/libcore/cgroup.c
@@ -37,6 +37,21 @@
#define CGROUP_CPU_QUOTA_PERIOD_USEC ((usec_t) 100 * USEC_PER_MSEC)
+static void cgroup_compat_warn(void) {
+ static bool cgroup_compat_warned = false;
+
+ if (cgroup_compat_warned)
+ return;
+
+ log_warning("cgroup compatibility translation between legacy and unified hierarchy settings activated. See cgroup-compat debug messages for details.");
+ cgroup_compat_warned = true;
+}
+
+#define log_cgroup_compat(unit, fmt, ...) do { \
+ cgroup_compat_warn(); \
+ log_unit_debug(unit, "cgroup-compat: " fmt, ##__VA_ARGS__); \
+ } while (false)
+
void cgroup_context_init(CGroupContext *c) {
assert(c);
@@ -47,7 +62,10 @@ void cgroup_context_init(CGroupContext *c) {
c->startup_cpu_shares = CGROUP_CPU_SHARES_INVALID;
c->cpu_quota_per_sec_usec = USEC_INFINITY;
- c->memory_limit = (uint64_t) -1;
+ c->memory_high = CGROUP_LIMIT_MAX;
+ c->memory_max = CGROUP_LIMIT_MAX;
+
+ c->memory_limit = CGROUP_LIMIT_MAX;
c->io_weight = CGROUP_WEIGHT_INVALID;
c->startup_io_weight = CGROUP_WEIGHT_INVALID;
@@ -148,6 +166,9 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
"%sStartupIOWeight=%" PRIu64 "\n"
"%sBlockIOWeight=%" PRIu64 "\n"
"%sStartupBlockIOWeight=%" PRIu64 "\n"
+ "%sMemoryLow=%" PRIu64 "\n"
+ "%sMemoryHigh=%" PRIu64 "\n"
+ "%sMemoryMax=%" PRIu64 "\n"
"%sMemoryLimit=%" PRIu64 "\n"
"%sTasksMax=%" PRIu64 "\n"
"%sDevicePolicy=%s\n"
@@ -164,6 +185,9 @@ void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix) {
prefix, c->startup_io_weight,
prefix, c->blockio_weight,
prefix, c->startup_blockio_weight,
+ prefix, c->memory_low,
+ prefix, c->memory_high,
+ prefix, c->memory_max,
prefix, c->memory_limit,
prefix, c->tasks_max,
prefix, cgroup_device_policy_to_string(c->device_policy),
@@ -405,7 +429,7 @@ static uint64_t cgroup_weight_io_to_blkio(uint64_t io_weight) {
CGROUP_BLKIO_WEIGHT_MIN, CGROUP_BLKIO_WEIGHT_MAX);
}
-static void cgroup_apply_io_device_weight(const char *path, const char *dev_path, uint64_t io_weight) {
+static void cgroup_apply_io_device_weight(Unit *u, const char *dev_path, uint64_t io_weight) {
char buf[DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1];
dev_t dev;
int r;
@@ -415,13 +439,13 @@ static void cgroup_apply_io_device_weight(const char *path, const char *dev_path
return;
xsprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), io_weight);
- r = cg_set_attribute("io", path, "io.weight", buf);
+ r = cg_set_attribute("io", u->cgroup_path, "io.weight", buf);
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set io.weight on %s: %m", path);
+ log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to set io.weight: %m");
}
-static void cgroup_apply_blkio_device_weight(const char *path, const char *dev_path, uint64_t blkio_weight) {
+static void cgroup_apply_blkio_device_weight(Unit *u, const char *dev_path, uint64_t blkio_weight) {
char buf[DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1];
dev_t dev;
int r;
@@ -431,13 +455,13 @@ static void cgroup_apply_blkio_device_weight(const char *path, const char *dev_p
return;
xsprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), blkio_weight);
- r = cg_set_attribute("blkio", path, "blkio.weight_device", buf);
+ r = cg_set_attribute("blkio", u->cgroup_path, "blkio.weight_device", buf);
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set blkio.weight_device on %s: %m", path);
+ log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to set blkio.weight_device: %m");
}
-static unsigned cgroup_apply_io_device_limit(const char *path, const char *dev_path, uint64_t *limits) {
+static unsigned cgroup_apply_io_device_limit(Unit *u, const char *dev_path, uint64_t *limits) {
char limit_bufs[_CGROUP_IO_LIMIT_TYPE_MAX][DECIMAL_STR_MAX(uint64_t)];
char buf[DECIMAL_STR_MAX(dev_t)*2+2+(6+DECIMAL_STR_MAX(uint64_t)+1)*4];
CGroupIOLimitType type;
@@ -461,14 +485,14 @@ static unsigned cgroup_apply_io_device_limit(const char *path, const char *dev_p
xsprintf(buf, "%u:%u rbps=%s wbps=%s riops=%s wiops=%s\n", major(dev), minor(dev),
limit_bufs[CGROUP_IO_RBPS_MAX], limit_bufs[CGROUP_IO_WBPS_MAX],
limit_bufs[CGROUP_IO_RIOPS_MAX], limit_bufs[CGROUP_IO_WIOPS_MAX]);
- r = cg_set_attribute("io", path, "io.max", buf);
+ r = cg_set_attribute("io", u->cgroup_path, "io.max", buf);
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set io.max on %s: %m", path);
+ log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to set io.max: %m");
return n;
}
-static unsigned cgroup_apply_blkio_device_limit(const char *path, const char *dev_path, uint64_t rbps, uint64_t wbps) {
+static unsigned cgroup_apply_blkio_device_limit(Unit *u, const char *dev_path, uint64_t rbps, uint64_t wbps) {
char buf[DECIMAL_STR_MAX(dev_t)*2+2+DECIMAL_STR_MAX(uint64_t)+1];
dev_t dev;
unsigned n = 0;
@@ -481,26 +505,50 @@ static unsigned cgroup_apply_blkio_device_limit(const char *path, const char *de
if (rbps != CGROUP_LIMIT_MAX)
n++;
sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), rbps);
- r = cg_set_attribute("blkio", path, "blkio.throttle.read_bps_device", buf);
+ r = cg_set_attribute("blkio", u->cgroup_path, "blkio.throttle.read_bps_device", buf);
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set blkio.throttle.read_bps_device on %s: %m", path);
+ log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to set blkio.throttle.read_bps_device: %m");
if (wbps != CGROUP_LIMIT_MAX)
n++;
sprintf(buf, "%u:%u %" PRIu64 "\n", major(dev), minor(dev), wbps);
- r = cg_set_attribute("blkio", path, "blkio.throttle.write_bps_device", buf);
+ r = cg_set_attribute("blkio", u->cgroup_path, "blkio.throttle.write_bps_device", buf);
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set blkio.throttle.write_bps_device on %s: %m", path);
+ log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to set blkio.throttle.write_bps_device: %m");
return n;
}
-void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, ManagerState state) {
+static bool cgroup_context_has_unified_memory_config(CGroupContext *c) {
+ return c->memory_low > 0 || c->memory_high != CGROUP_LIMIT_MAX || c->memory_max != CGROUP_LIMIT_MAX;
+}
+
+static void cgroup_apply_unified_memory_limit(Unit *u, const char *file, uint64_t v) {
+ char buf[DECIMAL_STR_MAX(uint64_t) + 1] = "max";
+ int r;
+
+ if (v != CGROUP_LIMIT_MAX)
+ xsprintf(buf, "%" PRIu64 "\n", v);
+
+ r = cg_set_attribute("memory", u->cgroup_path, file, buf);
+ if (r < 0)
+ log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to set %s: %m", file);
+}
+
+static void cgroup_context_apply(Unit *u, CGroupMask mask, ManagerState state) {
+ const char *path;
+ CGroupContext *c;
bool is_root;
int r;
+ assert(u);
+
+ c = unit_get_cgroup_context(u);
+ path = u->cgroup_path;
+
assert(c);
assert(path);
@@ -526,14 +574,14 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
c->cpu_shares != CGROUP_CPU_SHARES_INVALID ? c->cpu_shares : CGROUP_CPU_SHARES_DEFAULT);
r = cg_set_attribute("cpu", path, "cpu.shares", buf);
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set cpu.shares on %s: %m", path);
+ log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to set cpu.shares: %m");
sprintf(buf, USEC_FMT "\n", CGROUP_CPU_QUOTA_PERIOD_USEC);
r = cg_set_attribute("cpu", path, "cpu.cfs_period_us", buf);
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set cpu.cfs_period_us on %s: %m", path);
+ log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to set cpu.cfs_period_us: %m");
if (c->cpu_quota_per_sec_usec != USEC_INFINITY) {
sprintf(buf, USEC_FMT "\n", c->cpu_quota_per_sec_usec * CGROUP_CPU_QUOTA_PERIOD_USEC / USEC_PER_SEC);
@@ -541,8 +589,8 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
} else
r = cg_set_attribute("cpu", path, "cpu.cfs_quota_us", "-1");
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set cpu.cfs_quota_us on %s: %m", path);
+ log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to set cpu.cfs_quota_us: %m");
}
if (mask & CGROUP_MASK_IO) {
@@ -555,29 +603,40 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
if (has_io)
weight = cgroup_context_io_weight(c, state);
- else if (has_blockio)
- weight = cgroup_weight_blkio_to_io(cgroup_context_blkio_weight(c, state));
- else
+ else if (has_blockio) {
+ uint64_t blkio_weight = cgroup_context_blkio_weight(c, state);
+
+ weight = cgroup_weight_blkio_to_io(blkio_weight);
+
+ log_cgroup_compat(u, "Applying [Startup]BlockIOWeight %" PRIu64 " as [Startup]IOWeight %" PRIu64,
+ blkio_weight, weight);
+ } else
weight = CGROUP_WEIGHT_DEFAULT;
xsprintf(buf, "default %" PRIu64 "\n", weight);
r = cg_set_attribute("io", path, "io.weight", buf);
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set io.weight on %s: %m", path);
+ log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to set io.weight: %m");
if (has_io) {
CGroupIODeviceWeight *w;
/* FIXME: no way to reset this list */
LIST_FOREACH(device_weights, w, c->io_device_weights)
- cgroup_apply_io_device_weight(path, w->path, w->weight);
+ cgroup_apply_io_device_weight(u, w->path, w->weight);
} else if (has_blockio) {
CGroupBlockIODeviceWeight *w;
/* FIXME: no way to reset this list */
- LIST_FOREACH(device_weights, w, c->blockio_device_weights)
- cgroup_apply_io_device_weight(path, w->path, cgroup_weight_blkio_to_io(w->weight));
+ LIST_FOREACH(device_weights, w, c->blockio_device_weights) {
+ weight = cgroup_weight_blkio_to_io(w->weight);
+
+ log_cgroup_compat(u, "Applying BlockIODeviceWeight %" PRIu64 " as IODeviceWeight %" PRIu64 " for %s",
+ w->weight, weight, w->path);
+
+ cgroup_apply_io_device_weight(u, w->path, weight);
+ }
}
}
@@ -586,7 +645,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
CGroupIODeviceLimit *l, *next;
LIST_FOREACH_SAFE(device_limits, l, next, c->io_device_limits) {
- if (!cgroup_apply_io_device_limit(path, l->path, l->limits))
+ if (!cgroup_apply_io_device_limit(u, l->path, l->limits))
cgroup_context_free_io_device_limit(c, l);
}
} else if (has_blockio) {
@@ -602,7 +661,10 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
limits[CGROUP_IO_RBPS_MAX] = b->rbps;
limits[CGROUP_IO_WBPS_MAX] = b->wbps;
- if (!cgroup_apply_io_device_limit(path, b->path, limits))
+ log_cgroup_compat(u, "Applying BlockIO{Read|Write}Bandwidth %" PRIu64 " %" PRIu64 " as IO{Read|Write}BandwidthMax for %s",
+ b->rbps, b->wbps, b->path);
+
+ if (!cgroup_apply_io_device_limit(u, b->path, limits))
cgroup_context_free_blockio_device_bandwidth(c, b);
}
}
@@ -618,29 +680,40 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
if (has_blockio)
weight = cgroup_context_blkio_weight(c, state);
- else if (has_io)
+ else if (has_io) {
+ uint64_t io_weight = cgroup_context_io_weight(c, state);
+
weight = cgroup_weight_io_to_blkio(cgroup_context_io_weight(c, state));
- else
+
+ log_cgroup_compat(u, "Applying [Startup]IOWeight %" PRIu64 " as [Startup]BlockIOWeight %" PRIu64,
+ io_weight, weight);
+ } else
weight = CGROUP_BLKIO_WEIGHT_DEFAULT;
xsprintf(buf, "%" PRIu64 "\n", weight);
r = cg_set_attribute("blkio", path, "blkio.weight", buf);
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set blkio.weight on %s: %m", path);
+ log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to set blkio.weight: %m");
if (has_blockio) {
CGroupBlockIODeviceWeight *w;
/* FIXME: no way to reset this list */
LIST_FOREACH(device_weights, w, c->blockio_device_weights)
- cgroup_apply_blkio_device_weight(path, w->path, w->weight);
+ cgroup_apply_blkio_device_weight(u, w->path, w->weight);
} else if (has_io) {
CGroupIODeviceWeight *w;
/* FIXME: no way to reset this list */
- LIST_FOREACH(device_weights, w, c->io_device_weights)
- cgroup_apply_blkio_device_weight(path, w->path, cgroup_weight_io_to_blkio(w->weight));
+ LIST_FOREACH(device_weights, w, c->io_device_weights) {
+ weight = cgroup_weight_io_to_blkio(w->weight);
+
+ log_cgroup_compat(u, "Applying IODeviceWeight %" PRIu64 " as BlockIODeviceWeight %" PRIu64 " for %s",
+ w->weight, weight, w->path);
+
+ cgroup_apply_blkio_device_weight(u, w->path, weight);
+ }
}
}
@@ -649,40 +722,59 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
CGroupBlockIODeviceBandwidth *b, *next;
LIST_FOREACH_SAFE(device_bandwidths, b, next, c->blockio_device_bandwidths) {
- if (!cgroup_apply_blkio_device_limit(path, b->path, b->rbps, b->wbps))
+ if (!cgroup_apply_blkio_device_limit(u, b->path, b->rbps, b->wbps))
cgroup_context_free_blockio_device_bandwidth(c, b);
}
} else if (has_io) {
CGroupIODeviceLimit *l, *next;
LIST_FOREACH_SAFE(device_limits, l, next, c->io_device_limits) {
- if (!cgroup_apply_blkio_device_limit(path, l->path, l->limits[CGROUP_IO_RBPS_MAX], l->limits[CGROUP_IO_WBPS_MAX]))
+ log_cgroup_compat(u, "Applying IO{Read|Write}Bandwidth %" PRIu64 " %" PRIu64 " as BlockIO{Read|Write}BandwidthMax for %s",
+ l->limits[CGROUP_IO_RBPS_MAX], l->limits[CGROUP_IO_WBPS_MAX], l->path);
+
+ if (!cgroup_apply_blkio_device_limit(u, l->path, l->limits[CGROUP_IO_RBPS_MAX], l->limits[CGROUP_IO_WBPS_MAX]))
cgroup_context_free_io_device_limit(c, l);
}
}
}
if ((mask & CGROUP_MASK_MEMORY) && !is_root) {
- if (c->memory_limit != (uint64_t) -1) {
- char buf[DECIMAL_STR_MAX(uint64_t) + 1];
+ if (cg_unified() > 0) {
+ uint64_t max = c->memory_max;
- sprintf(buf, "%" PRIu64 "\n", c->memory_limit);
+ if (cgroup_context_has_unified_memory_config(c))
+ max = c->memory_max;
+ else {
+ max = c->memory_limit;
- if (cg_unified() <= 0)
- r = cg_set_attribute("memory", path, "memory.limit_in_bytes", buf);
- else
- r = cg_set_attribute("memory", path, "memory.max", buf);
+ if (max != CGROUP_LIMIT_MAX)
+ log_cgroup_compat(u, "Applying MemoryLimit %" PRIu64 " as MemoryMax", max);
+ }
+ cgroup_apply_unified_memory_limit(u, "memory.low", c->memory_low);
+ cgroup_apply_unified_memory_limit(u, "memory.high", c->memory_high);
+ cgroup_apply_unified_memory_limit(u, "memory.max", max);
} else {
- if (cg_unified() <= 0)
- r = cg_set_attribute("memory", path, "memory.limit_in_bytes", "-1");
+ char buf[DECIMAL_STR_MAX(uint64_t) + 1];
+ uint64_t val = c->memory_limit;
+
+ if (val == CGROUP_LIMIT_MAX) {
+ val = c->memory_max;
+
+ if (val != CGROUP_LIMIT_MAX)
+ log_cgroup_compat(u, "Applying MemoryMax %" PRIi64 " as MemoryLimit", c->memory_max);
+ }
+
+ if (val == CGROUP_LIMIT_MAX)
+ strncpy(buf, "-1\n", sizeof(buf));
else
- r = cg_set_attribute("memory", path, "memory.max", "max");
- }
+ xsprintf(buf, "%" PRIu64 "\n", val);
- if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set memory.limit_in_bytes/memory.max on %s: %m", path);
+ r = cg_set_attribute("memory", path, "memory.limit_in_bytes", buf);
+ if (r < 0)
+ log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to set memory.limit_in_bytes: %m");
+ }
}
if ((mask & CGROUP_MASK_DEVICES) && !is_root) {
@@ -697,8 +789,8 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
else
r = cg_set_attribute("devices", path, "devices.allow", "a");
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EINVAL, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to reset devices.list on %s: %m", path);
+ log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EINVAL, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to reset devices.list: %m");
if (c->device_policy == CGROUP_CLOSED ||
(c->device_policy == CGROUP_AUTO && c->device_allow)) {
@@ -709,7 +801,10 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
"/dev/random\0" "rwm\0"
"/dev/urandom\0" "rwm\0"
"/dev/tty\0" "rwm\0"
- "/dev/pts/ptmx\0" "rw\0"; /* /dev/pts/ptmx may not be duplicated, but accessed */
+ "/dev/pts/ptmx\0" "rw\0" /* /dev/pts/ptmx may not be duplicated, but accessed */
+ /* Allow /run/systemd/inaccessible/{chr,blk} devices for mapping InaccessiblePaths */
+ "/run/systemd/inaccessible/chr\0" "rwm\0"
+ "/run/systemd/inaccessible/blk\0" "rwm\0";
const char *x, *y;
@@ -744,7 +839,7 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
else if (startswith(a->path, "char-"))
whitelist_major(path, a->path + 5, 'c', acc);
else
- log_debug("Ignoring device %s while writing cgroup attribute.", a->path);
+ log_unit_debug(u, "Ignoring device %s while writing cgroup attribute.", a->path);
}
}
@@ -759,8 +854,8 @@ void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, M
r = cg_set_attribute("pids", path, "pids.max", "max");
if (r < 0)
- log_full_errno(IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
- "Failed to set pids.max on %s: %m", path);
+ log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+ "Failed to set pids.max: %m");
}
}
@@ -779,7 +874,8 @@ CGroupMask cgroup_context_get_mask(CGroupContext *c) {
mask |= CGROUP_MASK_IO | CGROUP_MASK_BLKIO;
if (c->memory_accounting ||
- c->memory_limit != (uint64_t) -1)
+ c->memory_limit != CGROUP_LIMIT_MAX ||
+ cgroup_context_has_unified_memory_config(c))
mask |= CGROUP_MASK_MEMORY;
if (c->device_allow ||
@@ -1044,7 +1140,7 @@ int unit_watch_cgroup(Unit *u) {
/* Only applies to the unified hierarchy */
r = cg_unified();
if (r < 0)
- return log_unit_error_errno(u, r, "Failed detect wether the unified hierarchy is used: %m");
+ return log_unit_error_errno(u, r, "Failed detect whether the unified hierarchy is used: %m");
if (r == 0)
return 0;
@@ -1194,7 +1290,7 @@ static int unit_realize_cgroup_now(Unit *u, ManagerState state) {
return r;
/* Finally, apply the necessary attributes. */
- cgroup_context_apply(unit_get_cgroup_context(u), target_mask, u->cgroup_path, state);
+ cgroup_context_apply(u, target_mask, state);
return 0;
}
@@ -1325,7 +1421,7 @@ void unit_prune_cgroup(Unit *u) {
r = cg_trim_everywhere(u->manager->cgroup_supported, u->cgroup_path, !is_root_slice);
if (r < 0) {
- log_debug_errno(r, "Failed to destroy cgroup %s, ignoring: %m", u->cgroup_path);
+ log_unit_debug_errno(u, r, "Failed to destroy cgroup %s, ignoring: %m", u->cgroup_path);
return;
}
@@ -1566,7 +1662,7 @@ int manager_setup_cgroup(Manager *m) {
/* 3. Install agent */
if (unified) {
- /* In the unified hierarchy we can can get
+ /* In the unified hierarchy we can get
* cgroup empty notifications via inotify. */
m->cgroup_inotify_event_source = sd_event_source_unref(m->cgroup_inotify_event_source);
@@ -1613,7 +1709,7 @@ int manager_setup_cgroup(Manager *m) {
/* also, move all other userspace processes remaining
* in the root cgroup into that scope. */
- r = cg_migrate(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, SYSTEMD_CGROUP_CONTROLLER, scope_path, false);
+ r = cg_migrate(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_root, SYSTEMD_CGROUP_CONTROLLER, scope_path, 0);
if (r < 0)
log_warning_errno(r, "Couldn't move remaining userspace processes, ignoring: %m");
@@ -1634,7 +1730,7 @@ int manager_setup_cgroup(Manager *m) {
return log_error_errno(r, "Failed to determine supported controllers: %m");
for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++)
- log_debug("Controller '%s' supported: %s", cgroup_controller_to_string(c), yes_no(m->cgroup_supported & c));
+ log_debug("Controller '%s' supported: %s", cgroup_controller_to_string(c), yes_no(m->cgroup_supported & CGROUP_CONTROLLER_TO_MASK(c)));
return 0;
}
diff --git a/src/grp-system/libcore/cgroup.h b/src/grp-system/libcore/cgroup.h
index 36699fb21b..bf40c3cc74 100644
--- a/src/grp-system/libcore/cgroup.h
+++ b/src/grp-system/libcore/cgroup.h
@@ -94,6 +94,10 @@ struct CGroupContext {
LIST_HEAD(CGroupIODeviceWeight, io_device_weights);
LIST_HEAD(CGroupIODeviceLimit, io_device_limits);
+ uint64_t memory_low;
+ uint64_t memory_high;
+ uint64_t memory_max;
+
/* For legacy hierarchies */
uint64_t cpu_shares;
uint64_t startup_cpu_shares;
@@ -120,7 +124,6 @@ struct CGroupContext {
void cgroup_context_init(CGroupContext *c);
void cgroup_context_done(CGroupContext *c);
void cgroup_context_dump(CGroupContext *c, FILE* f, const char *prefix);
-void cgroup_context_apply(CGroupContext *c, CGroupMask mask, const char *path, ManagerState state);
CGroupMask cgroup_context_get_mask(CGroupContext *c);
diff --git a/src/grp-system/libcore/dbus-cgroup.c b/src/grp-system/libcore/dbus-cgroup.c
index d707ac51c3..da1c333043 100644
--- a/src/grp-system/libcore/dbus-cgroup.c
+++ b/src/grp-system/libcore/dbus-cgroup.c
@@ -229,6 +229,9 @@ const sd_bus_vtable bus_cgroup_vtable[] = {
SD_BUS_PROPERTY("BlockIOReadBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
SD_BUS_PROPERTY("BlockIOWriteBandwidth", "a(st)", property_get_blockio_device_bandwidths, 0, 0),
SD_BUS_PROPERTY("MemoryAccounting", "b", bus_property_get_bool, offsetof(CGroupContext, memory_accounting), 0),
+ SD_BUS_PROPERTY("MemoryLow", "t", NULL, offsetof(CGroupContext, memory_low), 0),
+ SD_BUS_PROPERTY("MemoryHigh", "t", NULL, offsetof(CGroupContext, memory_high), 0),
+ SD_BUS_PROPERTY("MemoryMax", "t", NULL, offsetof(CGroupContext, memory_max), 0),
SD_BUS_PROPERTY("MemoryLimit", "t", NULL, offsetof(CGroupContext, memory_limit), 0),
SD_BUS_PROPERTY("DevicePolicy", "s", property_get_cgroup_device_policy, offsetof(CGroupContext, device_policy), 0),
SD_BUS_PROPERTY("DeviceAllow", "a(ss)", property_get_device_allow, 0, 0),
@@ -624,7 +627,7 @@ int bus_cgroup_set_property(
if (r < 0)
return r;
- if (CGROUP_BLKIO_WEIGHT_IS_OK(weight))
+ if (!CGROUP_BLKIO_WEIGHT_IS_OK(weight))
return sd_bus_error_set_errnof(error, EINVAL, "StartupBlockIOWeight value out of range");
if (mode != UNIT_CHECK) {
@@ -639,7 +642,7 @@ int bus_cgroup_set_property(
return 1;
- } else if (streq(name, "BlockIOReadBandwidth") || streq(name, "BlockIOWriteBandwidth")) {
+ } else if (STR_IN_SET(name, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
const char *path;
bool read = true;
unsigned n = 0;
@@ -827,12 +830,74 @@ int bus_cgroup_set_property(
return 1;
+ } else if (STR_IN_SET(name, "MemoryLow", "MemoryHigh", "MemoryMax")) {
+ uint64_t v;
+
+ r = sd_bus_message_read(message, "t", &v);
+ if (r < 0)
+ return r;
+ if (v <= 0)
+ return sd_bus_error_set_errnof(error, EINVAL, "%s= is too small", name);
+
+ if (mode != UNIT_CHECK) {
+ if (streq(name, "MemoryLow"))
+ c->memory_low = v;
+ else if (streq(name, "MemoryHigh"))
+ c->memory_high = v;
+ else
+ c->memory_max = v;
+
+ unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
+
+ if (v == CGROUP_LIMIT_MAX)
+ unit_write_drop_in_private_format(u, mode, name, "%s=infinity", name);
+ else
+ unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu64, name, v);
+ }
+
+ return 1;
+
+ } else if (STR_IN_SET(name, "MemoryLowScale", "MemoryHighScale", "MemoryMaxScale")) {
+ uint32_t raw;
+ uint64_t v;
+
+ r = sd_bus_message_read(message, "u", &raw);
+ if (r < 0)
+ return r;
+
+ v = physical_memory_scale(raw, UINT32_MAX);
+ if (v <= 0 || v == UINT64_MAX)
+ return sd_bus_error_set_errnof(error, EINVAL, "%s= is out of range", name);
+
+ if (mode != UNIT_CHECK) {
+ const char *e;
+
+ /* Chop off suffix */
+ assert_se(e = endswith(name, "Scale"));
+ name = strndupa(name, e - name);
+
+ if (streq(name, "MemoryLow"))
+ c->memory_low = v;
+ else if (streq(name, "MemoryHigh"))
+ c->memory_high = v;
+ else
+ c->memory_max = v;
+
+ unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
+ unit_write_drop_in_private_format(u, mode, name, "%s=%" PRIu32 "%%", name,
+ (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX)));
+ }
+
+ return 1;
+
} else if (streq(name, "MemoryLimit")) {
uint64_t limit;
r = sd_bus_message_read(message, "t", &limit);
if (r < 0)
return r;
+ if (limit <= 0)
+ return sd_bus_error_set_errnof(error, EINVAL, "%s= is too small", name);
if (mode != UNIT_CHECK) {
c->memory_limit = limit;
@@ -846,6 +911,27 @@ int bus_cgroup_set_property(
return 1;
+ } else if (streq(name, "MemoryLimitScale")) {
+ uint64_t limit;
+ uint32_t raw;
+
+ r = sd_bus_message_read(message, "u", &raw);
+ if (r < 0)
+ return r;
+
+ limit = physical_memory_scale(raw, UINT32_MAX);
+ if (limit <= 0 || limit == UINT64_MAX)
+ return sd_bus_error_set_errnof(error, EINVAL, "%s= is out of range", name);
+
+ if (mode != UNIT_CHECK) {
+ c->memory_limit = limit;
+ unit_invalidate_cgroup(u, CGROUP_MASK_MEMORY);
+ unit_write_drop_in_private_format(u, mode, "MemoryLimit", "MemoryLimit=%" PRIu32 "%%",
+ (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX)));
+ }
+
+ return 1;
+
} else if (streq(name, "DevicePolicy")) {
const char *policy;
CGroupDevicePolicy p;
@@ -859,13 +945,9 @@ int bus_cgroup_set_property(
return -EINVAL;
if (mode != UNIT_CHECK) {
- char *buf;
-
c->device_policy = p;
unit_invalidate_cgroup(u, CGROUP_MASK_DEVICES);
-
- buf = strjoina("DevicePolicy=", policy);
- unit_write_drop_in_private(u, mode, name, buf);
+ unit_write_drop_in_private_format(u, mode, name, "DevicePolicy=%s", policy);
}
return 1;
@@ -881,6 +963,7 @@ int bus_cgroup_set_property(
while ((r = sd_bus_message_read(message, "(ss)", &path, &rwm)) > 0) {
if ((!startswith(path, "/dev/") &&
+ !startswith(path, "/run/systemd/inaccessible/") &&
!startswith(path, "block-") &&
!startswith(path, "char-")) ||
strpbrk(path, WHITESPACE))
@@ -980,6 +1063,8 @@ int bus_cgroup_set_property(
r = sd_bus_message_read(message, "t", &limit);
if (r < 0)
return r;
+ if (limit <= 0)
+ return sd_bus_error_set_errnof(error, EINVAL, "%s= is too small", name);
if (mode != UNIT_CHECK) {
c->tasks_max = limit;
@@ -992,6 +1077,26 @@ int bus_cgroup_set_property(
}
return 1;
+ } else if (streq(name, "TasksMaxScale")) {
+ uint64_t limit;
+ uint32_t raw;
+
+ r = sd_bus_message_read(message, "u", &raw);
+ if (r < 0)
+ return r;
+
+ limit = system_tasks_max_scale(raw, UINT32_MAX);
+ if (limit <= 0 || limit >= UINT64_MAX)
+ return sd_bus_error_set_errnof(error, EINVAL, "%s= is out of range", name);
+
+ if (mode != UNIT_CHECK) {
+ c->tasks_max = limit;
+ unit_invalidate_cgroup(u, CGROUP_MASK_PIDS);
+ unit_write_drop_in_private_format(u, mode, name, "TasksMax=%" PRIu32 "%%",
+ (uint32_t) (DIV_ROUND_UP((uint64_t) raw * 100U, (uint64_t) UINT32_MAX)));
+ }
+
+ return 1;
}
if (u->transient && u->load_state == UNIT_STUB) {
diff --git a/src/grp-system/libcore/dbus-execute.c b/src/grp-system/libcore/dbus-execute.c
index fe1d9da440..f7c217efc1 100644
--- a/src/grp-system/libcore/dbus-execute.c
+++ b/src/grp-system/libcore/dbus-execute.c
@@ -696,9 +696,12 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("Group", "s", NULL, offsetof(ExecContext, group), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SupplementaryGroups", "as", NULL, offsetof(ExecContext, supplementary_groups), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("PAMName", "s", NULL, offsetof(ExecContext, pam_name), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("ReadWriteDirectories", "as", NULL, offsetof(ExecContext, read_write_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("ReadOnlyDirectories", "as", NULL, offsetof(ExecContext, read_only_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("InaccessibleDirectories", "as", NULL, offsetof(ExecContext, inaccessible_dirs), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("ReadWriteDirectories", "as", NULL, offsetof(ExecContext, read_write_paths), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
+ SD_BUS_PROPERTY("ReadOnlyDirectories", "as", NULL, offsetof(ExecContext, read_only_paths), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
+ SD_BUS_PROPERTY("InaccessibleDirectories", "as", NULL, offsetof(ExecContext, inaccessible_paths), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
+ SD_BUS_PROPERTY("ReadWritePaths", "as", NULL, offsetof(ExecContext, read_write_paths), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("ReadOnlyPaths", "as", NULL, offsetof(ExecContext, read_only_paths), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("InaccessiblePaths", "as", NULL, offsetof(ExecContext, inaccessible_paths), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MountFlags", "t", bus_property_get_ulong, offsetof(ExecContext, mount_flags), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("PrivateTmp", "b", bus_property_get_bool, offsetof(ExecContext, private_tmp), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("PrivateNetwork", "b", bus_property_get_bool, offsetof(ExecContext, private_network), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -720,6 +723,8 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("RestrictAddressFamilies", "(bas)", property_get_address_families, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RuntimeDirectoryMode", "u", bus_property_get_mode, offsetof(ExecContext, runtime_directory_mode), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RuntimeDirectory", "as", NULL, offsetof(ExecContext, runtime_directory), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("MemoryDenyWriteExecute", "b", bus_property_get_bool, offsetof(ExecContext, memory_deny_write_execute), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("RestrictRealtime", "b", bus_property_get_bool, offsetof(ExecContext, restrict_realtime), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_VTABLE_END
};
@@ -843,7 +848,7 @@ int bus_exec_context_set_transient_property(
else if (free_and_strdup(&c->user, uu) < 0)
return -ENOMEM;
- unit_write_drop_in_private_format(u, mode, name, "User=%s\n", uu);
+ unit_write_drop_in_private_format(u, mode, name, "User=%s", uu);
}
return 1;
@@ -862,7 +867,7 @@ int bus_exec_context_set_transient_property(
else if (free_and_strdup(&c->group, gg) < 0)
return -ENOMEM;
- unit_write_drop_in_private_format(u, mode, name, "Group=%s\n", gg);
+ unit_write_drop_in_private_format(u, mode, name, "Group=%s", gg);
}
return 1;
@@ -880,7 +885,7 @@ int bus_exec_context_set_transient_property(
else if (free_and_strdup(&c->syslog_identifier, id) < 0)
return -ENOMEM;
- unit_write_drop_in_private_format(u, mode, name, "SyslogIdentifier=%s\n", id);
+ unit_write_drop_in_private_format(u, mode, name, "SyslogIdentifier=%s", id);
}
return 1;
@@ -896,7 +901,7 @@ int bus_exec_context_set_transient_property(
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);
+ unit_write_drop_in_private_format(u, mode, name, "SyslogLevel=%i", level);
}
return 1;
@@ -912,7 +917,7 @@ int bus_exec_context_set_transient_property(
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);
+ unit_write_drop_in_private_format(u, mode, name, "SyslogFacility=%i", facility);
}
return 1;
@@ -928,7 +933,7 @@ int bus_exec_context_set_transient_property(
if (mode != UNIT_CHECK) {
c->nice = n;
- unit_write_drop_in_private_format(u, mode, name, "Nice=%i\n", n);
+ unit_write_drop_in_private_format(u, mode, name, "Nice=%i", n);
}
return 1;
@@ -953,7 +958,7 @@ int bus_exec_context_set_transient_property(
if (r < 0)
return r;
- unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s);
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, s);
}
return 1;
@@ -1008,7 +1013,7 @@ int bus_exec_context_set_transient_property(
if (mode != UNIT_CHECK) {
c->std_input = p;
- unit_write_drop_in_private_format(u, mode, name, "StandardInput=%s\n", exec_input_to_string(p));
+ unit_write_drop_in_private_format(u, mode, name, "StandardInput=%s", exec_input_to_string(p));
}
return 1;
@@ -1029,7 +1034,7 @@ int bus_exec_context_set_transient_property(
if (mode != UNIT_CHECK) {
c->std_output = p;
- unit_write_drop_in_private_format(u, mode, name, "StandardOutput=%s\n", exec_output_to_string(p));
+ unit_write_drop_in_private_format(u, mode, name, "StandardOutput=%s", exec_output_to_string(p));
}
return 1;
@@ -1049,7 +1054,7 @@ int bus_exec_context_set_transient_property(
if (mode != UNIT_CHECK) {
c->std_error = p;
- unit_write_drop_in_private_format(u, mode, name, "StandardError=%s\n", exec_output_to_string(p));
+ unit_write_drop_in_private_format(u, mode, name, "StandardError=%s", exec_output_to_string(p));
}
return 1;
@@ -1057,7 +1062,7 @@ int bus_exec_context_set_transient_property(
} else if (STR_IN_SET(name,
"IgnoreSIGPIPE", "TTYVHangup", "TTYReset",
"PrivateTmp", "PrivateDevices", "PrivateNetwork",
- "NoNewPrivileges", "SyslogLevelPrefix")) {
+ "NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute", "RestrictRealtime")) {
int b;
r = sd_bus_message_read(message, "b", &b);
@@ -1081,8 +1086,12 @@ int bus_exec_context_set_transient_property(
c->no_new_privileges = b;
else if (streq(name, "SyslogLevelPrefix"))
c->syslog_level_prefix = b;
+ else if (streq(name, "MemoryDenyWriteExecute"))
+ c->memory_deny_write_execute = b;
+ else if (streq(name, "RestrictRealtime"))
+ c->restrict_realtime = b;
- unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, yes_no(b));
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, yes_no(b));
}
return 1;
@@ -1100,7 +1109,7 @@ int bus_exec_context_set_transient_property(
else if (free_and_strdup(&c->utmp_id, id) < 0)
return -ENOMEM;
- unit_write_drop_in_private_format(u, mode, name, "UtmpIdentifier=%s\n", strempty(id));
+ unit_write_drop_in_private_format(u, mode, name, "UtmpIdentifier=%s", strempty(id));
}
return 1;
@@ -1120,7 +1129,7 @@ int bus_exec_context_set_transient_property(
if (mode != UNIT_CHECK) {
c->utmp_mode = m;
- unit_write_drop_in_private_format(u, mode, name, "UtmpMode=%s\n", exec_utmp_mode_to_string(m));
+ unit_write_drop_in_private_format(u, mode, name, "UtmpMode=%s", exec_utmp_mode_to_string(m));
}
return 1;
@@ -1138,7 +1147,7 @@ int bus_exec_context_set_transient_property(
else if (free_and_strdup(&c->pam_name, n) < 0)
return -ENOMEM;
- unit_write_drop_in_private_format(u, mode, name, "PAMName=%s\n", strempty(n));
+ unit_write_drop_in_private_format(u, mode, name, "PAMName=%s", strempty(n));
}
return 1;
@@ -1160,7 +1169,7 @@ int bus_exec_context_set_transient_property(
if (strv_length(l) == 0) {
c->environment = strv_free(c->environment);
- unit_write_drop_in_private_format(u, mode, name, "Environment=\n");
+ unit_write_drop_in_private_format(u, mode, name, "Environment=");
} else {
e = strv_env_merge(2, c->environment, l);
if (!e)
@@ -1173,7 +1182,7 @@ int bus_exec_context_set_transient_property(
if (!joined)
return -ENOMEM;
- unit_write_drop_in_private_format(u, mode, name, "Environment=%s\n", joined);
+ unit_write_drop_in_private_format(u, mode, name, "Environment=%s", joined);
}
}
@@ -1189,7 +1198,7 @@ int bus_exec_context_set_transient_property(
if (mode != UNIT_CHECK) {
c->timer_slack_nsec = n;
- unit_write_drop_in_private_format(u, mode, name, "TimerSlackNSec=" NSEC_FMT "\n", n);
+ unit_write_drop_in_private_format(u, mode, name, "TimerSlackNSec=" NSEC_FMT, n);
}
return 1;
@@ -1207,7 +1216,7 @@ int bus_exec_context_set_transient_property(
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);
+ unit_write_drop_in_private_format(u, mode, name, "OOMScoreAdjust=%i", oa);
}
return 1;
@@ -1229,7 +1238,7 @@ int bus_exec_context_set_transient_property(
return -ENOMEM;
STRV_FOREACH(i, c->environment_files)
- fprintf(f, "EnvironmentFile=%s\n", *i);
+ fprintf(f, "EnvironmentFile=%s", *i);
while ((r = sd_bus_message_enter_container(message, 'r', "sb")) > 0) {
const char *path;
@@ -1253,7 +1262,7 @@ int bus_exec_context_set_transient_property(
if (!buf)
return -ENOMEM;
- fprintf(f, "EnvironmentFile=%s\n", buf);
+ fprintf(f, "EnvironmentFile=%s", buf);
r = strv_consume(&l, buf);
if (r < 0)
@@ -1274,7 +1283,7 @@ int bus_exec_context_set_transient_property(
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");
+ unit_write_drop_in_private(u, mode, name, "EnvironmentFile=");
} else {
r = strv_extend_strv(&c->environment_files, l, true);
if (r < 0)
@@ -1300,7 +1309,7 @@ int bus_exec_context_set_transient_property(
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");
+ unit_write_drop_in_private_format(u, mode, name, "PassEnvironment=");
} else {
_cleanup_free_ char *joined = NULL;
@@ -1312,14 +1321,14 @@ int bus_exec_context_set_transient_property(
if (!joined)
return -ENOMEM;
- unit_write_drop_in_private_format(u, mode, name, "PassEnvironment=%s\n", joined);
+ unit_write_drop_in_private_format(u, mode, name, "PassEnvironment=%s", joined);
}
}
return 1;
- } else if (STR_IN_SET(name, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories")) {
-
+ } else if (STR_IN_SET(name, "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories",
+ "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths")) {
_cleanup_strv_free_ char **l = NULL;
char ***dirs;
char **p;
@@ -1341,16 +1350,16 @@ int bus_exec_context_set_transient_property(
if (mode != UNIT_CHECK) {
_cleanup_free_ char *joined = NULL;
- if (streq(name, "ReadWriteDirectories"))
- dirs = &c->read_write_dirs;
- else if (streq(name, "ReadOnlyDirectories"))
- dirs = &c->read_only_dirs;
- else /* "InaccessibleDirectories" */
- dirs = &c->inaccessible_dirs;
+ if (STR_IN_SET(name, "ReadWriteDirectories", "ReadWritePaths"))
+ dirs = &c->read_write_paths;
+ else if (STR_IN_SET(name, "ReadOnlyDirectories", "ReadOnlyPaths"))
+ dirs = &c->read_only_paths;
+ else /* "InaccessiblePaths" */
+ dirs = &c->inaccessible_paths;
if (strv_length(l) == 0) {
*dirs = strv_free(*dirs);
- unit_write_drop_in_private_format(u, mode, name, "%s=\n", name);
+ unit_write_drop_in_private_format(u, mode, name, "%s=", name);
} else {
r = strv_extend_strv(dirs, l, true);
@@ -1361,7 +1370,7 @@ int bus_exec_context_set_transient_property(
if (!joined)
return -ENOMEM;
- unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, joined);
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, joined);
}
}
@@ -1389,7 +1398,7 @@ int bus_exec_context_set_transient_property(
if (mode != UNIT_CHECK) {
c->protect_system = ps;
- unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s);
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, s);
}
return 1;
@@ -1415,7 +1424,7 @@ int bus_exec_context_set_transient_property(
if (mode != UNIT_CHECK) {
c->protect_home = ph;
- unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, s);
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, s);
}
return 1;
@@ -1438,7 +1447,7 @@ int bus_exec_context_set_transient_property(
if (strv_isempty(l)) {
c->runtime_directory = strv_free(c->runtime_directory);
- unit_write_drop_in_private_format(u, mode, name, "%s=\n", name);
+ unit_write_drop_in_private_format(u, mode, name, "%s=", name);
} else {
r = strv_extend_strv(&c->runtime_directory, l, true);
@@ -1449,7 +1458,7 @@ int bus_exec_context_set_transient_property(
if (!joined)
return -ENOMEM;
- unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, joined);
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, joined);
}
}
@@ -1468,7 +1477,7 @@ int bus_exec_context_set_transient_property(
else if (free_and_strdup(&c->selinux_context, s) < 0)
return -ENOMEM;
- unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, strempty(s));
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, strempty(s));
}
return 1;
@@ -1536,7 +1545,7 @@ int bus_exec_context_set_transient_property(
return -ENOMEM;
}
- unit_write_drop_in_private_format(u, mode, name, "%s=%s\n", name, f);
+ unit_write_drop_in_private_format(u, mode, name, "%s=%s", name, f);
}
return 1;
diff --git a/src/grp-system/libcore/dbus-kill.c b/src/grp-system/libcore/dbus-kill.c
index ba7a3f3b72..44bc2db7e2 100644
--- a/src/grp-system/libcore/dbus-kill.c
+++ b/src/grp-system/libcore/dbus-kill.c
@@ -64,7 +64,7 @@ int bus_kill_context_set_transient_property(
if (mode != UNIT_CHECK) {
c->kill_mode = k;
- unit_write_drop_in_private_format(u, mode, name, "KillMode=%s\n", kill_mode_to_string(k));
+ unit_write_drop_in_private_format(u, mode, name, "KillMode=%s", kill_mode_to_string(k));
}
return 1;
@@ -82,7 +82,7 @@ int bus_kill_context_set_transient_property(
if (mode != UNIT_CHECK) {
c->kill_signal = sig;
- unit_write_drop_in_private_format(u, mode, name, "KillSignal=%s\n", signal_to_string(sig));
+ unit_write_drop_in_private_format(u, mode, name, "KillSignal=%s", signal_to_string(sig));
}
return 1;
@@ -97,7 +97,7 @@ int bus_kill_context_set_transient_property(
if (mode != UNIT_CHECK) {
c->send_sighup = b;
- unit_write_drop_in_private_format(u, mode, name, "SendSIGHUP=%s\n", yes_no(b));
+ unit_write_drop_in_private_format(u, mode, name, "SendSIGHUP=%s", yes_no(b));
}
return 1;
@@ -112,7 +112,7 @@ int bus_kill_context_set_transient_property(
if (mode != UNIT_CHECK) {
c->send_sigkill = b;
- unit_write_drop_in_private_format(u, mode, name, "SendSIGKILL=%s\n", yes_no(b));
+ unit_write_drop_in_private_format(u, mode, name, "SendSIGKILL=%s", yes_no(b));
}
return 1;
diff --git a/src/grp-system/libcore/dbus-manager.c b/src/grp-system/libcore/dbus-manager.c
index b2ca867987..c5684014d3 100644
--- a/src/grp-system/libcore/dbus-manager.c
+++ b/src/grp-system/libcore/dbus-manager.c
@@ -782,6 +782,7 @@ static int transient_unit_from_message(
return r;
/* Now load the missing bits of the unit we just created */
+ unit_add_to_load_queue(u);
manager_dispatch_load_queue(m);
*unit = u;
diff --git a/src/grp-system/libcore/dbus-scope.c b/src/grp-system/libcore/dbus-scope.c
index 9ecc01d275..d319597c10 100644
--- a/src/grp-system/libcore/dbus-scope.c
+++ b/src/grp-system/libcore/dbus-scope.c
@@ -148,7 +148,7 @@ static int bus_scope_set_transient_property(
if (r < 0)
return r;
- unit_write_drop_in_format(UNIT(s), mode, name, "[Scope]\nTimeoutStopSec="USEC_FMT"us\n", s->timeout_stop_usec);
+ unit_write_drop_in_private_format(UNIT(s), mode, name, "TimeoutStopSec="USEC_FMT"us", s->timeout_stop_usec);
} else {
r = sd_bus_message_skip(message, "t");
if (r < 0)
@@ -226,5 +226,5 @@ int bus_scope_send_request_stop(Scope *s) {
if (r < 0)
return r;
- return sd_bus_send_to(UNIT(s)->manager->api_bus, m, /* s->controller */ NULL, NULL);
+ return sd_bus_send_to(UNIT(s)->manager->api_bus, m, s->controller, NULL);
}
diff --git a/src/grp-system/libcore/dbus-service.c b/src/grp-system/libcore/dbus-service.c
index a666c9db95..a3524815bd 100644
--- a/src/grp-system/libcore/dbus-service.c
+++ b/src/grp-system/libcore/dbus-service.c
@@ -103,7 +103,7 @@ static int bus_service_set_transient_property(
if (mode != UNIT_CHECK) {
s->remain_after_exit = b;
- unit_write_drop_in_private_format(UNIT(s), mode, name, "RemainAfterExit=%s\n", yes_no(b));
+ unit_write_drop_in_private_format(UNIT(s), mode, name, "RemainAfterExit=%s", yes_no(b));
}
return 1;
@@ -122,7 +122,7 @@ static int bus_service_set_transient_property(
if (mode != UNIT_CHECK) {
s->type = k;
- unit_write_drop_in_private_format(UNIT(s), mode, name, "Type=%s\n", service_type_to_string(s->type));
+ unit_write_drop_in_private_format(UNIT(s), mode, name, "Type=%s", service_type_to_string(s->type));
}
return 1;
@@ -135,7 +135,7 @@ static int bus_service_set_transient_property(
if (mode != UNIT_CHECK) {
s->runtime_max_usec = u;
- unit_write_drop_in_private_format(UNIT(s), mode, name, "RuntimeMaxSec=" USEC_FMT "us\n", u);
+ unit_write_drop_in_private_format(UNIT(s), mode, name, "RuntimeMaxSec=" USEC_FMT "us", u);
}
return 1;
diff --git a/src/grp-system/libcore/dbus-timer.c b/src/grp-system/libcore/dbus-timer.c
index 02036de42f..ce454385f8 100644
--- a/src/grp-system/libcore/dbus-timer.c
+++ b/src/grp-system/libcore/dbus-timer.c
@@ -221,7 +221,7 @@ static int bus_timer_set_transient_property(
if (mode != UNIT_CHECK) {
char time[FORMAT_TIMESPAN_MAX];
- unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, format_timespan(time, sizeof(time), u, USEC_PER_MSEC));
+ unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s", name, format_timespan(time, sizeof(time), u, USEC_PER_MSEC));
v = new0(TimerValue, 1);
if (!v)
@@ -250,7 +250,7 @@ static int bus_timer_set_transient_property(
if (r < 0)
return r;
- unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s\n", name, str);
+ unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s", name, str);
v = new0(TimerValue, 1);
if (!v) {
@@ -278,7 +278,7 @@ static int bus_timer_set_transient_property(
if (mode != UNIT_CHECK) {
t->accuracy_usec = u;
- unit_write_drop_in_private_format(UNIT(t), mode, name, "AccuracySec=" USEC_FMT "us\n", u);
+ unit_write_drop_in_private_format(UNIT(t), mode, name, "AccuracySec=" USEC_FMT "us", u);
}
return 1;
@@ -292,7 +292,7 @@ static int bus_timer_set_transient_property(
if (mode != UNIT_CHECK) {
t->random_usec = u;
- unit_write_drop_in_private_format(UNIT(t), mode, name, "RandomizedDelaySec=" USEC_FMT "us\n", u);
+ unit_write_drop_in_private_format(UNIT(t), mode, name, "RandomizedDelaySec=" USEC_FMT "us", u);
}
return 1;
@@ -306,7 +306,7 @@ 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(b));
+ unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s", name, yes_no(b));
}
return 1;
@@ -320,7 +320,7 @@ static int bus_timer_set_transient_property(
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));
+ unit_write_drop_in_private_format(UNIT(t), mode, name, "%s=%s", name, yes_no(b));
}
return 1;
diff --git a/src/grp-system/libcore/dbus-unit.c b/src/grp-system/libcore/dbus-unit.c
index 31fbb0d54d..7e2a63b434 100644
--- a/src/grp-system/libcore/dbus-unit.c
+++ b/src/grp-system/libcore/dbus-unit.c
@@ -1206,7 +1206,7 @@ static int bus_unit_set_transient_property(
if (r < 0)
return r;
- unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s\n", d);
+ unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s", d);
}
return 1;
@@ -1220,7 +1220,7 @@ static int bus_unit_set_transient_property(
if (mode != UNIT_CHECK) {
u->default_dependencies = b;
- unit_write_drop_in_format(u, mode, name, "[Unit]\nDefaultDependencies=%s\n", yes_no(b));
+ unit_write_drop_in_format(u, mode, name, "[Unit]\nDefaultDependencies=%s", yes_no(b));
}
return 1;
@@ -1258,7 +1258,7 @@ static int bus_unit_set_transient_property(
if (r < 0)
return r;
- unit_write_drop_in_private_format(u, mode, name, "Slice=%s\n", s);
+ unit_write_drop_in_private_format(u, mode, name, "Slice=%s", s);
}
return 1;
@@ -1306,7 +1306,7 @@ static int bus_unit_set_transient_property(
if (!label)
return -ENOMEM;
- unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s\n", name, other);
+ unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s", name, other);
}
}
diff --git a/src/grp-system/libcore/execute.c b/src/grp-system/libcore/execute.c
index b19473c6a5..b73577817f 100644
--- a/src/grp-system/libcore/execute.c
+++ b/src/grp-system/libcore/execute.c
@@ -25,6 +25,7 @@
#include <signal.h>
#include <string.h>
#include <sys/capability.h>
+#include <sys/mman.h>
#include <sys/personality.h>
#include <sys/prctl.h>
#include <sys/socket.h>
@@ -290,7 +291,15 @@ static int connect_journal_socket(int fd, uid_t uid, gid_t gid) {
return r;
}
-static int connect_logger_as(const ExecContext *context, ExecOutput output, const char *ident, const char *unit_id, int nfd, uid_t uid, gid_t gid) {
+static int connect_logger_as(
+ Unit *unit,
+ const ExecContext *context,
+ ExecOutput output,
+ const char *ident,
+ int nfd,
+ uid_t uid,
+ gid_t gid) {
+
int fd, r;
assert(context);
@@ -311,7 +320,7 @@ static int connect_logger_as(const ExecContext *context, ExecOutput output, cons
return -errno;
}
- fd_inc_sndbuf(fd, SNDBUF_SIZE);
+ (void) fd_inc_sndbuf(fd, SNDBUF_SIZE);
dprintf(fd,
"%s\n"
@@ -322,18 +331,18 @@ static int connect_logger_as(const ExecContext *context, ExecOutput output, cons
"%i\n"
"%i\n",
context->syslog_identifier ? context->syslog_identifier : ident,
- unit_id,
+ unit->id,
context->syslog_priority,
!!context->syslog_level_prefix,
output == EXEC_OUTPUT_SYSLOG || output == EXEC_OUTPUT_SYSLOG_AND_CONSOLE,
output == EXEC_OUTPUT_KMSG || output == EXEC_OUTPUT_KMSG_AND_CONSOLE,
is_terminal_output(output));
- if (fd != nfd) {
- r = dup2(fd, nfd) < 0 ? -errno : nfd;
- safe_close(fd);
- } else
- r = nfd;
+ if (fd == nfd)
+ return nfd;
+
+ r = dup2(fd, nfd) < 0 ? -errno : nfd;
+ safe_close(fd);
return r;
}
@@ -447,7 +456,10 @@ static int setup_output(
int fileno,
int socket_fd,
const char *ident,
- uid_t uid, gid_t gid) {
+ uid_t uid,
+ gid_t gid,
+ dev_t *journal_stream_dev,
+ ino_t *journal_stream_ino) {
ExecOutput o;
ExecInput i;
@@ -457,6 +469,8 @@ static int setup_output(
assert(context);
assert(params);
assert(ident);
+ assert(journal_stream_dev);
+ assert(journal_stream_ino);
if (fileno == STDOUT_FILENO && params->stdout_fd >= 0) {
@@ -532,10 +546,21 @@ static int setup_output(
case EXEC_OUTPUT_KMSG_AND_CONSOLE:
case EXEC_OUTPUT_JOURNAL:
case EXEC_OUTPUT_JOURNAL_AND_CONSOLE:
- r = connect_logger_as(context, o, ident, unit->id, fileno, uid, gid);
+ r = connect_logger_as(unit, context, o, ident, fileno, uid, gid);
if (r < 0) {
log_unit_error_errno(unit, r, "Failed to connect %s to the journal socket, ignoring: %m", fileno == STDOUT_FILENO ? "stdout" : "stderr");
r = open_null_as(O_WRONLY, fileno);
+ } else {
+ struct stat st;
+
+ /* If we connected this fd to the journal via a stream, patch the device/inode into the passed
+ * parameters, but only then. This is useful so that we can set $JOURNAL_STREAM that permits
+ * services to detect whether they are connected to the journal or not. */
+
+ if (fstat(fileno, &st) >= 0) {
+ *journal_stream_dev = st.st_dev;
+ *journal_stream_ino = st.st_ino;
+ }
}
return r;
@@ -553,6 +578,10 @@ static int chown_terminal(int fd, uid_t uid) {
assert(fd >= 0);
+ /* Before we chown/chmod the TTY, let's ensure this is actually a tty */
+ if (isatty(fd) < 1)
+ return 0;
+
/* This might fail. What matters are the results. */
(void) fchown(fd, uid, -1);
(void) fchmod(fd, TTY_MODE);
@@ -796,7 +825,7 @@ static int setup_pam(
const char *user,
uid_t uid,
const char *tty,
- char ***pam_env,
+ char ***env,
int fds[], unsigned n_fds) {
static const struct pam_conv conv = {
@@ -808,14 +837,14 @@ static int setup_pam(
pam_handle_t *handle = NULL;
sigset_t old_ss;
int pam_code = PAM_SUCCESS, r;
- char **e = NULL;
+ char **nv, **e = NULL;
bool close_session = false;
pid_t pam_pid = 0, parent_pid;
int flags = 0;
assert(name);
assert(user);
- assert(pam_env);
+ assert(env);
/* We set up PAM in the parent process, then fork. The child
* will then stay around until killed via PR_GET_PDEATHSIG or
@@ -843,6 +872,12 @@ static int setup_pam(
goto fail;
}
+ STRV_FOREACH(nv, *env) {
+ pam_code = pam_putenv(handle, *nv);
+ if (pam_code != PAM_SUCCESS)
+ goto fail;
+ }
+
pam_code = pam_acct_mgmt(handle, flags);
if (pam_code != PAM_SUCCESS)
goto fail;
@@ -963,8 +998,8 @@ static int setup_pam(
if (!barrier_place_and_sync(&barrier))
log_error("PAM initialization failed");
- *pam_env = e;
- e = NULL;
+ strv_free(*env);
+ *env = e;
return 0;
@@ -1192,6 +1227,115 @@ finish:
return r;
}
+static int apply_memory_deny_write_execute(const ExecContext *c) {
+ scmp_filter_ctx *seccomp;
+ int r;
+
+ assert(c);
+
+ seccomp = seccomp_init(SCMP_ACT_ALLOW);
+ if (!seccomp)
+ return -ENOMEM;
+
+ r = seccomp_rule_add(
+ seccomp,
+ SCMP_ACT_ERRNO(EPERM),
+ SCMP_SYS(mmap),
+ 1,
+ SCMP_A2(SCMP_CMP_MASKED_EQ, PROT_EXEC|PROT_WRITE, PROT_EXEC|PROT_WRITE));
+ if (r < 0)
+ goto finish;
+
+ r = seccomp_rule_add(
+ seccomp,
+ SCMP_ACT_ERRNO(EPERM),
+ SCMP_SYS(mprotect),
+ 1,
+ SCMP_A2(SCMP_CMP_MASKED_EQ, PROT_EXEC, PROT_EXEC));
+ if (r < 0)
+ goto finish;
+
+ r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0);
+ if (r < 0)
+ goto finish;
+
+ r = seccomp_load(seccomp);
+
+finish:
+ seccomp_release(seccomp);
+ return r;
+}
+
+static int apply_restrict_realtime(const ExecContext *c) {
+ static const int permitted_policies[] = {
+ SCHED_OTHER,
+ SCHED_BATCH,
+ SCHED_IDLE,
+ };
+
+ scmp_filter_ctx *seccomp;
+ unsigned i;
+ int r, p, max_policy = 0;
+
+ assert(c);
+
+ seccomp = seccomp_init(SCMP_ACT_ALLOW);
+ if (!seccomp)
+ return -ENOMEM;
+
+ /* Determine the highest policy constant we want to allow */
+ for (i = 0; i < ELEMENTSOF(permitted_policies); i++)
+ if (permitted_policies[i] > max_policy)
+ max_policy = permitted_policies[i];
+
+ /* Go through all policies with lower values than that, and block them -- unless they appear in the
+ * whitelist. */
+ for (p = 0; p < max_policy; p++) {
+ bool good = false;
+
+ /* Check if this is in the whitelist. */
+ for (i = 0; i < ELEMENTSOF(permitted_policies); i++)
+ if (permitted_policies[i] == p) {
+ good = true;
+ break;
+ }
+
+ if (good)
+ continue;
+
+ /* Deny this policy */
+ r = seccomp_rule_add(
+ seccomp,
+ SCMP_ACT_ERRNO(EPERM),
+ SCMP_SYS(sched_setscheduler),
+ 1,
+ SCMP_A1(SCMP_CMP_EQ, p));
+ if (r < 0)
+ goto finish;
+ }
+
+ /* Blacklist all other policies, i.e. the ones with higher values. Note that all comparisons are unsigned here,
+ * hence no need no check for < 0 values. */
+ r = seccomp_rule_add(
+ seccomp,
+ SCMP_ACT_ERRNO(EPERM),
+ SCMP_SYS(sched_setscheduler),
+ 1,
+ SCMP_A1(SCMP_CMP_GT, max_policy));
+ if (r < 0)
+ goto finish;
+
+ r = seccomp_attr_set(seccomp, SCMP_FLTATR_CTL_NNP, 0);
+ if (r < 0)
+ goto finish;
+
+ r = seccomp_load(seccomp);
+
+finish:
+ seccomp_release(seccomp);
+ return r;
+}
+
#endif
static void do_idle_pipe_dance(int idle_pipe[4]) {
@@ -1230,6 +1374,8 @@ static int build_environment(
const char *home,
const char *username,
const char *shell,
+ dev_t journal_stream_dev,
+ ino_t journal_stream_ino,
char ***ret) {
_cleanup_strv_free_ char **our_env = NULL;
@@ -1239,7 +1385,7 @@ static int build_environment(
assert(c);
assert(ret);
- our_env = new0(char*, 11);
+ our_env = new0(char*, 12);
if (!our_env)
return -ENOMEM;
@@ -1311,8 +1457,15 @@ static int build_environment(
our_env[n_env++] = x;
}
+ if (journal_stream_dev != 0 && journal_stream_ino != 0) {
+ if (asprintf(&x, "JOURNAL_STREAM=" DEV_FMT ":" INO_FMT, journal_stream_dev, journal_stream_ino) < 0)
+ return -ENOMEM;
+
+ our_env[n_env++] = x;
+ }
+
our_env[n_env++] = NULL;
- assert(n_env <= 11);
+ assert(n_env <= 12);
*ret = our_env;
our_env = NULL;
@@ -1356,9 +1509,9 @@ static bool exec_needs_mount_namespace(
assert(context);
assert(params);
- if (!strv_isempty(context->read_write_dirs) ||
- !strv_isempty(context->read_only_dirs) ||
- !strv_isempty(context->inaccessible_dirs))
+ if (!strv_isempty(context->read_write_paths) ||
+ !strv_isempty(context->read_only_paths) ||
+ !strv_isempty(context->inaccessible_paths))
return true;
if (context->mount_flags != 0)
@@ -1422,13 +1575,15 @@ static int exec_child(
char **files_env,
int *exit_status) {
- _cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **pam_env = NULL, **final_env = NULL, **final_argv = NULL;
+ _cleanup_strv_free_ char **our_env = NULL, **pass_env = NULL, **accum_env = NULL, **final_argv = NULL;
_cleanup_free_ char *mac_selinux_context_net = NULL;
const char *username = NULL, *home = NULL, *shell = NULL, *wd;
+ dev_t journal_stream_dev = 0;
+ ino_t journal_stream_ino = 0;
+ bool needs_mount_namespace;
uid_t uid = UID_INVALID;
gid_t gid = GID_INVALID;
int i, r;
- bool needs_mount_namespace;
assert(unit);
assert(command);
@@ -1528,13 +1683,13 @@ static int exec_child(
return r;
}
- r = setup_output(unit, context, params, STDOUT_FILENO, socket_fd, basename(command->path), uid, gid);
+ r = setup_output(unit, context, params, STDOUT_FILENO, socket_fd, basename(command->path), uid, gid, &journal_stream_dev, &journal_stream_ino);
if (r < 0) {
*exit_status = EXIT_STDOUT;
return r;
}
- r = setup_output(unit, context, params, STDERR_FILENO, socket_fd, basename(command->path), uid, gid);
+ r = setup_output(unit, context, params, STDERR_FILENO, socket_fd, basename(command->path), uid, gid, &journal_stream_dev, &journal_stream_ino);
if (r < 0) {
*exit_status = EXIT_STDERR;
return r;
@@ -1673,9 +1828,43 @@ static int exec_child(
}
}
+ r = build_environment(
+ context,
+ params,
+ n_fds,
+ home,
+ username,
+ shell,
+ journal_stream_dev,
+ journal_stream_ino,
+ &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;
+ }
+
+ accum_env = strv_env_merge(5,
+ params->environment,
+ our_env,
+ pass_env,
+ context->environment,
+ files_env,
+ NULL);
+ if (!accum_env) {
+ *exit_status = EXIT_MEMORY;
+ return -ENOMEM;
+ }
+ accum_env = strv_env_clean(accum_env);
+
umask(context->umask);
- if (params->apply_permissions) {
+ if (params->apply_permissions && !command->privileged) {
r = enforce_groups(context, username, gid);
if (r < 0) {
*exit_status = EXIT_GROUP;
@@ -1709,7 +1898,7 @@ static int exec_child(
#endif
#ifdef HAVE_PAM
if (context->pam_name && username) {
- r = setup_pam(context->pam_name, username, uid, context->tty_path, &pam_env, fds, n_fds);
+ r = setup_pam(context->pam_name, username, uid, context->tty_path, &accum_env, fds, n_fds);
if (r < 0) {
*exit_status = EXIT_PAM;
return r;
@@ -1746,9 +1935,9 @@ static int exec_child(
r = setup_namespace(
params->apply_chroot ? context->root_directory : NULL,
- context->read_write_dirs,
- context->read_only_dirs,
- context->inaccessible_dirs,
+ context->read_write_paths,
+ context->read_only_paths,
+ context->inaccessible_paths,
tmp,
var,
context->private_devices,
@@ -1800,7 +1989,7 @@ static int exec_child(
}
#ifdef HAVE_SELINUX
- if (params->apply_permissions && mac_selinux_use() && params->selinux_context_net && socket_fd >= 0) {
+ if (params->apply_permissions && mac_selinux_use() && params->selinux_context_net && socket_fd >= 0 && !command->privileged) {
r = mac_selinux_get_child_mls_label(socket_fd, command->path, context->selinux_context, &mac_selinux_context_net);
if (r < 0) {
*exit_status = EXIT_SELINUX_CONTEXT;
@@ -1825,7 +2014,7 @@ static int exec_child(
return r;
}
- if (params->apply_permissions) {
+ if (params->apply_permissions && !command->privileged) {
bool use_address_families = context->address_families_whitelist ||
!set_isempty(context->address_families);
@@ -1835,10 +2024,20 @@ static int exec_child(
int secure_bits = context->secure_bits;
for (i = 0; i < _RLIMIT_MAX; i++) {
+
if (!context->rlimit[i])
continue;
- if (setrlimit_closest(i, context->rlimit[i]) < 0) {
+ r = setrlimit_closest(i, context->rlimit[i]);
+ if (r < 0) {
+ *exit_status = EXIT_LIMITS;
+ return r;
+ }
+ }
+
+ /* Set the RTPRIO resource limit to 0, but only if nothing else was explicitly requested. */
+ if (context->restrict_realtime && !context->rlimit[RLIMIT_RTPRIO]) {
+ if (setrlimit(RLIMIT_RTPRIO, &RLIMIT_MAKE_CONST(0)) < 0) {
*exit_status = EXIT_LIMITS;
return -errno;
}
@@ -1899,7 +2098,7 @@ static int exec_child(
}
if (context->no_new_privileges ||
- (!have_effective_cap(CAP_SYS_ADMIN) && (use_address_families || use_syscall_filter)))
+ (!have_effective_cap(CAP_SYS_ADMIN) && (use_address_families || context->memory_deny_write_execute || context->restrict_realtime || use_syscall_filter)))
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
*exit_status = EXIT_NO_NEW_PRIVILEGES;
return -errno;
@@ -1914,6 +2113,22 @@ static int exec_child(
}
}
+ if (context->memory_deny_write_execute) {
+ r = apply_memory_deny_write_execute(context);
+ if (r < 0) {
+ *exit_status = EXIT_SECCOMP;
+ return r;
+ }
+ }
+
+ if (context->restrict_realtime) {
+ r = apply_restrict_realtime(context);
+ if (r < 0) {
+ *exit_status = EXIT_SECCOMP;
+ return r;
+ }
+ }
+
if (use_syscall_filter) {
r = apply_seccomp(context);
if (r < 0) {
@@ -1948,39 +2163,12 @@ static int exec_child(
#endif
}
- r = build_environment(context, params, n_fds, home, username, shell, &our_env);
- if (r < 0) {
- *exit_status = EXIT_MEMORY;
- return r;
- }
-
- r = build_pass_environment(context, &pass_env);
- if (r < 0) {
- *exit_status = EXIT_MEMORY;
- return r;
- }
-
- final_env = strv_env_merge(6,
- params->environment,
- our_env,
- pass_env,
- context->environment,
- files_env,
- pam_env,
- NULL);
- if (!final_env) {
- *exit_status = EXIT_MEMORY;
- return -ENOMEM;
- }
-
- final_argv = replace_env_argv(argv, final_env);
+ final_argv = replace_env_argv(argv, accum_env);
if (!final_argv) {
*exit_status = EXIT_MEMORY;
return -ENOMEM;
}
- final_env = strv_env_clean(final_env);
-
if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
_cleanup_free_ char *line;
@@ -1996,7 +2184,7 @@ static int exec_child(
}
}
- execve(command->path, final_argv, final_env);
+ execve(command->path, final_argv, accum_env);
*exit_status = EXIT_EXEC;
return -errno;
}
@@ -2138,9 +2326,9 @@ void exec_context_done(ExecContext *c) {
c->pam_name = mfree(c->pam_name);
- c->read_only_dirs = strv_free(c->read_only_dirs);
- c->read_write_dirs = strv_free(c->read_write_dirs);
- c->inaccessible_dirs = strv_free(c->inaccessible_dirs);
+ c->read_only_paths = strv_free(c->read_only_paths);
+ c->read_write_paths = strv_free(c->read_write_paths);
+ c->inaccessible_paths = strv_free(c->inaccessible_paths);
if (c->cpuset)
CPU_FREE(c->cpuset);
@@ -2373,7 +2561,9 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
"%sPrivateDevices: %s\n"
"%sProtectHome: %s\n"
"%sProtectSystem: %s\n"
- "%sIgnoreSIGPIPE: %s\n",
+ "%sIgnoreSIGPIPE: %s\n"
+ "%sMemoryDenyWriteExecute: %s\n"
+ "%sRestrictRealtime: %s\n",
prefix, c->umask,
prefix, c->working_directory ? c->working_directory : "/",
prefix, c->root_directory ? c->root_directory : "/",
@@ -2383,7 +2573,9 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
prefix, yes_no(c->private_devices),
prefix, protect_home_to_string(c->protect_home),
prefix, protect_system_to_string(c->protect_system),
- prefix, yes_no(c->ignore_sigpipe));
+ prefix, yes_no(c->ignore_sigpipe),
+ prefix, yes_no(c->memory_deny_write_execute),
+ prefix, yes_no(c->restrict_realtime));
STRV_FOREACH(e, c->environment)
fprintf(f, "%sEnvironment: %s\n", prefix, *e);
@@ -2542,21 +2734,21 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
if (c->pam_name)
fprintf(f, "%sPAMName: %s\n", prefix, c->pam_name);
- if (strv_length(c->read_write_dirs) > 0) {
- fprintf(f, "%sReadWriteDirs:", prefix);
- strv_fprintf(f, c->read_write_dirs);
+ if (strv_length(c->read_write_paths) > 0) {
+ fprintf(f, "%sReadWritePaths:", prefix);
+ strv_fprintf(f, c->read_write_paths);
fputs("\n", f);
}
- if (strv_length(c->read_only_dirs) > 0) {
- fprintf(f, "%sReadOnlyDirs:", prefix);
- strv_fprintf(f, c->read_only_dirs);
+ if (strv_length(c->read_only_paths) > 0) {
+ fprintf(f, "%sReadOnlyPaths:", prefix);
+ strv_fprintf(f, c->read_only_paths);
fputs("\n", f);
}
- if (strv_length(c->inaccessible_dirs) > 0) {
- fprintf(f, "%sInaccessibleDirs:", prefix);
- strv_fprintf(f, c->inaccessible_dirs);
+ if (strv_length(c->inaccessible_paths) > 0) {
+ fprintf(f, "%sInaccessiblePaths:", prefix);
+ strv_fprintf(f, c->inaccessible_paths);
fputs("\n", f);
}
@@ -2637,7 +2829,7 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
bool exec_context_maintains_privileges(ExecContext *c) {
assert(c);
- /* Returns true if the process forked off would run run under
+ /* Returns true if the process forked off would run under
* an unchanged UID or as root. */
if (!c->user)
@@ -2872,7 +3064,7 @@ int exec_runtime_make(ExecRuntime **rt, ExecContext *c, const char *id) {
return r;
if (c->private_network && (*rt)->netns_storage_socket[0] < 0) {
- if (socketpair(AF_UNIX, SOCK_DGRAM, 0, (*rt)->netns_storage_socket) < 0)
+ if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, (*rt)->netns_storage_socket) < 0)
return -errno;
}
diff --git a/src/grp-system/libcore/execute.h b/src/grp-system/libcore/execute.h
index 18d6f0e4a3..cf5e7e4617 100644
--- a/src/grp-system/libcore/execute.h
+++ b/src/grp-system/libcore/execute.h
@@ -24,9 +24,10 @@
#include <stdio.h>
#include <sys/capability.h>
-#include "basic/fdset.h"
+#include "basic/cgroup-util.h"
#include "basic/list.h"
#include "basic/missing.h"
+#include "shared/fdset.h"
typedef struct ExecCommand ExecCommand;
typedef struct ExecContext ExecContext;
@@ -82,7 +83,8 @@ struct ExecCommand {
char **argv;
ExecStatus exec_status;
LIST_FIELDS(ExecCommand, command); /* useful for chaining commands */
- bool ignore;
+ bool ignore:1;
+ bool privileged:1;
};
struct ExecRuntime {
@@ -130,7 +132,7 @@ struct ExecContext {
bool ignore_sigpipe;
- /* Since resolving these names might might involve socket
+ /* Since resolving these names might involve socket
* connections and we don't want to deadlock ourselves these
* names are resolved on execution only and in the child
* process. */
@@ -152,7 +154,7 @@ struct ExecContext {
bool smack_process_label_ignore;
char *smack_process_label;
- char **read_write_dirs, **read_only_dirs, **inaccessible_dirs;
+ char **read_write_paths, **read_only_paths, **inaccessible_paths;
unsigned long mount_flags;
uint64_t capability_bounding_set;
@@ -193,6 +195,9 @@ struct ExecContext {
char **runtime_directory;
mode_t runtime_directory_mode;
+ bool memory_deny_write_execute;
+ bool restrict_realtime;
+
bool oom_score_adjust_set:1;
bool nice_set:1;
bool ioprio_set:1;
@@ -200,10 +205,6 @@ struct ExecContext {
bool no_new_privileges_set:1;
};
-#include "basic/cgroup-util.h"
-
-#include "cgroup.h"
-
struct ExecParameters {
char **argv;
char **environment;
@@ -234,6 +235,8 @@ struct ExecParameters {
int stderr_fd;
};
+#include "unit.h"
+
int exec_spawn(Unit *unit,
ExecCommand *command,
const ExecContext *context,
diff --git a/src/grp-system/libcore/killall.c b/src/grp-system/libcore/killall.c
index bc4d67ae21..27946f1f84 100644
--- a/src/grp-system/libcore/killall.c
+++ b/src/grp-system/libcore/killall.c
@@ -23,6 +23,7 @@
#include <unistd.h>
#include "basic/alloc-util.h"
+#include "basic/def.h"
#include "basic/fd-util.h"
#include "basic/formats-util.h"
#include "basic/parse-util.h"
@@ -34,8 +35,6 @@
#include "killall.h"
-#define TIMEOUT_USEC (10 * USEC_PER_SEC)
-
static bool ignore_proc(pid_t pid, bool warn_rootfs) {
_cleanup_fclose_ FILE *f = NULL;
char c;
@@ -81,7 +80,7 @@ static bool ignore_proc(pid_t pid, bool warn_rootfs) {
get_process_comm(pid, &comm);
if (r)
- log_notice("Process " PID_FMT " (%s) has been been marked to be excluded from killing. It is "
+ log_notice("Process " PID_FMT " (%s) has been marked to be excluded from killing. It is "
"running from the root file system, and thus likely to block re-mounting of the "
"root file system to read-only. Please consider moving it into an initrd file "
"system instead.", pid, strna(comm));
@@ -100,7 +99,7 @@ static void wait_for_children(Set *pids, sigset_t *mask) {
if (set_isempty(pids))
return;
- until = now(CLOCK_MONOTONIC) + TIMEOUT_USEC;
+ until = now(CLOCK_MONOTONIC) + DEFAULT_TIMEOUT_USEC;
for (;;) {
struct timespec ts;
int k;
diff --git a/src/grp-system/libcore/kmod-setup.c b/src/grp-system/libcore/kmod-setup.c
index a6fa6a32fb..c91c280e7d 100644
--- a/src/grp-system/libcore/kmod-setup.c
+++ b/src/grp-system/libcore/kmod-setup.c
@@ -65,9 +65,6 @@ int kmod_setup(void) {
/* this should never be a module */
{ "unix", "/proc/net/unix", true, true, NULL },
- /* IPC is needed before we bring up any other services */
- { "kdbus", "/sys/fs/kdbus", false, false, is_kdbus_wanted },
-
#ifdef HAVE_LIBIPTC
/* netfilter is needed by networkd, nspawn among others, and cannot be autoloaded */
{ "ip_tables", "/proc/net/ip_tables_names", false, false, NULL },
diff --git a/src/grp-system/libcore/load-fragment-gperf.gperf.m4 b/src/grp-system/libcore/load-fragment-gperf.gperf.m4
index c9f6e6acf7..ac4598f4c2 100644
--- a/src/grp-system/libcore/load-fragment-gperf.gperf.m4
+++ b/src/grp-system/libcore/load-fragment-gperf.gperf.m4
@@ -55,10 +55,14 @@ m4_ifdef(`HAVE_SECCOMP',
`$1.SystemCallFilter, config_parse_syscall_filter, 0, offsetof($1, exec_context)
$1.SystemCallArchitectures, config_parse_syscall_archs, 0, offsetof($1, exec_context.syscall_archs)
$1.SystemCallErrorNumber, config_parse_syscall_errno, 0, offsetof($1, exec_context)
+$1.MemoryDenyWriteExecute, config_parse_bool, 0, offsetof($1, exec_context.memory_deny_write_execute)
+$1.RestrictRealtime, config_parse_bool, 0, offsetof($1, exec_context.restrict_realtime)
$1.RestrictAddressFamilies, config_parse_address_families, 0, offsetof($1, exec_context)',
`$1.SystemCallFilter, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.SystemCallArchitectures, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
$1.SystemCallErrorNumber, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
+$1.MemoryDenyWriteExecute, config_parse_warn_compat, DISABLED_CONFIGURATION, 0
+$1.RestrictRealtime, 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)
@@ -76,9 +80,12 @@ $1.LimitMSGQUEUE, config_parse_limit, RLIMIT_MSGQ
$1.LimitNICE, config_parse_limit, RLIMIT_NICE, offsetof($1, exec_context.rlimit)
$1.LimitRTPRIO, config_parse_limit, RLIMIT_RTPRIO, offsetof($1, exec_context.rlimit)
$1.LimitRTTIME, config_parse_limit, RLIMIT_RTTIME, offsetof($1, exec_context.rlimit)
-$1.ReadWriteDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_dirs)
-$1.ReadOnlyDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_dirs)
-$1.InaccessibleDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_dirs)
+$1.ReadWriteDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_paths)
+$1.ReadOnlyDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_paths)
+$1.InaccessibleDirectories, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_paths)
+$1.ReadWritePaths, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_write_paths)
+$1.ReadOnlyPaths, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_paths)
+$1.InaccessiblePaths, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_paths)
$1.PrivateTmp, config_parse_bool, 0, offsetof($1, exec_context.private_tmp)
$1.PrivateNetwork, config_parse_bool, 0, offsetof($1, exec_context.private_network)
$1.PrivateDevices, config_parse_bool, 0, offsetof($1, exec_context.private_devices)
@@ -117,6 +124,9 @@ $1.CPUShares, config_parse_cpu_shares, 0,
$1.StartupCPUShares, config_parse_cpu_shares, 0, offsetof($1, cgroup_context.startup_cpu_shares)
$1.CPUQuota, config_parse_cpu_quota, 0, offsetof($1, cgroup_context)
$1.MemoryAccounting, config_parse_bool, 0, offsetof($1, cgroup_context.memory_accounting)
+$1.MemoryLow, config_parse_memory_limit, 0, offsetof($1, cgroup_context)
+$1.MemoryHigh, config_parse_memory_limit, 0, offsetof($1, cgroup_context)
+$1.MemoryMax, config_parse_memory_limit, 0, offsetof($1, cgroup_context)
$1.MemoryLimit, config_parse_memory_limit, 0, offsetof($1, cgroup_context)
$1.DeviceAllow, config_parse_device_allow, 0, offsetof($1, cgroup_context)
$1.DevicePolicy, config_parse_device_policy, 0, offsetof($1, cgroup_context.device_policy)
diff --git a/src/grp-system/libcore/load-fragment.c b/src/grp-system/libcore/load-fragment.c
index bb12b6cbfe..9a6ffc8bff 100644
--- a/src/grp-system/libcore/load-fragment.c
+++ b/src/grp-system/libcore/load-fragment.c
@@ -599,7 +599,7 @@ int config_parse_exec(
p = rvalue;
do {
_cleanup_free_ char *path = NULL, *firstword = NULL;
- bool separate_argv0 = false, ignore = false;
+ bool separate_argv0 = false, ignore = false, privileged = false;
_cleanup_free_ ExecCommand *nce = NULL;
_cleanup_strv_free_ char **n = NULL;
size_t nlen = 0, nbufsize = 0;
@@ -613,14 +613,18 @@ int config_parse_exec(
return 0;
f = firstword;
- for (i = 0; i < 2; i++) {
- /* We accept an absolute path as first argument, or
- * alternatively an absolute prefixed with @ to allow
- * overriding of argv[0]. */
+ for (i = 0; i < 3; i++) {
+ /* We accept an absolute path as first argument.
+ * If it's prefixed with - and the path doesn't exist,
+ * we ignore it instead of erroring out;
+ * if it's prefixed with @, we allow overriding of argv[0];
+ * and if it's prefixed with !, it will be run with full privileges */
if (*f == '-' && !ignore)
ignore = true;
else if (*f == '@' && !separate_argv0)
separate_argv0 = true;
+ else if (*f == '+' && !privileged)
+ privileged = true;
else
break;
f++;
@@ -718,6 +722,7 @@ int config_parse_exec(
nce->argv = n;
nce->path = path;
nce->ignore = ignore;
+ nce->privileged = privileged;
exec_command_append_list(e, nce);
@@ -2399,6 +2404,55 @@ int config_parse_documentation(const char *unit,
}
#ifdef HAVE_SECCOMP
+static int syscall_filter_parse_one(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ ExecContext *c,
+ bool invert,
+ const char *t,
+ bool warn) {
+ int r;
+
+ if (*t == '@') {
+ const SystemCallFilterSet *set;
+
+ for (set = syscall_filter_sets; set->set_name; set++)
+ if (streq(set->set_name, t)) {
+ const char *sys;
+
+ NULSTR_FOREACH(sys, set->value) {
+ r = syscall_filter_parse_one(unit, filename, line, c, invert, sys, false);
+ if (r < 0)
+ return r;
+ }
+ break;
+ }
+ } else {
+ int id;
+
+ id = seccomp_syscall_resolve_name(t);
+ if (id == __NR_SCMP_ERROR) {
+ if (warn)
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call, ignoring: %s", t);
+ return 0;
+ }
+
+ /* If we previously wanted to forbid a syscall and now
+ * we want to allow it, then remove it from the list
+ */
+ if (!invert == c->syscall_whitelist) {
+ r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
+ if (r == 0)
+ return 0;
+ if (r < 0)
+ return log_oom();
+ } else
+ set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
+ }
+ return 0;
+}
+
int config_parse_syscall_filter(
const char *unit,
const char *filename,
@@ -2411,13 +2465,6 @@ int config_parse_syscall_filter(
void *data,
void *userdata) {
- static const char default_syscalls[] =
- "execve\0"
- "exit\0"
- "exit_group\0"
- "rt_sigreturn\0"
- "sigreturn\0";
-
ExecContext *c = data;
Unit *u = userdata;
bool invert = false;
@@ -2451,53 +2498,26 @@ int config_parse_syscall_filter(
/* Allow everything but the ones listed */
c->syscall_whitelist = false;
else {
- const char *i;
-
/* Allow nothing but the ones listed */
c->syscall_whitelist = true;
/* Accept default syscalls if we are on a whitelist */
- NULSTR_FOREACH(i, default_syscalls) {
- int id;
-
- id = seccomp_syscall_resolve_name(i);
- if (id < 0)
- continue;
-
- r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
- if (r == 0)
- continue;
- if (r < 0)
- return log_oom();
- }
+ r = syscall_filter_parse_one(unit, filename, line, c, false, "@default", false);
+ if (r < 0)
+ return r;
}
}
FOREACH_WORD_QUOTED(word, l, rvalue, state) {
_cleanup_free_ char *t = NULL;
- int id;
t = strndup(word, l);
if (!t)
return log_oom();
- id = seccomp_syscall_resolve_name(t);
- if (id < 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse system call, ignoring: %s", t);
- continue;
- }
-
- /* If we previously wanted to forbid a syscall and now
- * we want to allow it, then remove it from the list
- */
- if (!invert == c->syscall_whitelist) {
- r = set_put(c->syscall_filter, INT_TO_PTR(id + 1));
- if (r == 0)
- continue;
- if (r < 0)
- return log_oom();
- } else
- set_remove(c->syscall_filter, INT_TO_PTR(id + 1));
+ r = syscall_filter_parse_one(unit, filename, line, c, invert, t, true);
+ if (r < 0)
+ return r;
}
if (!isempty(state))
log_syntax(unit, LOG_ERR, filename, line, 0, "Trailing garbage, ignoring.");
@@ -2757,7 +2777,7 @@ int config_parse_cpu_quota(
void *userdata) {
CGroupContext *c = data;
- double percent;
+ int r;
assert(filename);
assert(lvalue);
@@ -2768,18 +2788,13 @@ int config_parse_cpu_quota(
return 0;
}
- if (!endswith(rvalue, "%")) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "CPU quota '%s' not ending in '%%'. Ignoring.", rvalue);
+ r = parse_percent(rvalue);
+ if (r <= 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "CPU quota '%s' invalid. Ignoring.", rvalue);
return 0;
}
- if (sscanf(rvalue, "%lf%%", &percent) != 1 || percent <= 0) {
- log_syntax(unit, LOG_ERR, filename, line, 0, "CPU quota '%s' invalid. Ignoring.", rvalue);
- return 0;
- }
-
- c->cpu_quota_per_sec_usec = (usec_t) (percent * USEC_PER_SEC / 100);
-
+ c->cpu_quota_per_sec_usec = ((usec_t) r * USEC_PER_SEC) / 100U;
return 0;
}
@@ -2796,21 +2811,36 @@ int config_parse_memory_limit(
void *userdata) {
CGroupContext *c = data;
- uint64_t bytes;
+ uint64_t bytes = CGROUP_LIMIT_MAX;
int r;
- if (isempty(rvalue) || streq(rvalue, "infinity")) {
- c->memory_limit = (uint64_t) -1;
- return 0;
- }
+ if (!isempty(rvalue) && !streq(rvalue, "infinity")) {
- r = parse_size(rvalue, 1024, &bytes);
- if (r < 0 || bytes < 1) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue);
- return 0;
+ r = parse_percent(rvalue);
+ if (r < 0) {
+ r = parse_size(rvalue, 1024, &bytes);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Memory limit '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+ } else
+ bytes = physical_memory_scale(r, 100U);
+
+ if (bytes <= 0 || bytes >= UINT64_MAX) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Memory limit '%s' out of range. Ignoring.", rvalue);
+ return 0;
+ }
}
- c->memory_limit = bytes;
+ if (streq(lvalue, "MemoryLow"))
+ c->memory_low = bytes;
+ else if (streq(lvalue, "MemoryHigh"))
+ c->memory_high = bytes;
+ else if (streq(lvalue, "MemoryMax"))
+ c->memory_max = bytes;
+ else
+ c->memory_limit = bytes;
+
return 0;
}
@@ -2834,9 +2864,18 @@ int config_parse_tasks_max(
return 0;
}
- r = safe_atou64(rvalue, &u);
- if (r < 0 || u < 1) {
- log_syntax(unit, LOG_ERR, filename, line, r, "Maximum tasks value '%s' invalid. Ignoring.", rvalue);
+ r = parse_percent(rvalue);
+ if (r < 0) {
+ r = safe_atou64(rvalue, &u);
+ if (r < 0) {
+ log_syntax(unit, LOG_ERR, filename, line, r, "Maximum tasks value '%s' invalid. Ignoring.", rvalue);
+ return 0;
+ }
+ } else
+ u = system_tasks_max_scale(r, 100U);
+
+ if (u <= 0 || u >= UINT64_MAX) {
+ log_syntax(unit, LOG_ERR, filename, line, 0, "Maximum tasks value '%s' out of range. Ignoring.", rvalue);
return 0;
}
@@ -3063,7 +3102,7 @@ int config_parse_io_limit(
return 0;
}
- if (streq("max", limit)) {
+ if (streq("infinity", limit)) {
num = CGROUP_LIMIT_MAX;
} else {
r = parse_size(limit, 1000, &num);
@@ -3567,7 +3606,7 @@ int config_parse_protect_home(
assert(data);
/* Our enum shall be a superset of booleans, hence first try
- * to parse as as boolean, and then as enum */
+ * to parse as boolean, and then as enum */
k = parse_boolean(rvalue);
if (k > 0)
@@ -3610,7 +3649,7 @@ int config_parse_protect_system(
assert(data);
/* Our enum shall be a superset of booleans, hence first try
- * to parse as as boolean, and then as enum */
+ * to parse as boolean, and then as enum */
k = parse_boolean(rvalue);
if (k > 0)
@@ -3726,7 +3765,7 @@ static int merge_by_names(Unit **u, Set *names, const char *id) {
/* If the symlink name we are looking at is unit template, then
we must search for instance of this template */
- if (unit_name_is_valid(k, UNIT_NAME_TEMPLATE)) {
+ if (unit_name_is_valid(k, UNIT_NAME_TEMPLATE) && (*u)->instance) {
_cleanup_free_ char *instance = NULL;
r = unit_name_replace_instance(k, (*u)->instance, &instance);
@@ -3808,7 +3847,15 @@ static int load_from_path(Unit *u, const char *path) {
if (r >= 0)
break;
filename = mfree(filename);
- if (r != -ENOENT)
+
+ /* ENOENT means that the file is missing or is a dangling symlink.
+ * ENOTDIR means that one of paths we expect to be is a directory
+ * is not a directory, we should just ignore that.
+ * EACCES means that the directory or file permissions are wrong.
+ */
+ if (r == -EACCES)
+ log_debug_errno(r, "Cannot access \"%s\": %m", filename);
+ else if (!IN_SET(r, -ENOENT, -ENOTDIR))
return r;
/* Empty the symlink names for the next run */
diff --git a/src/grp-system/libcore/machine-id-setup.c b/src/grp-system/libcore/machine-id-setup.c
index 28722b46f0..0b65583686 100644
--- a/src/grp-system/libcore/machine-id-setup.c
+++ b/src/grp-system/libcore/machine-id-setup.c
@@ -17,11 +17,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#include <errno.h>
#include <fcntl.h>
#include <sched.h>
-#include <stdio.h>
-#include <string.h>
#include <sys/mount.h>
#include <unistd.h>
@@ -29,10 +26,7 @@
#include "basic/alloc-util.h"
#include "basic/fd-util.h"
-#include "basic/fileio.h"
#include "basic/fs-util.h"
-#include "basic/hexdecoct.h"
-#include "basic/io-util.h"
#include "basic/log.h"
#include "basic/macro.h"
#include "basic/mkdir.h"
@@ -44,104 +38,27 @@
#include "basic/umask-util.h"
#include "basic/util.h"
#include "basic/virt.h"
+#include "sd-id128/id128-util.h"
#include "machine-id-setup.h"
-static int shorten_uuid(char destination[34], const char source[36]) {
- unsigned i, j;
-
- assert(destination);
- assert(source);
-
- /* Converts a UUID into a machine ID, by lowercasing it and
- * removing dashes. Validates everything. */
-
- for (i = 0, j = 0; i < 36 && j < 32; i++) {
- int t;
-
- t = unhexchar(source[i]);
- if (t < 0)
- continue;
-
- destination[j++] = hexchar(t);
- }
-
- if (i != 36 || j != 32)
- return -EINVAL;
-
- destination[32] = '\n';
- destination[33] = 0;
- return 0;
-}
-
-static int read_machine_id(int fd, char id[34]) {
- char id_to_validate[34];
- int r;
-
- assert(fd >= 0);
- assert(id);
-
- /* Reads a machine ID from a file, validates it, and returns
- * it. The returned ID ends in a newline. */
-
- r = loop_read_exact(fd, id_to_validate, 33, false);
- if (r < 0)
- return r;
-
- if (id_to_validate[32] != '\n')
- return -EINVAL;
-
- id_to_validate[32] = 0;
-
- if (!id128_is_valid(id_to_validate))
- return -EINVAL;
-
- memcpy(id, id_to_validate, 32);
- id[32] = '\n';
- id[33] = 0;
- return 0;
-}
-
-static int write_machine_id(int fd, const char id[34]) {
- int r;
-
- assert(fd >= 0);
- assert(id);
-
- if (lseek(fd, 0, SEEK_SET) < 0)
- return -errno;
-
- r = loop_write(fd, id, 33, false);
- if (r < 0)
- return r;
-
- if (fsync(fd) < 0)
- return -errno;
-
- return 0;
-}
-
-static int generate_machine_id(char id[34], const char *root) {
- int fd, r;
- unsigned char *p;
- sd_id128_t buf;
- char *q;
+static int generate_machine_id(const char *root, sd_id128_t *ret) {
const char *dbus_machine_id;
+ _cleanup_close_ int fd = -1;
+ int r;
- assert(id);
-
- dbus_machine_id = prefix_roota(root, "/var/lib/dbus/machine-id");
+ assert(ret);
/* First, try reading the D-Bus machine id, unless it is a symlink */
+ dbus_machine_id = prefix_roota(root, "/var/lib/dbus/machine-id");
fd = open(dbus_machine_id, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
if (fd >= 0) {
- r = read_machine_id(fd, id);
- safe_close(fd);
-
- if (r >= 0) {
+ if (id128_read_fd(fd, ID128_PLAIN, ret) >= 0) {
log_info("Initializing machine ID from D-Bus machine ID.");
return 0;
}
+
+ fd = safe_close(fd);
}
if (isempty(root)) {
@@ -152,13 +69,10 @@ static int generate_machine_id(char id[34], const char *root) {
if (detect_container() > 0) {
_cleanup_free_ char *e = NULL;
- r = getenv_for_pid(1, "container_uuid", &e);
- if (r > 0) {
- r = shorten_uuid(id, e);
- if (r >= 0) {
- log_info("Initializing machine ID from container UUID.");
- return 0;
- }
+ if (getenv_for_pid(1, "container_uuid", &e) > 0 &&
+ sd_id128_from_string(e, ret) >= 0) {
+ log_info("Initializing machine ID from container UUID.");
+ return 0;
}
} else if (detect_vm() == VIRTUALIZATION_KVM) {
@@ -167,51 +81,29 @@ static int generate_machine_id(char id[34], const char *root) {
* running in qemu/kvm and a machine ID was passed in
* via -uuid on the qemu/kvm command line */
- char uuid[36];
-
- fd = open("/sys/class/dmi/id/product_uuid", O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NOFOLLOW);
- if (fd >= 0) {
- r = loop_read_exact(fd, uuid, 36, false);
- safe_close(fd);
-
- if (r >= 0) {
- r = shorten_uuid(id, uuid);
- if (r >= 0) {
- log_info("Initializing machine ID from KVM UUID.");
- return 0;
- }
- }
+ if (id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, ret) >= 0) {
+ log_info("Initializing machine ID from KVM UUID.");
+ return 0;
}
}
}
/* If that didn't work, generate a random machine id */
- r = sd_id128_randomize(&buf);
+ r = sd_id128_randomize(ret);
if (r < 0)
- return log_error_errno(r, "Failed to open /dev/urandom: %m");
-
- for (p = buf.bytes, q = id; p < buf.bytes + sizeof(buf); p++, q += 2) {
- q[0] = hexchar(*p >> 4);
- q[1] = hexchar(*p & 15);
- }
-
- id[32] = '\n';
- id[33] = 0;
+ return log_error_errno(r, "Failed to generate randomized : %m");
log_info("Initializing machine ID from random generator.");
-
return 0;
}
-int machine_id_setup(const char *root, sd_id128_t machine_id) {
+int machine_id_setup(const char *root, sd_id128_t machine_id, sd_id128_t *ret) {
const char *etc_machine_id, *run_machine_id;
_cleanup_close_ int fd = -1;
- bool writable = true;
- char id[34]; /* 32 + \n + \0 */
+ bool writable;
int r;
etc_machine_id = prefix_roota(root, "/etc/machine-id");
- run_machine_id = prefix_roota(root, "/run/machine-id");
RUN_WITH_UMASK(0000) {
/* We create this 0444, to indicate that this isn't really
@@ -219,7 +111,7 @@ int machine_id_setup(const char *root, sd_id128_t machine_id) {
* will be owned by root it doesn't matter much, but maybe
* people look. */
- mkdir_parents(etc_machine_id, 0755);
+ (void) mkdir_parents(etc_machine_id, 0755);
fd = open(etc_machine_id, O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444);
if (fd < 0) {
int old_errno = errno;
@@ -240,41 +132,41 @@ int machine_id_setup(const char *root, sd_id128_t machine_id) {
}
writable = false;
- }
+ } else
+ writable = true;
}
- /* A machine id argument overrides all other machined-ids */
- if (!sd_id128_is_null(machine_id)) {
- sd_id128_to_string(machine_id, id);
- id[32] = '\n';
- id[33] = 0;
- } else {
- if (read_machine_id(fd, id) >= 0)
- return 0;
+ /* A we got a valid machine ID argument, that's what counts */
+ if (sd_id128_is_null(machine_id)) {
- /* Hmm, so, the id currently stored is not useful, then let's
- * generate one */
+ /* Try to read any existing machine ID */
+ if (id128_read_fd(fd, ID128_PLAIN, ret) >= 0)
+ return 0;
- r = generate_machine_id(id, root);
+ /* Hmm, so, the id currently stored is not useful, then let's generate one */
+ r = generate_machine_id(root, &machine_id);
if (r < 0)
return r;
+
+ if (lseek(fd, 0, SEEK_SET) == (off_t) -1)
+ return log_error_errno(errno, "Failed to seek: %m");
}
if (writable)
- if (write_machine_id(fd, id) >= 0)
- return 0;
+ if (id128_write_fd(fd, ID128_PLAIN, machine_id, true) >= 0)
+ goto finish;
fd = safe_close(fd);
- /* Hmm, we couldn't write it? So let's write it to
- * /run/machine-id as a replacement */
+ /* Hmm, we couldn't write it? So let's write it to /run/machine-id as a replacement */
- RUN_WITH_UMASK(0022) {
- r = write_string_file(run_machine_id, id, WRITE_STRING_FILE_CREATE);
- if (r < 0) {
- (void) unlink(run_machine_id);
- return log_error_errno(r, "Cannot write %s: %m", run_machine_id);
- }
+ run_machine_id = prefix_roota(root, "/run/machine-id");
+
+ RUN_WITH_UMASK(0022)
+ r = id128_write(run_machine_id, ID128_PLAIN, machine_id, false);
+ if (r < 0) {
+ (void) unlink(run_machine_id);
+ return log_error_errno(r, "Cannot write %s: %m", run_machine_id);
}
/* And now, let's mount it over */
@@ -287,7 +179,11 @@ int machine_id_setup(const char *root, sd_id128_t machine_id) {
/* Mark the mount read-only */
if (mount(NULL, etc_machine_id, NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, NULL) < 0)
- log_warning_errno(errno, "Failed to make transient %s read-only: %m", etc_machine_id);
+ log_warning_errno(errno, "Failed to make transient %s read-only, ignoring: %m", etc_machine_id);
+
+finish:
+ if (ret)
+ *ret = machine_id;
return 0;
}
@@ -295,16 +191,20 @@ int machine_id_setup(const char *root, sd_id128_t machine_id) {
int machine_id_commit(const char *root) {
_cleanup_close_ int fd = -1, initial_mntns_fd = -1;
const char *etc_machine_id;
- char id[34]; /* 32 + \n + \0 */
+ sd_id128_t id;
int r;
+ /* Replaces a tmpfs bind mount of /etc/machine-id by a proper file, atomically. For this, the umount is removed
+ * in a mount namespace, a new file is created at the right place. Afterwards the mount is also removed in the
+ * original mount namespace, thus revealing the file that was just created. */
+
etc_machine_id = prefix_roota(root, "/etc/machine-id");
r = path_is_mount_point(etc_machine_id, 0);
if (r < 0)
return log_error_errno(r, "Failed to determine whether %s is a mount point: %m", etc_machine_id);
if (r == 0) {
- log_debug("%s is is not a mount point. Nothing to do.", etc_machine_id);
+ log_debug("%s is not a mount point. Nothing to do.", etc_machine_id);
return 0;
}
@@ -313,10 +213,6 @@ int machine_id_commit(const char *root) {
if (fd < 0)
return log_error_errno(errno, "Cannot open %s: %m", etc_machine_id);
- r = read_machine_id(fd, id);
- if (r < 0)
- return log_error_errno(r, "We didn't find a valid machine ID in %s.", etc_machine_id);
-
r = fd_is_temporary_fs(fd);
if (r < 0)
return log_error_errno(r, "Failed to determine whether %s is on a temporary file system: %m", etc_machine_id);
@@ -325,6 +221,10 @@ int machine_id_commit(const char *root) {
return -EROFS;
}
+ r = id128_read_fd(fd, ID128_PLAIN, &id);
+ if (r < 0)
+ return log_error_errno(r, "We didn't find a valid machine ID in %s.", etc_machine_id);
+
fd = safe_close(fd);
/* Store current mount namespace */
@@ -343,15 +243,9 @@ int machine_id_commit(const char *root) {
return log_error_errno(errno, "Failed to unmount transient %s file in our private namespace: %m", etc_machine_id);
/* Update a persistent version of etc_machine_id */
- fd = open(etc_machine_id, O_RDWR|O_CREAT|O_CLOEXEC|O_NOCTTY, 0444);
- if (fd < 0)
- return log_error_errno(errno, "Cannot open for writing %s. This is mandatory to get a persistent machine-id: %m", etc_machine_id);
-
- r = write_machine_id(fd, id);
+ r = id128_write(etc_machine_id, ID128_PLAIN, id, true);
if (r < 0)
- return log_error_errno(r, "Cannot write %s: %m", etc_machine_id);
-
- fd = safe_close(fd);
+ return log_error_errno(r, "Cannot write %s. This is mandatory to get a persistent machine ID: %m", etc_machine_id);
/* Return to initial namespace and proceed a lazy tmpfs unmount */
r = namespace_enter(-1, initial_mntns_fd, -1, -1, -1);
diff --git a/src/grp-system/libcore/machine-id-setup.h b/src/grp-system/libcore/machine-id-setup.h
index c5dd8d7790..88830ecc42 100644
--- a/src/grp-system/libcore/machine-id-setup.h
+++ b/src/grp-system/libcore/machine-id-setup.h
@@ -22,4 +22,4 @@
#include <systemd/sd-id128.h>
int machine_id_commit(const char *root);
-int machine_id_setup(const char *root, sd_id128_t machine_id);
+int machine_id_setup(const char *root, sd_id128_t requested, sd_id128_t *ret);
diff --git a/src/grp-system/libcore/manager.c b/src/grp-system/libcore/manager.c
index 29dbf092d7..26395bc2b3 100644
--- a/src/grp-system/libcore/manager.c
+++ b/src/grp-system/libcore/manager.c
@@ -137,23 +137,28 @@ static void draw_cylon(char buffer[], size_t buflen, unsigned width, unsigned po
if (pos > 1) {
if (pos > 2)
p = mempset(p, ' ', pos-2);
- p = stpcpy(p, ANSI_RED);
+ if (log_get_show_color())
+ p = stpcpy(p, ANSI_RED);
*p++ = '*';
}
if (pos > 0 && pos <= width) {
- p = stpcpy(p, ANSI_HIGHLIGHT_RED);
+ if (log_get_show_color())
+ p = stpcpy(p, ANSI_HIGHLIGHT_RED);
*p++ = '*';
}
- p = stpcpy(p, ANSI_NORMAL);
+ if (log_get_show_color())
+ p = stpcpy(p, ANSI_NORMAL);
if (pos < width) {
- p = stpcpy(p, ANSI_RED);
+ if (log_get_show_color())
+ p = stpcpy(p, ANSI_RED);
*p++ = '*';
if (pos < width-1)
p = mempset(p, ' ', width-1-pos);
- strcpy(p, ANSI_NORMAL);
+ if (log_get_show_color())
+ strcpy(p, ANSI_NORMAL);
}
}
@@ -566,7 +571,7 @@ int manager_new(UnitFileScope scope, bool test_run, Manager **_m) {
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);
+ m->default_tasks_max = UINT64_MAX;
#ifdef ENABLE_EFI
if (MANAGER_IS_SYSTEM(m) && detect_container() <= 0)
@@ -810,28 +815,6 @@ static int manager_setup_cgroups_agent(Manager *m) {
return 0;
}
-static int manager_setup_kdbus(Manager *m) {
- _cleanup_free_ char *p = NULL;
-
- assert(m);
-
- if (m->test_run || m->kdbus_fd >= 0)
- return 0;
- if (!is_kdbus_available())
- return -ESOCKTNOSUPPORT;
-
- m->kdbus_fd = bus_kernel_create_bus(
- MANAGER_IS_SYSTEM(m) ? "system" : "user",
- MANAGER_IS_SYSTEM(m), &p);
-
- if (m->kdbus_fd < 0)
- return log_debug_errno(m->kdbus_fd, "Failed to set up kdbus: %m");
-
- log_debug("Successfully set up kdbus on %s", p);
-
- return 0;
-}
-
static int manager_connect_bus(Manager *m, bool reexecuting) {
bool try_bus_connect;
@@ -873,6 +856,19 @@ enum {
_GC_OFFSET_MAX
};
+static void unit_gc_mark_good(Unit *u, unsigned gc_marker)
+{
+ Iterator i;
+ Unit *other;
+
+ u->gc_marker = gc_marker + GC_OFFSET_GOOD;
+
+ /* Recursively mark referenced units as GOOD as well */
+ SET_FOREACH(other, u->dependencies[UNIT_REFERENCES], i)
+ if (other->gc_marker == gc_marker + GC_OFFSET_UNSURE)
+ unit_gc_mark_good(other, gc_marker);
+}
+
static void unit_gc_sweep(Unit *u, unsigned gc_marker) {
Iterator i;
Unit *other;
@@ -882,6 +878,7 @@ static void unit_gc_sweep(Unit *u, unsigned gc_marker) {
if (u->gc_marker == gc_marker + GC_OFFSET_GOOD ||
u->gc_marker == gc_marker + GC_OFFSET_BAD ||
+ u->gc_marker == gc_marker + GC_OFFSET_UNSURE ||
u->gc_marker == gc_marker + GC_OFFSET_IN_PATH)
return;
@@ -922,7 +919,7 @@ bad:
return;
good:
- u->gc_marker = gc_marker + GC_OFFSET_GOOD;
+ unit_gc_mark_good(u, gc_marker);
}
static unsigned manager_dispatch_gc_queue(Manager *m) {
@@ -1226,7 +1223,6 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
/* We might have deserialized the kdbus control fd, but if we
* didn't, then let's create the bus now. */
- manager_setup_kdbus(m);
manager_connect_bus(m, !!serialization);
bus_track_coldplug(m, &m->subscribed, &m->deserialized_subscribed);
@@ -1611,9 +1607,9 @@ static void manager_invoke_notify_message(Manager *m, Unit *u, pid_t pid, const
}
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,
@@ -1721,16 +1717,28 @@ static int manager_dispatch_notify_fd(sd_event_source *source, int fd, uint32_t
}
static void invoke_sigchld_event(Manager *m, Unit *u, const siginfo_t *si) {
+ uint64_t iteration;
+
assert(m);
assert(u);
assert(si);
+ sd_event_get_iteration(m->event, &iteration);
+
log_unit_debug(u, "Child "PID_FMT" belongs to %s", si->si_pid, u->id);
unit_unwatch_pid(u, si->si_pid);
- if (UNIT_VTABLE(u)->sigchld_event)
- UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status);
+ if (UNIT_VTABLE(u)->sigchld_event) {
+ if (set_size(u->pids) <= 1 ||
+ iteration != u->sigchldgen ||
+ unit_main_pid(u) == si->si_pid ||
+ unit_control_pid(u) == si->si_pid) {
+ UNIT_VTABLE(u)->sigchld_event(u, si->si_pid, si->si_code, si->si_status);
+ u->sigchldgen = iteration;
+ } else
+ log_debug("%s already issued a sigchld this iteration %" PRIu64 ", skipping. Pids still being watched %d", u->id, iteration, set_size(u->pids));
+ }
}
static int manager_dispatch_sigchld(Manager *m) {
diff --git a/src/grp-system/libcore/manager.h b/src/grp-system/libcore/manager.h
index fedf39ddcd..252919c27f 100644
--- a/src/grp-system/libcore/manager.h
+++ b/src/grp-system/libcore/manager.h
@@ -27,10 +27,10 @@
#include <systemd/sd-event.h>
#include "basic/cgroup-util.h"
-#include "basic/fdset.h"
#include "basic/hashmap.h"
#include "basic/list.h"
#include "basic/ratelimit.h"
+#include "shared/fdset.h"
/* Enforce upper limit how many names we allow */
#define MANAGER_MAX_NAMES 131072 /* 128K */
diff --git a/src/grp-system/libcore/mount-setup.c b/src/grp-system/libcore/mount-setup.c
index e90f0e918a..0de1c63b3e 100644
--- a/src/grp-system/libcore/mount-setup.c
+++ b/src/grp-system/libcore/mount-setup.c
@@ -25,6 +25,7 @@
#include "basic/alloc-util.h"
#include "basic/cgroup-util.h"
+#include "basic/fs-util.h"
#include "basic/label.h"
#include "basic/log.h"
#include "basic/macro.h"
@@ -109,8 +110,6 @@ static const MountPoint mount_table[] = {
{ "efivarfs", "/sys/firmware/efi/efivars", "efivarfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
is_efi_boot, MNT_NONE },
#endif
- { "kdbusfs", "/sys/fs/kdbus", "kdbusfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV,
- is_kdbus_wanted, MNT_IN_CONTAINER },
};
/* These are API file systems that might be mounted by other software,
@@ -406,9 +405,16 @@ int mount_setup(bool loaded_policy) {
* really needs to stay for good, otherwise software that
* copied sd-daemon.c into their sources will misdetect
* systemd. */
- mkdir_label("/run/systemd", 0755);
- mkdir_label("/run/systemd/system", 0755);
- mkdir_label("/run/systemd/inaccessible", 0000);
+ (void) mkdir_label("/run/systemd", 0755);
+ (void) mkdir_label("/run/systemd/system", 0755);
+ (void) mkdir_label("/run/systemd/inaccessible", 0000);
+ /* Set up inaccessible items */
+ (void) mknod("/run/systemd/inaccessible/reg", S_IFREG | 0000, 0);
+ (void) mkdir_label("/run/systemd/inaccessible/dir", 0000);
+ (void) mknod("/run/systemd/inaccessible/chr", S_IFCHR | 0000, makedev(0, 0));
+ (void) mknod("/run/systemd/inaccessible/blk", S_IFBLK | 0000, makedev(0, 0));
+ (void) mkfifo("/run/systemd/inaccessible/fifo", 0000);
+ (void) mknod("/run/systemd/inaccessible/sock", S_IFSOCK | 0000, 0);
return 0;
}
diff --git a/src/grp-system/libcore/mount.c b/src/grp-system/libcore/mount.c
index d4af6c65f6..bc5f29692d 100644
--- a/src/grp-system/libcore/mount.c
+++ b/src/grp-system/libcore/mount.c
@@ -1707,6 +1707,7 @@ static int mount_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
/* This has just been unmounted by
* somebody else, follow the state
* change. */
+ mount->result = MOUNT_SUCCESS; /* make sure we forget any earlier umount failures */
mount_enter_dead(mount, MOUNT_SUCCESS);
break;
diff --git a/src/grp-system/libcore/namespace.c b/src/grp-system/libcore/namespace.c
index db60336a60..f76a0a7fbf 100644
--- a/src/grp-system/libcore/namespace.c
+++ b/src/grp-system/libcore/namespace.c
@@ -280,6 +280,7 @@ static int apply_mount(
const char *what;
int r;
+ struct stat target;
assert(m);
@@ -289,12 +290,21 @@ static int apply_mount(
/* First, get rid of everything that is below if there
* is anything... Then, overmount it with an
- * inaccessible directory. */
+ * inaccessible path. */
umount_recursive(m->path, 0);
- what = "/run/systemd/inaccessible";
- break;
+ if (lstat(m->path, &target) < 0) {
+ if (m->ignore && errno == ENOENT)
+ return 0;
+ return -errno;
+ }
+ what = mode_to_inaccessible_node(target.st_mode);
+ if (!what) {
+ log_debug("File type not supported for inaccessible mounts. Note that symlinks are not allowed");
+ return -ELOOP;
+ }
+ break;
case READONLY:
case READWRITE:
/* Nothing to mount here, we just later toggle the
@@ -319,12 +329,14 @@ static int apply_mount(
assert(what);
r = mount(what, m->path, NULL, MS_BIND|MS_REC, NULL);
- if (r >= 0)
+ if (r >= 0) {
log_debug("Successfully mounted %s to %s", what, m->path);
- else if (m->ignore && errno == ENOENT)
- return 0;
-
- return r;
+ return r;
+ } else {
+ if (m->ignore && errno == ENOENT)
+ return 0;
+ return log_debug_errno(errno, "Failed to mount %s to %s: %m", what, m->path);
+ }
}
static int make_read_only(BindMount *m) {
@@ -337,7 +349,8 @@ static int make_read_only(BindMount *m) {
else if (IN_SET(m->mode, READWRITE, PRIVATE_TMP, PRIVATE_VAR_TMP, PRIVATE_DEV)) {
r = bind_remount_recursive(m->path, false);
if (r == 0 && m->mode == PRIVATE_DEV) /* can be readonly but the submounts can't*/
- r = mount(NULL, m->path, NULL, MS_REMOUNT|DEV_MOUNT_OPTIONS|MS_RDONLY, NULL);
+ if (mount(NULL, m->path, NULL, MS_REMOUNT|DEV_MOUNT_OPTIONS|MS_RDONLY, NULL) < 0)
+ r = -errno;
} else
r = 0;
@@ -349,9 +362,9 @@ static int make_read_only(BindMount *m) {
int setup_namespace(
const char* root_directory,
- char** read_write_dirs,
- char** read_only_dirs,
- char** inaccessible_dirs,
+ char** read_write_paths,
+ char** read_only_paths,
+ char** inaccessible_paths,
const char* tmp_dir,
const char* var_tmp_dir,
bool private_dev,
@@ -370,9 +383,9 @@ int setup_namespace(
return -errno;
n = !!tmp_dir + !!var_tmp_dir +
- strv_length(read_write_dirs) +
- strv_length(read_only_dirs) +
- strv_length(inaccessible_dirs) +
+ strv_length(read_write_paths) +
+ strv_length(read_only_paths) +
+ strv_length(inaccessible_paths) +
private_dev +
(protect_home != PROTECT_HOME_NO ? 3 : 0) +
(protect_system != PROTECT_SYSTEM_NO ? 2 : 0) +
@@ -380,15 +393,15 @@ int setup_namespace(
if (n > 0) {
m = mounts = (BindMount *) alloca0(n * sizeof(BindMount));
- r = append_mounts(&m, read_write_dirs, READWRITE);
+ r = append_mounts(&m, read_write_paths, READWRITE);
if (r < 0)
return r;
- r = append_mounts(&m, read_only_dirs, READONLY);
+ r = append_mounts(&m, read_only_paths, READONLY);
if (r < 0)
return r;
- r = append_mounts(&m, inaccessible_dirs, INACCESSIBLE);
+ r = append_mounts(&m, inaccessible_paths, INACCESSIBLE);
if (r < 0)
return r;
@@ -631,7 +644,7 @@ int setup_netns(int netns_storage_socket[2]) {
}
fail:
- lockf(netns_storage_socket[0], F_ULOCK, 0);
+ (void) lockf(netns_storage_socket[0], F_ULOCK, 0);
return r;
}
diff --git a/src/grp-system/libcore/namespace.h b/src/grp-system/libcore/namespace.h
index 03097327dd..1ae206efd1 100644
--- a/src/grp-system/libcore/namespace.h
+++ b/src/grp-system/libcore/namespace.h
@@ -40,9 +40,9 @@ typedef enum ProtectSystem {
} ProtectSystem;
int setup_namespace(const char *chroot,
- char **read_write_dirs,
- char **read_only_dirs,
- char **inaccessible_dirs,
+ char **read_write_paths,
+ char **read_only_paths,
+ char **inaccessible_paths,
const char *tmp_dir,
const char *var_tmp_dir,
bool private_dev,
diff --git a/src/grp-system/libcore/scope.c b/src/grp-system/libcore/scope.c
index c290529e14..8998f751f5 100644
--- a/src/grp-system/libcore/scope.c
+++ b/src/grp-system/libcore/scope.c
@@ -241,7 +241,7 @@ static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) {
/* If we have a controller set let's ask the controller nicely
* to terminate the scope, instead of us going directly into
- * SIGTERM beserk mode */
+ * SIGTERM berserk mode */
if (state == SCOPE_STOP_SIGTERM)
skip_signal = bus_scope_send_request_stop(s) > 0;
@@ -249,7 +249,9 @@ static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) {
r = unit_kill_context(
UNIT(s),
&s->kill_context,
- state != SCOPE_STOP_SIGTERM ? KILL_KILL : KILL_TERMINATE,
+ state != SCOPE_STOP_SIGTERM ? KILL_KILL :
+ s->was_abandoned ? KILL_TERMINATE_AND_LOG :
+ KILL_TERMINATE,
-1, -1, false);
if (r < 0)
goto fail;
@@ -370,6 +372,7 @@ static int scope_serialize(Unit *u, FILE *f, FDSet *fds) {
assert(fds);
unit_serialize_item(u, f, "state", scope_state_to_string(s->state));
+ unit_serialize_item(u, f, "was-abandoned", yes_no(s->was_abandoned));
return 0;
}
@@ -390,6 +393,14 @@ static int scope_deserialize_item(Unit *u, const char *key, const char *value, F
else
s->deserialized_state = state;
+ } else if (streq(key, "was-abandoned")) {
+ int k;
+
+ k = parse_boolean(value);
+ if (k < 0)
+ log_unit_debug(u, "Failed to parse boolean value: %s", value);
+ else
+ s->was_abandoned = k;
} else
log_unit_debug(u, "Unknown serialization key: %s", key);
@@ -429,8 +440,9 @@ static void scope_sigchld_event(Unit *u, pid_t pid, int code, int status) {
unit_tidy_watch_pids(u, 0, 0);
unit_watch_all_pids(u);
- /* If the PID set is empty now, then let's finish this off */
- if (set_isempty(u->pids))
+ /* If the PID set is empty now, then let's finish this off
+ (On unified we use proper notifications) */
+ if (cg_unified() <= 0 && set_isempty(u->pids))
scope_notify_cgroup_empty_event(u);
}
@@ -474,6 +486,7 @@ int scope_abandon(Scope *s) {
if (!IN_SET(s->state, SCOPE_RUNNING, SCOPE_ABANDONED))
return -ESTALE;
+ s->was_abandoned = true;
s->controller = mfree(s->controller);
/* The client is no longer watching the remaining processes,
diff --git a/src/grp-system/libcore/scope.h b/src/grp-system/libcore/scope.h
index f0cb3bd3e2..eaf8e8b447 100644
--- a/src/grp-system/libcore/scope.h
+++ b/src/grp-system/libcore/scope.h
@@ -21,6 +21,7 @@
typedef struct Scope Scope;
+#include "cgroup.h"
#include "kill.h"
#include "unit.h"
@@ -44,6 +45,7 @@ struct Scope {
usec_t timeout_stop_usec;
char *controller;
+ bool was_abandoned;
sd_event_source *timer_event_source;
};
diff --git a/src/grp-system/libcore/selinux-access.c b/src/grp-system/libcore/selinux-access.c
index ce2ef2db1c..f6dbfa64b7 100644
--- a/src/grp-system/libcore/selinux-access.c
+++ b/src/grp-system/libcore/selinux-access.c
@@ -192,7 +192,7 @@ int mac_selinux_generic_access_check(
const char *tclass = NULL, *scon = NULL;
struct audit_info audit_info = {};
_cleanup_free_ char *cl = NULL;
- security_context_t fcon = NULL;
+ char *fcon = NULL;
char **cmdline = NULL;
int r = 0;
diff --git a/src/grp-system/libcore/selinux-setup.c b/src/grp-system/libcore/selinux-setup.c
index 314d8edbaa..08c61af146 100644
--- a/src/grp-system/libcore/selinux-setup.c
+++ b/src/grp-system/libcore/selinux-setup.c
@@ -45,7 +45,7 @@ int mac_selinux_setup(bool *loaded_policy) {
#ifdef HAVE_SELINUX
int enforce = 0;
usec_t before_load, after_load;
- security_context_t con;
+ char *con;
int r;
union selinux_callback cb;
bool initialized = false;
diff --git a/src/grp-system/libcore/service.c b/src/grp-system/libcore/service.c
index 9b7f7bd68c..43d195bbba 100644
--- a/src/grp-system/libcore/service.c
+++ b/src/grp-system/libcore/service.c
@@ -201,16 +201,27 @@ static void service_stop_watchdog(Service *s) {
s->watchdog_timestamp = DUAL_TIMESTAMP_NULL;
}
+static usec_t service_get_watchdog_usec(Service *s) {
+ assert(s);
+
+ if (s->watchdog_override_enable)
+ return s->watchdog_override_usec;
+ else
+ return s->watchdog_usec;
+}
+
static void service_start_watchdog(Service *s) {
int r;
+ usec_t watchdog_usec;
assert(s);
- if (s->watchdog_usec <= 0)
+ watchdog_usec = service_get_watchdog_usec(s);
+ if (watchdog_usec == 0 || watchdog_usec == USEC_INFINITY)
return;
if (s->watchdog_event_source) {
- r = sd_event_source_set_time(s->watchdog_event_source, usec_add(s->watchdog_timestamp.monotonic, s->watchdog_usec));
+ r = sd_event_source_set_time(s->watchdog_event_source, usec_add(s->watchdog_timestamp.monotonic, watchdog_usec));
if (r < 0) {
log_unit_warning_errno(UNIT(s), r, "Failed to reset watchdog timer: %m");
return;
@@ -222,7 +233,7 @@ static void service_start_watchdog(Service *s) {
UNIT(s)->manager->event,
&s->watchdog_event_source,
CLOCK_MONOTONIC,
- usec_add(s->watchdog_timestamp.monotonic, s->watchdog_usec), 0,
+ usec_add(s->watchdog_timestamp.monotonic, watchdog_usec), 0,
service_dispatch_watchdog, s);
if (r < 0) {
log_unit_warning_errno(UNIT(s), r, "Failed to add watchdog timer: %m");
@@ -247,6 +258,17 @@ static void service_reset_watchdog(Service *s) {
service_start_watchdog(s);
}
+static void service_reset_watchdog_timeout(Service *s, usec_t watchdog_override_usec) {
+ assert(s);
+
+ s->watchdog_override_enable = true;
+ s->watchdog_override_usec = watchdog_override_usec;
+ service_reset_watchdog(s);
+
+ log_unit_debug(UNIT(s), "watchdog_usec="USEC_FMT, s->watchdog_usec);
+ log_unit_debug(UNIT(s), "watchdog_override_usec="USEC_FMT, s->watchdog_override_usec);
+}
+
static void service_fd_store_unlink(ServiceFDStore *fs) {
if (!fs)
@@ -575,20 +597,9 @@ static int service_setup_bus_name(Service *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");
- }
+ 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);
@@ -1664,7 +1675,7 @@ static void service_kill_control_processes(Service *s) {
return;
p = strjoina(UNIT(s)->cgroup_path, "/control");
- cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, p, SIGKILL, true, true, true, NULL);
+ cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, p, SIGKILL, CGROUP_SIGCONT|CGROUP_IGNORE_SELF|CGROUP_REMOVE, NULL, NULL, NULL);
}
static void service_enter_start(Service *s) {
@@ -2004,6 +2015,9 @@ static int service_start(Unit *u) {
s->notify_state = NOTIFY_UNKNOWN;
+ s->watchdog_override_enable = false;
+ s->watchdog_override_usec = 0;
+
service_enter_start_pre(s);
return 1;
}
@@ -2135,6 +2149,9 @@ static int service_serialize(Unit *u, FILE *f, FDSet *fds) {
unit_serialize_item(u, f, "forbid-restart", yes_no(s->forbid_restart));
+ if (s->watchdog_override_enable)
+ unit_serialize_item_format(u, f, "watchdog-override-usec", USEC_FMT, s->watchdog_override_usec);
+
return 0;
}
@@ -2329,6 +2346,14 @@ static int service_deserialize_item(Unit *u, const char *key, const char *value,
s->stderr_fd = fdset_remove(fds, fd);
s->exec_context.stdio_as_fds = true;
}
+ } else if (streq(key, "watchdog-override-usec")) {
+ usec_t watchdog_override_usec;
+ if (timestamp_deserialize(value, &watchdog_override_usec) < 0)
+ log_unit_debug(u, "Failed to parse watchdog_override_usec value: %s", value);
+ else {
+ s->watchdog_override_enable = true;
+ s->watchdog_override_usec = watchdog_override_usec;
+ }
} else
log_unit_debug(u, "Unknown serialization key: %s", key);
@@ -2801,8 +2826,9 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
unit_tidy_watch_pids(u, s->main_pid, s->control_pid);
unit_watch_all_pids(u);
- /* If the PID set is empty now, then let's finish this off */
- if (set_isempty(u->pids))
+ /* If the PID set is empty now, then let's finish this off
+ (On unified we use proper notifications) */
+ if (cg_unified() <= 0 && set_isempty(u->pids))
service_notify_cgroup_empty_event(u);
}
@@ -2906,12 +2932,15 @@ static int service_dispatch_timer(sd_event_source *source, usec_t usec, void *us
static int service_dispatch_watchdog(sd_event_source *source, usec_t usec, void *userdata) {
Service *s = SERVICE(userdata);
char t[FORMAT_TIMESPAN_MAX];
+ usec_t watchdog_usec;
assert(s);
assert(source == s->watchdog_event_source);
+ watchdog_usec = service_get_watchdog_usec(s);
+
log_unit_error(UNIT(s), "Watchdog timeout (limit %s)!",
- format_timespan(t, sizeof(t), s->watchdog_usec, 1));
+ format_timespan(t, sizeof(t), watchdog_usec, 1));
service_enter_signal(s, SERVICE_STOP_SIGABRT, SERVICE_FAILURE_WATCHDOG);
@@ -3048,6 +3077,15 @@ static void service_notify_message(Unit *u, pid_t pid, char **tags, FDSet *fds)
service_add_fd_store_set(s, fds, name);
}
+ e = strv_find_startswith(tags, "WATCHDOG_USEC=");
+ if (e) {
+ usec_t watchdog_override_usec;
+ if (safe_atou64(e, &watchdog_override_usec) < 0)
+ log_unit_warning(u, "Failed to parse WATCHDOG_USEC=%s", e);
+ else
+ service_reset_watchdog_timeout(s, watchdog_override_usec);
+ }
+
/* Notify clients about changed status or main pid */
if (notify_dbus)
unit_add_to_dbus_queue(u);
diff --git a/src/grp-system/libcore/service.h b/src/grp-system/libcore/service.h
index aa7d1de8b6..4dcf5ecf78 100644
--- a/src/grp-system/libcore/service.h
+++ b/src/grp-system/libcore/service.h
@@ -122,6 +122,8 @@ struct Service {
dual_timestamp watchdog_timestamp;
usec_t watchdog_usec;
+ usec_t watchdog_override_usec;
+ bool watchdog_override_enable;
sd_event_source *watchdog_event_source;
ExecCommand* exec_command[_SERVICE_EXEC_COMMAND_MAX];
diff --git a/src/grp-system/libcore/socket.c b/src/grp-system/libcore/socket.c
index 051cbdab8b..3e0b3e2e49 100644
--- a/src/grp-system/libcore/socket.c
+++ b/src/grp-system/libcore/socket.c
@@ -732,16 +732,16 @@ static int instance_from_socket(int fd, unsigned nr, char **instance) {
case AF_INET: {
uint32_t
- a = ntohl(local.in.sin_addr.s_addr),
- b = ntohl(remote.in.sin_addr.s_addr);
+ a = be32toh(local.in.sin_addr.s_addr),
+ b = be32toh(remote.in.sin_addr.s_addr);
if (asprintf(&r,
"%u-%u.%u.%u.%u:%u-%u.%u.%u.%u:%u",
nr,
a >> 24, (a >> 16) & 0xFF, (a >> 8) & 0xFF, a & 0xFF,
- ntohs(local.in.sin_port),
+ be16toh(local.in.sin_port),
b >> 24, (b >> 16) & 0xFF, (b >> 8) & 0xFF, b & 0xFF,
- ntohs(remote.in.sin_port)) < 0)
+ be16toh(remote.in.sin_port)) < 0)
return -ENOMEM;
break;
@@ -762,9 +762,9 @@ static int instance_from_socket(int fd, unsigned nr, char **instance) {
"%u-%u.%u.%u.%u:%u-%u.%u.%u.%u:%u",
nr,
a[0], a[1], a[2], a[3],
- ntohs(local.in6.sin6_port),
+ be16toh(local.in6.sin6_port),
b[0], b[1], b[2], b[3],
- ntohs(remote.in6.sin6_port)) < 0)
+ be16toh(remote.in6.sin6_port)) < 0)
return -ENOMEM;
} else {
char a[INET6_ADDRSTRLEN], b[INET6_ADDRSTRLEN];
@@ -773,9 +773,9 @@ static int instance_from_socket(int fd, unsigned nr, char **instance) {
"%u-%s:%u-%s:%u",
nr,
inet_ntop(AF_INET6, &local.in6.sin6_addr, a, sizeof(a)),
- ntohs(local.in6.sin6_port),
+ be16toh(local.in6.sin6_port),
inet_ntop(AF_INET6, &remote.in6.sin6_addr, b, sizeof(b)),
- ntohs(remote.in6.sin6_port)) < 0)
+ be16toh(remote.in6.sin6_port)) < 0)
return -ENOMEM;
}
diff --git a/src/grp-system/libcore/transaction.c b/src/grp-system/libcore/transaction.c
index d19e19f978..aa57eee556 100644
--- a/src/grp-system/libcore/transaction.c
+++ b/src/grp-system/libcore/transaction.c
@@ -374,7 +374,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
delete = NULL;
for (k = from; k; k = ((k->generation == generation && k->marker != k) ? k->marker : NULL)) {
- /* logging for j not k here here to provide consistent narrative */
+ /* logging for j not k here to provide consistent narrative */
log_unit_warning(j->unit,
"Found dependency on %s/%s",
k->unit->id, job_type_to_string(k->type));
@@ -393,7 +393,7 @@ static int transaction_verify_order_one(Transaction *tr, Job *j, Job *from, unsi
if (delete) {
const char *status;
- /* logging for j not k here here to provide consistent narrative */
+ /* logging for j not k here to provide consistent narrative */
log_unit_warning(j->unit,
"Breaking ordering cycle by deleting job %s/%s",
delete->unit->id, job_type_to_string(delete->type));
@@ -592,6 +592,9 @@ static int transaction_apply(Transaction *tr, Manager *m, JobMode mode) {
HASHMAP_FOREACH(j, m->jobs, i) {
assert(j->installed);
+ if (j->unit->ignore_on_isolate)
+ continue;
+
if (hashmap_get(tr->jobs, j->unit))
continue;
diff --git a/src/grp-system/libcore/unit.c b/src/grp-system/libcore/unit.c
index f539c3971d..aff4dbd2ca 100644
--- a/src/grp-system/libcore/unit.c
+++ b/src/grp-system/libcore/unit.c
@@ -101,6 +101,7 @@ Unit *unit_new(Manager *m, size_t size) {
u->on_failure_job_mode = JOB_REPLACE;
u->cgroup_inotify_wd = -1;
u->job_timeout = USEC_INFINITY;
+ u->sigchldgen = 0;
RATELIMIT_INIT(u->start_limit, m->default_start_limit_interval, m->default_start_limit_burst);
RATELIMIT_INIT(u->auto_stop_ratelimit, 10 * USEC_PER_SEC, 16);
@@ -1683,7 +1684,7 @@ static void unit_check_unneeded(Unit *u) {
if (unit_active_or_pending(other))
return;
- /* If stopping a unit fails continously we might enter a stop
+ /* If stopping a unit fails continuously we might enter a stop
* loop here, hence stop acting on the service being
* unnecessary after a while. */
if (!ratelimit_test(&u->auto_stop_ratelimit)) {
@@ -1728,7 +1729,7 @@ static void unit_check_binds_to(Unit *u) {
if (!stop)
return;
- /* If stopping a unit fails continously we might enter a stop
+ /* If stopping a unit fails continuously we might enter a stop
* loop here, hence stop acting on the service being
* unnecessary after a while. */
if (!ratelimit_test(&u->auto_stop_ratelimit)) {
@@ -3144,7 +3145,7 @@ int unit_kill_common(
if (!pid_set)
return -ENOMEM;
- q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, false, false, false, pid_set);
+ q = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, signo, 0, pid_set, NULL, NULL);
if (q < 0 && q != -EAGAIN && q != -ESRCH && q != -ENOENT)
r = q;
else
@@ -3356,7 +3357,7 @@ static const char* unit_drop_in_dir(Unit *u, UnitSetPropertiesMode mode) {
int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, const char *data) {
_cleanup_free_ char *p = NULL, *q = NULL;
- const char *dir, *prefixed;
+ const char *dir, *wrapped;
int r;
assert(u);
@@ -3365,6 +3366,7 @@ int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, co
/* When this is a transient unit file in creation, then let's not create a new drop-in but instead
* write to the transient unit file. */
fputs(data, u->transient_file);
+ fputc('\n', u->transient_file);
return 0;
}
@@ -3375,15 +3377,17 @@ int unit_write_drop_in(Unit *u, UnitSetPropertiesMode mode, const char *name, co
if (!dir)
return -EINVAL;
- prefixed = strjoina("# This is a drop-in unit file extension, created via \"systemctl set-property\" or an equivalent operation. Do not edit.\n",
- data);
+ wrapped = strjoina("# This is a drop-in unit file extension, created via \"systemctl set-property\"\n"
+ "# or an equivalent operation. Do not edit.\n",
+ data,
+ "\n");
r = drop_in_file(dir, u->id, 50, name, &p, &q);
if (r < 0)
return r;
(void) mkdir_p(p, 0755);
- r = write_string_file_atomic_label(q, prefixed);
+ r = write_string_file_atomic_label(q, wrapped);
if (r < 0)
return r;
@@ -3502,7 +3506,6 @@ int unit_make_transient(Unit *u) {
unit_add_to_dbus_queue(u);
unit_add_to_gc_queue(u);
- unit_add_to_load_queue(u);
fputs("# This is a transient unit file, created programmatically via the systemd API. Do not edit.\n",
u->transient_file);
@@ -3510,6 +3513,43 @@ int unit_make_transient(Unit *u) {
return 0;
}
+static void log_kill(pid_t pid, int sig, void *userdata) {
+ _cleanup_free_ char *comm = NULL;
+
+ (void) get_process_comm(pid, &comm);
+
+ /* Don't log about processes marked with brackets, under the assumption that these are temporary processes
+ only, like for example systemd's own PAM stub process. */
+ if (comm && comm[0] == '(')
+ return;
+
+ log_unit_notice(userdata,
+ "Killing process " PID_FMT " (%s) with signal SIG%s.",
+ pid,
+ strna(comm),
+ signal_to_string(sig));
+}
+
+static int operation_to_signal(KillContext *c, KillOperation k) {
+ assert(c);
+
+ switch (k) {
+
+ case KILL_TERMINATE:
+ case KILL_TERMINATE_AND_LOG:
+ return c->kill_signal;
+
+ case KILL_KILL:
+ return SIGKILL;
+
+ case KILL_ABORT:
+ return SIGABRT;
+
+ default:
+ assert_not_reached("KillOperation unknown");
+ }
+}
+
int unit_kill_context(
Unit *u,
KillContext *c,
@@ -3518,58 +3558,63 @@ int unit_kill_context(
pid_t control_pid,
bool main_pid_alien) {
- bool wait_for_exit = false;
+ bool wait_for_exit = false, send_sighup;
+ cg_kill_log_func_t log_func;
int sig, r;
assert(u);
assert(c);
+ /* Kill the processes belonging to this unit, in preparation for shutting the unit down. Returns > 0 if we
+ * killed something worth waiting for, 0 otherwise. */
+
if (c->kill_mode == KILL_NONE)
return 0;
- switch (k) {
- case KILL_KILL:
- sig = SIGKILL;
- break;
- case KILL_ABORT:
- sig = SIGABRT;
- break;
- case KILL_TERMINATE:
- sig = c->kill_signal;
- break;
- default:
- assert_not_reached("KillOperation unknown");
- }
+ sig = operation_to_signal(c, k);
+
+ send_sighup =
+ c->send_sighup &&
+ IN_SET(k, KILL_TERMINATE, KILL_TERMINATE_AND_LOG) &&
+ sig != SIGHUP;
+
+ log_func =
+ k != KILL_TERMINATE ||
+ IN_SET(sig, SIGKILL, SIGABRT) ? log_kill : NULL;
if (main_pid > 0) {
- r = kill_and_sigcont(main_pid, sig);
+ if (log_func)
+ log_func(main_pid, sig, u);
+ r = kill_and_sigcont(main_pid, sig);
if (r < 0 && r != -ESRCH) {
_cleanup_free_ char *comm = NULL;
- get_process_comm(main_pid, &comm);
+ (void) get_process_comm(main_pid, &comm);
log_unit_warning_errno(u, r, "Failed to kill main process " PID_FMT " (%s), ignoring: %m", main_pid, strna(comm));
} else {
if (!main_pid_alien)
wait_for_exit = true;
- if (c->send_sighup && k == KILL_TERMINATE)
+ if (r != -ESRCH && send_sighup)
(void) kill(main_pid, SIGHUP);
}
}
if (control_pid > 0) {
- r = kill_and_sigcont(control_pid, sig);
+ if (log_func)
+ log_func(control_pid, sig, u);
+ r = kill_and_sigcont(control_pid, sig);
if (r < 0 && r != -ESRCH) {
_cleanup_free_ char *comm = NULL;
- get_process_comm(control_pid, &comm);
+ (void) get_process_comm(control_pid, &comm);
log_unit_warning_errno(u, r, "Failed to kill control process " PID_FMT " (%s), ignoring: %m", control_pid, strna(comm));
} else {
wait_for_exit = true;
- if (c->send_sighup && k == KILL_TERMINATE)
+ if (r != -ESRCH && send_sighup)
(void) kill(control_pid, SIGHUP);
}
}
@@ -3583,7 +3628,11 @@ int unit_kill_context(
if (!pid_set)
return -ENOMEM;
- r = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, sig, true, k != KILL_TERMINATE, false, pid_set);
+ r = cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path,
+ sig,
+ CGROUP_SIGCONT|CGROUP_IGNORE_SELF,
+ pid_set,
+ log_func, u);
if (r < 0) {
if (r != -EAGAIN && r != -ESRCH && r != -ENOENT)
log_unit_warning_errno(u, r, "Failed to kill control group %s, ignoring: %m", u->cgroup_path);
@@ -3608,14 +3657,18 @@ int unit_kill_context(
(detect_container() == 0 && !unit_cgroup_delegate(u)))
wait_for_exit = true;
- if (c->send_sighup && k != KILL_KILL) {
+ if (send_sighup) {
set_free(pid_set);
pid_set = unit_pid_set(main_pid, control_pid);
if (!pid_set)
return -ENOMEM;
- cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path, SIGHUP, false, true, false, pid_set);
+ cg_kill_recursive(SYSTEMD_CGROUP_CONTROLLER, u->cgroup_path,
+ SIGHUP,
+ CGROUP_IGNORE_SELF,
+ pid_set,
+ NULL, NULL);
}
}
}
@@ -3788,7 +3841,7 @@ bool unit_is_pristine(Unit *u) {
/* Check if the unit already exists or is already around,
* in a number of different ways. Note that to cater for unit
* types such as slice, we are generally fine with units that
- * are marked UNIT_LOADED even even though nothing was
+ * are marked UNIT_LOADED even though nothing was
* actually loaded, as those unit types don't require a file
* on disk to validly load. */
diff --git a/src/grp-system/libcore/unit.h b/src/grp-system/libcore/unit.h
index 72ceed1fef..3e25bfd32a 100644
--- a/src/grp-system/libcore/unit.h
+++ b/src/grp-system/libcore/unit.h
@@ -37,6 +37,7 @@ typedef struct UnitVTable UnitVTable;
typedef enum KillOperation {
KILL_TERMINATE,
+ KILL_TERMINATE_AND_LOG,
KILL_KILL,
KILL_ABORT,
_KILL_OPERATION_MAX,
@@ -163,6 +164,9 @@ struct Unit {
* process SIGCHLD for */
Set *pids;
+ /* Used in sigchld event invocation to avoid repeat events being invoked */
+ uint64_t sigchldgen;
+
/* Used during GC sweeps */
unsigned gc_marker;
diff --git a/src/grp-system/systemctl/Makefile b/src/grp-system/systemctl/Makefile
index 114e58cb27..afc8ea62cd 100644
--- a/src/grp-system/systemctl/Makefile
+++ b/src/grp-system/systemctl/Makefile
@@ -28,7 +28,7 @@ systemctl_SOURCES = \
src/systemctl/systemctl.c
systemctl_LDADD = \
- libshared.la
+ libsystemd-shared.la
files.out.all += systemctl.completion.bash
files.out.all += systemctl.completion.zsh
diff --git a/src/grp-system/systemctl/systemctl.c b/src/grp-system/systemctl/systemctl.c
index 63818d07b8..0f115db14c 100644
--- a/src/grp-system/systemctl/systemctl.c
+++ b/src/grp-system/systemctl/systemctl.c
@@ -58,6 +58,7 @@
#include "basic/process-util.h"
#include "basic/rlimit-util.h"
#include "basic/set.h"
+#include "basic/sigbus.h"
#include "basic/signal-util.h"
#include "basic/socket-util.h"
#include "basic/special.h"
@@ -86,6 +87,25 @@
#include "shared/spawn-polkit-agent.h"
#include "shared/utmp-wtmp.h"
+/* The init script exit status codes
+ 0 program is running or service is OK
+ 1 program is dead and /var/run pid file exists
+ 2 program is dead and /var/lock lock file exists
+ 3 program is not running
+ 4 program or service status is unknown
+ 5-99 reserved for future LSB use
+ 100-149 reserved for distribution use
+ 150-199 reserved for application use
+ 200-254 reserved
+*/
+enum {
+ EXIT_PROGRAM_RUNNING_OR_SERVICE_OK = 0,
+ EXIT_PROGRAM_DEAD_AND_PID_EXISTS = 1,
+ EXIT_PROGRAM_DEAD_AND_LOCK_FILE_EXISTS = 2,
+ EXIT_PROGRAM_NOT_RUNNING = 3,
+ EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN = 4,
+};
+
static char **arg_types = NULL;
static char **arg_states = NULL;
static char **arg_properties = NULL;
@@ -155,6 +175,7 @@ static bool arg_firmware_setup = false;
static bool arg_now = false;
static int daemon_reload(int argc, char *argv[], void* userdata);
+static int trivial_method(int argc, char *argv[], void *userdata);
static int halt_now(enum action a);
static int get_state_one_unit(sd_bus *bus, const char *name, UnitActiveState *active_state);
@@ -204,6 +225,21 @@ static void release_busses(void) {
busses[w] = sd_bus_flush_close_unref(busses[w]);
}
+static int map_string_no_copy(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
+ char *s;
+ const char **p = userdata;
+ int r;
+
+ r = sd_bus_message_read_basic(m, SD_BUS_TYPE_STRING, &s);
+ if (r < 0)
+ return r;
+
+ if (!isempty(s))
+ *p = s;
+
+ return 0;
+}
+
static void ask_password_agent_open_if_enabled(void) {
/* Open the password agent as a child process if necessary */
@@ -568,7 +604,8 @@ static int get_unit_list(
return bus_log_create_error(r);
r = sd_bus_call(bus, m, 0, &error, &reply);
- if (r < 0 && sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD)) {
+ if (r < 0 && (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_METHOD) ||
+ sd_bus_error_has_name(&error, SD_BUS_ERROR_ACCESS_DENIED))) {
/* Fallback to legacy ListUnitsFiltered method */
fallback = true;
log_debug_errno(r, "Failed to list units: %s Falling back to ListUnitsFiltered method.", bus_error_message(&error, r));
@@ -714,12 +751,12 @@ static int list_units(int argc, char *argv[], void *userdata) {
sd_bus *bus;
int r;
- pager_open(arg_no_pager, false);
-
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
return r;
+ pager_open(arg_no_pager, false);
+
r = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
if (r < 0)
return r;
@@ -926,12 +963,12 @@ static int list_sockets(int argc, char *argv[], void *userdata) {
int r = 0, n;
sd_bus *bus;
- pager_open(arg_no_pager, false);
-
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
return r;
+ pager_open(arg_no_pager, false);
+
n = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
if (n < 0)
return n;
@@ -1233,12 +1270,12 @@ static int list_timers(int argc, char *argv[], void *userdata) {
sd_bus *bus;
int r = 0;
- pager_open(arg_no_pager, false);
-
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
return r;
+ pager_open(arg_no_pager, false);
+
n = get_unit_list_recursive(bus, strv_skip(argv, 1), &unit_infos, &replies, &machines);
if (n < 0)
return n;
@@ -1404,8 +1441,6 @@ static int list_unit_files(int argc, char *argv[], void *userdata) {
int r;
bool fallback = false;
- pager_open(arg_no_pager, false);
-
if (install_client_side()) {
Hashmap *h;
UnitFileList *u;
@@ -1520,6 +1555,8 @@ static int list_unit_files(int argc, char *argv[], void *userdata) {
return bus_log_parse_error(r);
}
+ pager_open(arg_no_pager, false);
+
qsort_safe(units, c, sizeof(UnitFileList), compare_unit_file_list);
output_unit_file_list(units, c);
@@ -1768,12 +1805,12 @@ static int list_dependencies(int argc, char *argv[], void *userdata) {
} else
u = SPECIAL_DEFAULT_TARGET;
- pager_open(arg_no_pager, false);
-
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
return r;
+ pager_open(arg_no_pager, false);
+
puts(u);
return list_dependencies_one(bus, u, 0, &units, 0);
@@ -1799,12 +1836,12 @@ static const struct bus_properties_map machine_info_property_map[] = {
};
static void machine_info_clear(struct machine_info *info) {
- if (info) {
- free(info->name);
- free(info->state);
- free(info->control_group);
- zero(*info);
- }
+ assert(info);
+
+ free(info->name);
+ free(info->state);
+ free(info->control_group);
+ zero(*info);
}
static void free_machines_list(struct machine_info *machine_infos, int n) {
@@ -1999,8 +2036,6 @@ static int list_machines(int argc, char *argv[], void *userdata) {
return -EPERM;
}
- pager_open(arg_no_pager, false);
-
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
return r;
@@ -2009,6 +2044,8 @@ static int list_machines(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
+ pager_open(arg_no_pager, false);
+
qsort_safe(machine_infos, r, sizeof(struct machine_info), compare_machine_info);
output_machines_list(machine_infos, r);
free_machines_list(machine_infos, r);
@@ -2212,8 +2249,6 @@ static int list_jobs(int argc, char *argv[], void *userdata) {
int r;
bool skipped = false;
- pager_open(arg_no_pager, false);
-
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
return r;
@@ -2254,6 +2289,8 @@ static int list_jobs(int argc, char *argv[], void *userdata) {
if (r < 0)
return bus_log_parse_error(r);
+ pager_open(arg_no_pager, false);
+
output_jobs_list(jobs, c, skipped);
return 0;
}
@@ -2264,14 +2301,14 @@ static int cancel_job(int argc, char *argv[], void *userdata) {
int r = 0;
if (argc <= 1)
- return daemon_reload(argc, argv, userdata);
-
- polkit_agent_open_if_enabled();
+ return trivial_method(argc, argv, userdata);
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
return r;
+ polkit_agent_open_if_enabled();
+
STRV_FOREACH(name, strv_skip(argv, 1)) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
uint32_t id;
@@ -2478,7 +2515,7 @@ static int unit_find_paths(
r = 1;
}
- if (r == 0)
+ if (r == 0 && !arg_force)
log_error("No files found for %s.", unit_name);
return r;
@@ -2674,10 +2711,9 @@ static int start_unit_one(
if (r < 0) {
const char *verb;
- if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
- /* There's always a fallback possible for
- * legacy actions. */
- return -EADDRNOTAVAIL;
+ /* There's always a fallback possible for legacy actions. */
+ if (arg_action != ACTION_SYSTEMCTL)
+ return r;
verb = method_to_verb(method);
@@ -2808,13 +2844,13 @@ static int start_unit(int argc, char *argv[], void *userdata) {
char **name;
int r = 0;
- ask_password_agent_open_if_enabled();
- polkit_agent_open_if_enabled();
-
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
return r;
+ ask_password_agent_open_if_enabled();
+ polkit_agent_open_if_enabled();
+
if (arg_action == ACTION_SYSTEMCTL) {
enum action action;
@@ -2934,9 +2970,6 @@ static int logind_reboot(enum action a) {
sd_bus *bus;
int r;
- polkit_agent_open_if_enabled();
- (void) logind_set_wall_message();
-
r = acquire_bus(BUS_FULL, &bus);
if (r < 0)
return r;
@@ -2972,6 +3005,9 @@ static int logind_reboot(enum action a) {
return -EINVAL;
}
+ polkit_agent_open_if_enabled();
+ (void) logind_set_wall_message();
+
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
@@ -3013,6 +3049,9 @@ static int logind_check_inhibitors(enum action a) {
if (!on_tty())
return 0;
+ if (arg_transport != BUS_TRANSPORT_LOCAL)
+ return 0;
+
r = acquire_bus(BUS_FULL, &bus);
if (r < 0)
return r;
@@ -3233,7 +3272,7 @@ static int start_special(int argc, char *argv[], void *userdata) {
ACTION_REBOOT,
ACTION_KEXEC,
ACTION_EXIT))
- return daemon_reload(argc, argv, userdata);
+ return trivial_method(argc, argv, userdata);
/* First try logind, to allow authentication with polkit */
if (IN_SET(a,
@@ -3255,6 +3294,18 @@ static int start_special(int argc, char *argv[], void *userdata) {
return start_unit(argc, argv, userdata);
}
+static int start_system_special(int argc, char *argv[], void *userdata) {
+ /* Like start_special above, but raises an error when running in user mode */
+
+ if (arg_scope != UNIT_FILE_SYSTEM) {
+ log_error("Bad action for %s mode.",
+ arg_scope == UNIT_FILE_GLOBAL ? "--global" : "--user");
+ return -EINVAL;
+ }
+
+ return start_special(argc, argv, userdata);
+}
+
static int check_unit_generic(int code, const UnitActiveState good_states[], int nb_states, char **args) {
_cleanup_strv_free_ char **names = NULL;
UnitActiveState active_state;
@@ -3292,12 +3343,12 @@ static int check_unit_generic(int code, const UnitActiveState good_states[], int
static int check_unit_active(int argc, char *argv[], void *userdata) {
const UnitActiveState states[] = { UNIT_ACTIVE, UNIT_RELOADING };
/* According to LSB: 3, "program is not running" */
- return check_unit_generic(3, states, ELEMENTSOF(states), strv_skip(argv, 1));
+ return check_unit_generic(EXIT_PROGRAM_NOT_RUNNING, states, ELEMENTSOF(states), strv_skip(argv, 1));
}
static int check_unit_failed(int argc, char *argv[], void *userdata) {
const UnitActiveState states[] = { UNIT_FAILED };
- return check_unit_generic(1, states, ELEMENTSOF(states), strv_skip(argv, 1));
+ return check_unit_generic(EXIT_PROGRAM_DEAD_AND_PID_EXISTS, states, ELEMENTSOF(states), strv_skip(argv, 1));
}
static int kill_unit(int argc, char *argv[], void *userdata) {
@@ -3306,12 +3357,12 @@ static int kill_unit(int argc, char *argv[], void *userdata) {
sd_bus *bus;
int r, q;
- polkit_agent_open_if_enabled();
-
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
return r;
+ polkit_agent_open_if_enabled();
+
if (!arg_kill_who)
arg_kill_who = "all";
@@ -3423,6 +3474,27 @@ static int exec_status_info_deserialize(sd_bus_message *m, ExecStatusInfo *i) {
return 1;
}
+typedef struct UnitCondition {
+ char *name;
+ char *param;
+ bool trigger;
+ bool negate;
+ int tristate;
+
+ LIST_FIELDS(struct UnitCondition, conditions);
+} UnitCondition;
+
+static void unit_condition_free(UnitCondition *c) {
+ if (!c)
+ return;
+
+ free(c->name);
+ free(c->param);
+ free(c);
+}
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(UnitCondition*, unit_condition_free);
+
typedef struct UnitStatusInfo {
const char *id;
const char *load_state;
@@ -3469,10 +3541,7 @@ typedef struct UnitStatusInfo {
usec_t condition_timestamp;
bool condition_result;
- bool failed_condition_trigger;
- bool failed_condition_negate;
- const char *failed_condition;
- const char *failed_condition_parameter;
+ LIST_HEAD(UnitCondition, conditions);
usec_t assert_timestamp;
bool assert_result;
@@ -3500,6 +3569,9 @@ typedef struct UnitStatusInfo {
/* CGroup */
uint64_t memory_current;
+ uint64_t memory_low;
+ uint64_t memory_high;
+ uint64_t memory_max;
uint64_t memory_limit;
uint64_t cpu_usage_nsec;
uint64_t tasks_current;
@@ -3508,6 +3580,25 @@ typedef struct UnitStatusInfo {
LIST_HEAD(ExecStatusInfo, exec);
} UnitStatusInfo;
+static void unit_status_info_free(UnitStatusInfo *info) {
+ ExecStatusInfo *p;
+ UnitCondition *c;
+
+ strv_free(info->documentation);
+ strv_free(info->dropin_paths);
+ strv_free(info->listen);
+
+ while ((c = info->conditions)) {
+ LIST_REMOVE(conditions, info->conditions, c);
+ unit_condition_free(c);
+ }
+
+ while ((p = info->exec)) {
+ LIST_REMOVE(exec, info->exec, p);
+ exec_status_info_free(p);
+ }
+}
+
static void print_status_info(
sd_bus *bus,
UnitStatusInfo *i,
@@ -3629,19 +3720,28 @@ static void print_status_info(
printf("\n");
if (!i->condition_result && i->condition_timestamp > 0) {
+ UnitCondition *c;
+ int n = 0;
+
s1 = format_timestamp_relative(since1, sizeof(since1), i->condition_timestamp);
s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
printf("Condition: start %scondition failed%s at %s%s%s\n",
ansi_highlight_yellow(), ansi_normal(),
s2, s1 ? "; " : "", strempty(s1));
- if (i->failed_condition_trigger)
- printf(" none of the trigger conditions were met\n");
- else if (i->failed_condition)
- printf(" %s=%s%s was not met\n",
- i->failed_condition,
- i->failed_condition_negate ? "!" : "",
- i->failed_condition_parameter);
+
+ LIST_FOREACH(conditions, c, i->conditions)
+ if (c->tristate < 0)
+ n++;
+
+ LIST_FOREACH(conditions, c, i->conditions)
+ if (c->tristate < 0)
+ printf(" %s %s=%s%s%s was not met\n",
+ --n ? special_glyph(TREE_BRANCH) : special_glyph(TREE_RIGHT),
+ c->name,
+ c->trigger ? "|" : "",
+ c->negate ? "!" : "",
+ c->param);
}
if (!i->assert_result && i->assert_timestamp > 0) {
@@ -3726,7 +3826,7 @@ static void print_status_info(
if (i->running) {
_cleanup_free_ char *comm = NULL;
- get_process_comm(i->main_pid, &comm);
+ (void) get_process_comm(i->main_pid, &comm);
if (comm)
printf(" (%s)", comm);
} else if (i->exit_code > 0) {
@@ -3745,17 +3845,19 @@ static void print_status_info(
printf("signal=%s", signal_to_string(i->exit_status));
printf(")");
}
-
- if (i->control_pid > 0)
- printf(";");
}
if (i->control_pid > 0) {
_cleanup_free_ char *c = NULL;
- printf(" %8s: "PID_FMT, i->main_pid ? "" : " Control", i->control_pid);
+ if (i->main_pid > 0)
+ fputs("; Control PID: ", stdout);
+ else
+ fputs("Cntrl PID: ", stdout); /* if first in column, abbreviated so it fits alignment */
- get_process_comm(i->control_pid, &c);
+ printf(PID_FMT, i->control_pid);
+
+ (void) get_process_comm(i->control_pid, &c);
if (c)
printf(" (%s)", c);
}
@@ -3772,7 +3874,7 @@ static void print_status_info(
printf(" Tasks: %" PRIu64, i->tasks_current);
if (i->tasks_max != (uint64_t) -1)
- printf(" (limit: %" PRIi64 ")\n", i->tasks_max);
+ printf(" (limit: %" PRIu64 ")\n", i->tasks_max);
else
printf("\n");
}
@@ -3782,10 +3884,30 @@ static void print_status_info(
printf(" Memory: %s", format_bytes(buf, sizeof(buf), i->memory_current));
- if (i->memory_limit != (uint64_t) -1)
- printf(" (limit: %s)\n", format_bytes(buf, sizeof(buf), i->memory_limit));
- else
- printf("\n");
+ if (i->memory_low > 0 || i->memory_high != CGROUP_LIMIT_MAX || i->memory_max != CGROUP_LIMIT_MAX ||
+ i->memory_limit != CGROUP_LIMIT_MAX) {
+ const char *prefix = "";
+
+ printf(" (");
+ if (i->memory_low > 0) {
+ printf("%slow: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_low));
+ prefix = " ";
+ }
+ if (i->memory_high != CGROUP_LIMIT_MAX) {
+ printf("%shigh: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_high));
+ prefix = " ";
+ }
+ if (i->memory_max != CGROUP_LIMIT_MAX) {
+ printf("%smax: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_max));
+ prefix = " ";
+ }
+ if (i->memory_limit != CGROUP_LIMIT_MAX) {
+ printf("%slimit: %s", prefix, format_bytes(buf, sizeof(buf), i->memory_limit));
+ prefix = " ";
+ }
+ printf(")");
+ }
+ printf("\n");
}
if (i->cpu_usage_nsec != (uint64_t) -1) {
@@ -3793,14 +3915,13 @@ static void print_status_info(
printf(" CPU: %s\n", format_timespan(buf, sizeof(buf), i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC));
}
- if (i->control_group)
- printf(" CGroup: %s\n", i->control_group);
-
- {
+ if (i->control_group) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
static const char prefix[] = " ";
unsigned c;
+ printf(" CGroup: %s\n", i->control_group);
+
c = columns();
if (c > sizeof(prefix) - 1)
c -= sizeof(prefix) - 1;
@@ -4014,6 +4135,12 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *
i->assert_timestamp = (usec_t) u;
else if (streq(name, "MemoryCurrent"))
i->memory_current = u;
+ else if (streq(name, "MemoryLow"))
+ i->memory_low = u;
+ else if (streq(name, "MemoryHigh"))
+ i->memory_high = u;
+ else if (streq(name, "MemoryMax"))
+ i->memory_max = u;
else if (streq(name, "MemoryLimit"))
i->memory_limit = u;
else if (streq(name, "TasksCurrent"))
@@ -4109,13 +4236,25 @@ static int status_property(const char *name, sd_bus_message *m, UnitStatusInfo *
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
- log_debug("%s %d %d %s %d", cond, trigger, negate, param, state);
- if (state < 0 && (!trigger || !i->failed_condition)) {
- i->failed_condition = cond;
- i->failed_condition_trigger = trigger;
- i->failed_condition_negate = negate;
- i->failed_condition_parameter = param;
- }
+ _cleanup_(unit_condition_freep) UnitCondition *c = NULL;
+
+ log_debug("%s trigger=%d negate=%d %s →%d", cond, trigger, negate, param, state);
+
+ c = new0(UnitCondition, 1);
+ if (!c)
+ return log_oom();
+
+ c->name = strdup(cond);
+ c->param = strdup(param);
+ if (!c->name || !c->param)
+ return log_oom();
+
+ c->trigger = trigger;
+ c->negate = negate;
+ c->tristate = state;
+
+ LIST_PREPEND(conditions, i->conditions, c);
+ c = NULL;
}
if (r < 0)
return bus_log_parse_error(r);
@@ -4307,7 +4446,7 @@ static int print_property(const char *name, sd_bus_message *m, const char *conte
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(m, "(sb)", &path, &ignore)) > 0)
- print_prop("EnvironmentFile", "%s (ignore_errors=%s)\n", path, yes_no(ignore));
+ print_prop("EnvironmentFile", "%s (ignore_errors=%s)", path, yes_no(ignore));
if (r < 0)
return bus_log_parse_error(r);
@@ -4499,20 +4638,29 @@ static int show_one(
const char *verb,
sd_bus *bus,
const char *path,
+ const char *unit,
bool show_properties,
bool *new_line,
bool *ellipsized) {
+ static const struct bus_properties_map property_map[] = {
+ { "LoadState", "s", map_string_no_copy, offsetof(UnitStatusInfo, load_state) },
+ { "ActiveState", "s", map_string_no_copy, offsetof(UnitStatusInfo, active_state) },
+ {}
+ };
+
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- UnitStatusInfo info = {
+ _cleanup_set_free_ Set *found_properties = NULL;
+ _cleanup_(unit_status_info_free) UnitStatusInfo info = {
.memory_current = (uint64_t) -1,
+ .memory_high = CGROUP_LIMIT_MAX,
+ .memory_max = CGROUP_LIMIT_MAX,
.memory_limit = (uint64_t) -1,
.cpu_usage_nsec = (uint64_t) -1,
.tasks_current = (uint64_t) -1,
.tasks_max = (uint64_t) -1,
};
- ExecStatusInfo *p;
int r;
assert(path);
@@ -4532,6 +4680,25 @@ static int show_one(
if (r < 0)
return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
+ if (unit) {
+ r = bus_message_map_all_properties(reply, property_map, &info);
+ if (r < 0)
+ return log_error_errno(r, "Failed to map properties: %s", bus_error_message(&error, r));
+
+ if (streq_ptr(info.load_state, "not-found") && streq_ptr(info.active_state, "inactive")) {
+ log_error("Unit %s could not be found.", unit);
+
+ if (streq(verb, "status"))
+ return EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN;
+
+ return -ENOENT;
+ }
+
+ r = sd_bus_message_rewind(reply, true);
+ if (r < 0)
+ return log_error_errno(r, "Failed to rewind: %s", bus_error_message(&error, r));
+ }
+
r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
if (r < 0)
return bus_log_parse_error(r);
@@ -4556,9 +4723,17 @@ static int show_one(
if (r < 0)
return bus_log_parse_error(r);
- if (show_properties)
+ if (show_properties) {
+ r = set_ensure_allocated(&found_properties, &string_hash_ops);
+ if (r < 0)
+ return log_oom();
+
+ r = set_put(found_properties, name);
+ if (r < 0 && r != EEXIST)
+ return log_oom();
+
r = print_property(name, reply, contents);
- else
+ } else
r = status_property(name, reply, &info, contents);
if (r < 0)
return r;
@@ -4579,37 +4754,24 @@ static int show_one(
return bus_log_parse_error(r);
r = 0;
+ if (show_properties) {
+ char **pp;
- if (!show_properties) {
- if (streq(verb, "help"))
- show_unit_help(&info);
- else
- print_status_info(bus, &info, ellipsized);
- }
-
- strv_free(info.documentation);
- strv_free(info.dropin_paths);
- strv_free(info.listen);
-
- if (!streq_ptr(info.active_state, "active") &&
- !streq_ptr(info.active_state, "reloading") &&
- streq(verb, "status")) {
- /* According to LSB: "program not running" */
- /* 0: program is running or service is OK
- * 1: program is dead and /run PID file exists
- * 2: program is dead and /run/lock lock file exists
- * 3: program is not running
- * 4: program or service status is unknown
- */
- if (info.pid_file && access(info.pid_file, F_OK) == 0)
- r = 1;
- else
- r = 3;
- }
+ STRV_FOREACH(pp, arg_properties)
+ if (!set_contains(found_properties, *pp)) {
+ log_warning("Property %s does not exist.", *pp);
+ r = -ENXIO;
+ }
- while ((p = info.exec)) {
- LIST_REMOVE(exec, info.exec, p);
- exec_status_info_free(p);
+ } else if (streq(verb, "help"))
+ show_unit_help(&info);
+ else if (streq(verb, "status")) {
+ print_status_info(bus, &info, ellipsized);
+
+ if (info.active_state && STR_IN_SET(info.active_state, "inactive", "failed"))
+ r = EXIT_PROGRAM_NOT_RUNNING;
+ else
+ r = EXIT_PROGRAM_RUNNING_OR_SERVICE_OK;
}
return r;
@@ -4679,7 +4841,7 @@ static int show_all(
if (!p)
return log_oom();
- r = show_one(verb, bus, p, show_properties, new_line, ellipsized);
+ r = show_one(verb, bus, p, u->id, show_properties, new_line, ellipsized);
if (r < 0)
return r;
else if (r > 0 && ret == 0)
@@ -4761,6 +4923,10 @@ static int show(int argc, char *argv[], void *userdata) {
return -EINVAL;
}
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
pager_open(arg_no_pager, false);
if (show_status)
@@ -4769,17 +4935,12 @@ static int show(int argc, char *argv[], void *userdata) {
* be split up into many files. */
setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384));
- r = acquire_bus(BUS_MANAGER, &bus);
- if (r < 0)
- return r;
-
/* If no argument is specified inspect the manager itself */
if (show_properties && argc <= 1)
- return show_one(argv[0], bus, "/org/freedesktop/systemd1", show_properties, &new_line, &ellipsized);
+ return show_one(argv[0], bus, "/org/freedesktop/systemd1", NULL, show_properties, &new_line, &ellipsized);
if (show_status && argc <= 1) {
- pager_open(arg_no_pager, false);
show_system_status(bus);
new_line = true;
@@ -4790,7 +4951,7 @@ static int show(int argc, char *argv[], void *userdata) {
char **name;
STRV_FOREACH(name, strv_skip(argv, 1)) {
- _cleanup_free_ char *unit = NULL;
+ _cleanup_free_ char *path = NULL, *unit = NULL;
uint32_t id;
if (safe_atou32(*name, &id) < 0) {
@@ -4800,19 +4961,23 @@ static int show(int argc, char *argv[], void *userdata) {
continue;
} else if (show_properties) {
/* Interpret as job id */
- if (asprintf(&unit, "/org/freedesktop/systemd1/job/%u", id) < 0)
+ if (asprintf(&path, "/org/freedesktop/systemd1/job/%u", id) < 0)
return log_oom();
} else {
/* Interpret as PID */
- r = get_unit_dbus_path_by_pid(bus, id, &unit);
+ r = get_unit_dbus_path_by_pid(bus, id, &path);
if (r < 0) {
ret = r;
continue;
}
+
+ r = unit_name_from_dbus_path(path, &unit);
+ if (r < 0)
+ return log_oom();
}
- r = show_one(argv[0], bus, unit, show_properties, &new_line, &ellipsized);
+ r = show_one(argv[0], bus, path, unit, show_properties, &new_line, &ellipsized);
if (r < 0)
return r;
else if (r > 0 && ret == 0)
@@ -4827,16 +4992,16 @@ static int show(int argc, char *argv[], void *userdata) {
return log_error_errno(r, "Failed to expand names: %m");
STRV_FOREACH(name, names) {
- _cleanup_free_ char *unit;
+ _cleanup_free_ char *path;
- unit = unit_dbus_path_from_name(*name);
- if (!unit)
+ path = unit_dbus_path_from_name(*name);
+ if (!path)
return log_oom();
- r = show_one(argv[0], bus, unit, show_properties, &new_line, &ellipsized);
+ r = show_one(argv[0], bus, path, *name, show_properties, &new_line, &ellipsized);
if (r < 0)
return r;
- else if (r > 0 && ret == 0)
+ if (r > 0 && ret == 0)
ret = r;
}
}
@@ -4932,12 +5097,12 @@ static int set_property(int argc, char *argv[], void *userdata) {
char **i;
int r;
- polkit_agent_open_if_enabled();
-
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
return r;
+ polkit_agent_open_if_enabled();
+
r = sd_bus_message_new_method_call(
bus,
&m,
@@ -4979,36 +5144,87 @@ static int set_property(int argc, char *argv[], void *userdata) {
static int daemon_reload(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
const char *method;
sd_bus *bus;
int r;
- polkit_agent_open_if_enabled();
-
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
return r;
- if (arg_action == ACTION_RELOAD)
+ polkit_agent_open_if_enabled();
+
+ switch (arg_action) {
+
+ case ACTION_RELOAD:
method = "Reload";
- else if (arg_action == ACTION_REEXEC)
+ break;
+
+ case ACTION_REEXEC:
method = "Reexecute";
- else {
- assert(arg_action == ACTION_SYSTEMCTL);
+ break;
- method =
- streq(argv[0], "clear-jobs") ||
- streq(argv[0], "cancel") ? "ClearJobs" :
- streq(argv[0], "daemon-reexec") ? "Reexecute" :
- streq(argv[0], "reset-failed") ? "ResetFailed" :
- streq(argv[0], "halt") ? "Halt" :
- streq(argv[0], "poweroff") ? "PowerOff" :
- streq(argv[0], "reboot") ? "Reboot" :
- streq(argv[0], "kexec") ? "KExec" :
- streq(argv[0], "exit") ? "Exit" :
- /* "daemon-reload" */ "Reload";
+ case ACTION_SYSTEMCTL:
+ method = streq(argv[0], "daemon-reexec") ? "Reexecute" :
+ /* "daemon-reload" */ "Reload";
+ break;
+
+ default:
+ assert_not_reached("Unexpected action");
}
+ r = sd_bus_message_new_method_call(
+ bus,
+ &m,
+ "org.freedesktop.systemd1",
+ "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager",
+ method);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ /* Note we use an extra-long timeout here. This is because a reload or reexec means generators are rerun which
+ * are timed out after DEFAULT_TIMEOUT_USEC. Let's use twice that time here, so that the generators can have
+ * their timeout, and for everything else there's the same time budget in place. */
+
+ r = sd_bus_call(bus, m, DEFAULT_TIMEOUT_USEC * 2, &error, NULL);
+
+ /* On reexecution, we expect a disconnect, not a reply */
+ if (IN_SET(r, -ETIMEDOUT, -ECONNRESET) && streq(method, "Reexecute"))
+ r = 0;
+
+ if (r < 0 && arg_action == ACTION_SYSTEMCTL)
+ return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r));
+
+ /* Note that for the legacy commands (i.e. those with action != ACTION_SYSTEMCTL) we support fallbacks to the
+ * old ways of doing things, hence don't log any error in that case here. */
+
+ return r < 0 ? r : 0;
+}
+
+static int trivial_method(int argc, char *argv[], void *userdata) {
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ const char *method;
+ sd_bus *bus;
+ int r;
+
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ polkit_agent_open_if_enabled();
+
+ method =
+ streq(argv[0], "clear-jobs") ||
+ streq(argv[0], "cancel") ? "ClearJobs" :
+ streq(argv[0], "reset-failed") ? "ResetFailed" :
+ streq(argv[0], "halt") ? "Halt" :
+ streq(argv[0], "reboot") ? "Reboot" :
+ streq(argv[0], "kexec") ? "KExec" :
+ streq(argv[0], "exit") ? "Exit" :
+ /* poweroff */ "PowerOff";
+
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
@@ -5018,16 +5234,11 @@ static int daemon_reload(int argc, char *argv[], void *userdata) {
&error,
NULL,
NULL);
- if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
- /* There's always a fallback possible for
- * legacy actions. */
- r = -EADDRNOTAVAIL;
- else if ((r == -ETIMEDOUT || r == -ECONNRESET) && streq(method, "Reexecute"))
- /* On reexecution, we expect a disconnect, not a
- * reply */
- r = 0;
- else if (r < 0)
- return log_error_errno(r, "Failed to reload daemon: %s", bus_error_message(&error, r));
+ if (r < 0 && arg_action == ACTION_SYSTEMCTL)
+ return log_error_errno(r, "Failed to execute operation: %s", bus_error_message(&error, r));
+
+ /* Note that for the legacy commands (i.e. those with action != ACTION_SYSTEMCTL) we support fallbacks to the
+ * old ways of doing things, hence don't log any error in that case here. */
return r < 0 ? r : 0;
}
@@ -5039,14 +5250,14 @@ static int reset_failed(int argc, char *argv[], void *userdata) {
int r, q;
if (argc <= 1)
- return daemon_reload(argc, argv, userdata);
-
- polkit_agent_open_if_enabled();
+ return trivial_method(argc, argv, userdata);
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
return r;
+ polkit_agent_open_if_enabled();
+
r = expand_names(bus, strv_skip(argv, 1), NULL, &names);
if (r < 0)
return log_error_errno(r, "Failed to expand names: %m");
@@ -5080,12 +5291,12 @@ static int show_environment(int argc, char *argv[], void *userdata) {
sd_bus *bus;
int r;
- pager_open(arg_no_pager, false);
-
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
return r;
+ pager_open(arg_no_pager, false);
+
r = sd_bus_get_property(
bus,
"org.freedesktop.systemd1",
@@ -5145,9 +5356,7 @@ static int switch_root(int argc, char *argv[], void *userdata) {
init = cmdline_init;
}
- if (isempty(init))
- init = NULL;
-
+ init = empty_to_null(init);
if (init) {
const char *root_systemd_path = NULL, *root_init_path = NULL;
@@ -5191,12 +5400,12 @@ static int set_environment(int argc, char *argv[], void *userdata) {
assert(argc > 1);
assert(argv);
- polkit_agent_open_if_enabled();
-
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
return r;
+ polkit_agent_open_if_enabled();
+
method = streq(argv[0], "set-environment")
? "SetEnvironment"
: "UnsetEnvironment";
@@ -5228,12 +5437,12 @@ static int import_environment(int argc, char *argv[], void *userdata) {
sd_bus *bus;
int r;
- polkit_agent_open_if_enabled();
-
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
return r;
+ polkit_agent_open_if_enabled();
+
r = sd_bus_message_new_method_call(
bus,
&m,
@@ -5391,10 +5600,8 @@ static int enable_sysv_units(const char *verb, char **args) {
}
j = wait_for_terminate(pid, &status);
- if (j < 0) {
- log_error_errno(j, "Failed to wait for child: %m");
- return j;
- }
+ if (j < 0)
+ return log_error_errno(j, "Failed to wait for child: %m");
if (status.si_code == CLD_EXITED) {
if (streq(verb, "is-enabled")) {
@@ -5464,6 +5671,46 @@ static int mangle_names(char **original_names, char ***mangled_names) {
return 0;
}
+static int unit_exists(const char *unit) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_free_ char *path = NULL;
+ static const struct bus_properties_map property_map[] = {
+ { "LoadState", "s", map_string_no_copy, offsetof(UnitStatusInfo, load_state) },
+ { "ActiveState", "s", map_string_no_copy, offsetof(UnitStatusInfo, active_state)},
+ {},
+ };
+ UnitStatusInfo info = {};
+ sd_bus *bus;
+ int r;
+
+ path = unit_dbus_path_from_name(unit);
+ if (!path)
+ return log_oom();
+
+ r = acquire_bus(BUS_MANAGER, &bus);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_call_method(
+ bus,
+ "org.freedesktop.systemd1",
+ path,
+ "org.freedesktop.DBus.Properties",
+ "GetAll",
+ &error,
+ &reply,
+ "s", "");
+ if (r < 0)
+ return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
+
+ r = bus_message_map_all_properties(reply, property_map, &info);
+ if (r < 0)
+ return log_error_errno(r, "Failed to map properties: %s", bus_error_message(&error, r));
+
+ return !streq_ptr(info.load_state, "not-found") || !streq_ptr(info.active_state, "inactive");
+}
+
static int enable_unit(int argc, char *argv[], void *userdata) {
_cleanup_strv_free_ char **names = NULL;
const char *verb = argv[0];
@@ -5515,7 +5762,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
unit_file_dump_changes(r, verb, changes, n_changes, arg_quiet);
if (r < 0)
- return r;
+ goto finish;
r = 0;
} else {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL, *m = NULL;
@@ -5525,12 +5772,20 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
const char *method;
sd_bus *bus;
- polkit_agent_open_if_enabled();
+ if (STR_IN_SET(verb, "mask", "unmask")) {
+ r = unit_exists(*names);
+ if (r < 0)
+ return r;
+ if (r == 0)
+ log_notice("Unit %s does not exist, proceeding anyway.", *names);
+ }
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
return r;
+ polkit_agent_open_if_enabled();
+
if (streq(verb, "enable")) {
method = "EnableUnitFiles";
expect_carries_install_info = true;
@@ -5607,7 +5862,7 @@ static int enable_unit(int argc, char *argv[], void *userdata) {
r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, &changes, &n_changes);
if (r < 0)
- return r;
+ goto finish;
/* Try to reload if enabled */
if (!arg_no_reload)
@@ -5691,12 +5946,12 @@ static int add_dependency(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus;
- polkit_agent_open_if_enabled();
-
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
return r;
+ polkit_agent_open_if_enabled();
+
r = sd_bus_message_new_method_call(
bus,
&m,
@@ -5753,12 +6008,12 @@ static int preset_all(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
sd_bus *bus;
- polkit_agent_open_if_enabled();
-
r = acquire_bus(BUS_MANAGER, &bus);
if (r < 0)
return r;
+ polkit_agent_open_if_enabled();
+
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
@@ -5929,7 +6184,7 @@ static int create_edit_temp_file(const char *new_path, const char *original_path
return log_error_errno(r, "Failed to create temporary file \"%s\": %m", t);
} else if (r < 0)
- return log_error_errno(r, "Failed to copy \"%s\" to \"%s\": %m", original_path, t);
+ return log_error_errno(r, "Failed to create temporary file for \"%s\": %m", new_path);
*ret_tmp_fn = t;
t = NULL;
@@ -5952,7 +6207,7 @@ static int get_file_to_edit(
return log_oom();
if (arg_runtime) {
- run = strjoin(paths->runtime_config, name, NULL);
+ run = strjoin(paths->runtime_config, "/", name, NULL);
if (!run)
return log_oom();
}
@@ -5973,9 +6228,10 @@ static int get_file_to_edit(
return 0;
}
-static int unit_file_create_dropin(
+static int unit_file_create_new(
const LookupPaths *paths,
const char *unit_name,
+ const char *suffix,
char **ret_new_path,
char **ret_tmp_path) {
@@ -5986,7 +6242,7 @@ static int unit_file_create_dropin(
assert(ret_new_path);
assert(ret_tmp_path);
- ending = strjoina(unit_name, ".d/override.conf");
+ ending = strjoina(unit_name, suffix);
r = get_file_to_edit(paths, ending, &tmp_new_path);
if (r < 0)
return r;
@@ -6033,13 +6289,12 @@ static int unit_file_create_copy(
if (response != 'y') {
log_warning("%s ignored", unit_name);
free(tmp_new_path);
- return -1;
+ return -EKEYREJECTED;
}
}
r = create_edit_temp_file(tmp_new_path, fragment_path, &tmp_tmp_path);
if (r < 0) {
- log_error_errno(r, "Failed to create temporary file for \"%s\": %m", tmp_new_path);
free(tmp_new_path);
return r;
}
@@ -6150,18 +6405,24 @@ static int find_paths_to_edit(sd_bus *bus, char **names, char ***paths) {
r = unit_find_paths(bus, *name, &lp, &path, NULL);
if (r < 0)
return r;
- else if (r == 0)
- return -ENOENT;
- else if (!path) {
- // FIXME: support units with path==NULL (no FragmentPath)
- log_error("No fragment exists for %s.", *name);
- return -ENOENT;
+ else if (!arg_force) {
+ if (r == 0) {
+ log_error("Run 'systemctl edit --force %s' to create a new unit.", *name);
+ return -ENOENT;
+ } else if (!path) {
+ // FIXME: support units with path==NULL (no FragmentPath)
+ log_error("No fragment exists for %s.", *name);
+ return -ENOENT;
+ }
}
- if (arg_full)
- r = unit_file_create_copy(&lp, *name, path, &new_path, &tmp_path);
- else
- r = unit_file_create_dropin(&lp, *name, &new_path, &tmp_path);
+ if (path) {
+ if (arg_full)
+ r = unit_file_create_copy(&lp, *name, path, &new_path, &tmp_path);
+ else
+ r = unit_file_create_new(&lp, *name, ".d/override.conf", &new_path, &tmp_path);
+ } else
+ r = unit_file_create_new(&lp, *name, NULL, &new_path, &tmp_path);
if (r < 0)
return r;
@@ -6335,7 +6596,7 @@ static void systemctl_help(void) {
" unit is required or wanted\n\n"
"Unit File Commands:\n"
" list-unit-files [PATTERN...] List installed unit files\n"
- " enable NAME... Enable one or more unit files\n"
+ " enable [NAME...|PATH...] Enable one or more unit files\n"
" disable NAME... Disable one or more unit files\n"
" reenable NAME... Reenable one or more unit files\n"
" preset NAME... Enable/disable one or more unit files\n"
@@ -7421,71 +7682,71 @@ static int systemctl_main(int argc, char *argv[]) {
static const Verb verbs[] = {
{ "list-units", VERB_ANY, VERB_ANY, VERB_DEFAULT|VERB_NOCHROOT, list_units },
- { "list-unit-files", VERB_ANY, VERB_ANY, 0, list_unit_files },
- { "list-sockets", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_sockets },
- { "list-timers", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_timers },
- { "list-jobs", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_jobs },
- { "list-machines", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_machines },
- { "clear-jobs", VERB_ANY, 1, VERB_NOCHROOT, daemon_reload },
- { "cancel", VERB_ANY, VERB_ANY, VERB_NOCHROOT, cancel_job },
- { "start", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
- { "stop", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
- { "condstop", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with ALTLinux */
- { "reload", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
- { "restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
- { "try-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
- { "reload-or-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
- { "reload-or-try-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatbility with old systemctl <= 228 */
- { "try-reload-or-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
- { "force-reload", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with SysV */
- { "condreload", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with ALTLinux */
- { "condrestart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with RH */
- { "isolate", 2, 2, VERB_NOCHROOT, start_unit },
- { "kill", 2, VERB_ANY, VERB_NOCHROOT, kill_unit },
- { "is-active", 2, VERB_ANY, VERB_NOCHROOT, check_unit_active },
- { "check", 2, VERB_ANY, VERB_NOCHROOT, check_unit_active },
- { "is-failed", 2, VERB_ANY, VERB_NOCHROOT, check_unit_failed },
- { "show", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show },
- { "cat", 2, VERB_ANY, VERB_NOCHROOT, cat },
- { "status", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show },
- { "help", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show },
- { "daemon-reload", VERB_ANY, 1, VERB_NOCHROOT, daemon_reload },
- { "daemon-reexec", VERB_ANY, 1, VERB_NOCHROOT, daemon_reload },
- { "show-environment", VERB_ANY, 1, VERB_NOCHROOT, show_environment },
- { "set-environment", 2, VERB_ANY, VERB_NOCHROOT, set_environment },
- { "unset-environment", 2, VERB_ANY, VERB_NOCHROOT, set_environment },
- { "import-environment", VERB_ANY, VERB_ANY, VERB_NOCHROOT, import_environment},
- { "halt", VERB_ANY, 1, VERB_NOCHROOT, start_special },
- { "poweroff", VERB_ANY, 1, VERB_NOCHROOT, start_special },
- { "reboot", VERB_ANY, 2, VERB_NOCHROOT, start_special },
- { "kexec", VERB_ANY, 1, VERB_NOCHROOT, start_special },
- { "suspend", VERB_ANY, 1, VERB_NOCHROOT, start_special },
- { "hibernate", VERB_ANY, 1, VERB_NOCHROOT, start_special },
- { "hybrid-sleep", VERB_ANY, 1, VERB_NOCHROOT, start_special },
- { "default", VERB_ANY, 1, VERB_NOCHROOT, start_special },
- { "rescue", VERB_ANY, 1, VERB_NOCHROOT, start_special },
- { "emergency", VERB_ANY, 1, VERB_NOCHROOT, start_special },
- { "exit", VERB_ANY, 2, VERB_NOCHROOT, start_special },
- { "reset-failed", VERB_ANY, VERB_ANY, VERB_NOCHROOT, reset_failed },
- { "enable", 2, VERB_ANY, 0, enable_unit },
- { "disable", 2, VERB_ANY, 0, enable_unit },
- { "is-enabled", 2, VERB_ANY, 0, unit_is_enabled },
- { "reenable", 2, VERB_ANY, 0, enable_unit },
- { "preset", 2, VERB_ANY, 0, enable_unit },
- { "preset-all", VERB_ANY, 1, 0, preset_all },
- { "mask", 2, VERB_ANY, 0, enable_unit },
- { "unmask", 2, VERB_ANY, 0, enable_unit },
- { "link", 2, VERB_ANY, 0, enable_unit },
- { "revert", 2, VERB_ANY, 0, enable_unit },
- { "switch-root", 2, VERB_ANY, VERB_NOCHROOT, switch_root },
- { "list-dependencies", VERB_ANY, 2, VERB_NOCHROOT, list_dependencies },
- { "set-default", 2, 2, 0, set_default },
- { "get-default", VERB_ANY, 1, 0, get_default, },
- { "set-property", 3, VERB_ANY, VERB_NOCHROOT, set_property },
- { "is-system-running", VERB_ANY, 1, 0, is_system_running },
- { "add-wants", 3, VERB_ANY, 0, add_dependency },
- { "add-requires", 3, VERB_ANY, 0, add_dependency },
- { "edit", 2, VERB_ANY, VERB_NOCHROOT, edit },
+ { "list-unit-files", VERB_ANY, VERB_ANY, 0, list_unit_files },
+ { "list-sockets", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_sockets },
+ { "list-timers", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_timers },
+ { "list-jobs", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_jobs },
+ { "list-machines", VERB_ANY, VERB_ANY, VERB_NOCHROOT, list_machines },
+ { "clear-jobs", VERB_ANY, 1, VERB_NOCHROOT, trivial_method },
+ { "cancel", VERB_ANY, VERB_ANY, VERB_NOCHROOT, cancel_job },
+ { "start", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
+ { "stop", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
+ { "condstop", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with ALTLinux */
+ { "reload", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
+ { "restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
+ { "try-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
+ { "reload-or-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
+ { "reload-or-try-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatbility with old systemctl <= 228 */
+ { "try-reload-or-restart", 2, VERB_ANY, VERB_NOCHROOT, start_unit },
+ { "force-reload", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with SysV */
+ { "condreload", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with ALTLinux */
+ { "condrestart", 2, VERB_ANY, VERB_NOCHROOT, start_unit }, /* For compatibility with RH */
+ { "isolate", 2, 2, VERB_NOCHROOT, start_unit },
+ { "kill", 2, VERB_ANY, VERB_NOCHROOT, kill_unit },
+ { "is-active", 2, VERB_ANY, VERB_NOCHROOT, check_unit_active },
+ { "check", 2, VERB_ANY, VERB_NOCHROOT, check_unit_active },
+ { "is-failed", 2, VERB_ANY, VERB_NOCHROOT, check_unit_failed },
+ { "show", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show },
+ { "cat", 2, VERB_ANY, VERB_NOCHROOT, cat },
+ { "status", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show },
+ { "help", VERB_ANY, VERB_ANY, VERB_NOCHROOT, show },
+ { "daemon-reload", VERB_ANY, 1, VERB_NOCHROOT, daemon_reload },
+ { "daemon-reexec", VERB_ANY, 1, VERB_NOCHROOT, daemon_reload },
+ { "show-environment", VERB_ANY, 1, VERB_NOCHROOT, show_environment },
+ { "set-environment", 2, VERB_ANY, VERB_NOCHROOT, set_environment },
+ { "unset-environment", 2, VERB_ANY, VERB_NOCHROOT, set_environment },
+ { "import-environment", VERB_ANY, VERB_ANY, VERB_NOCHROOT, import_environment },
+ { "halt", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
+ { "poweroff", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
+ { "reboot", VERB_ANY, 2, VERB_NOCHROOT, start_system_special },
+ { "kexec", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
+ { "suspend", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
+ { "hibernate", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
+ { "hybrid-sleep", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
+ { "default", VERB_ANY, 1, VERB_NOCHROOT, start_special },
+ { "rescue", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
+ { "emergency", VERB_ANY, 1, VERB_NOCHROOT, start_system_special },
+ { "exit", VERB_ANY, 2, VERB_NOCHROOT, start_special },
+ { "reset-failed", VERB_ANY, VERB_ANY, VERB_NOCHROOT, reset_failed },
+ { "enable", 2, VERB_ANY, 0, enable_unit },
+ { "disable", 2, VERB_ANY, 0, enable_unit },
+ { "is-enabled", 2, VERB_ANY, 0, unit_is_enabled },
+ { "reenable", 2, VERB_ANY, 0, enable_unit },
+ { "preset", 2, VERB_ANY, 0, enable_unit },
+ { "preset-all", VERB_ANY, 1, 0, preset_all },
+ { "mask", 2, VERB_ANY, 0, enable_unit },
+ { "unmask", 2, VERB_ANY, 0, enable_unit },
+ { "link", 2, VERB_ANY, 0, enable_unit },
+ { "revert", 2, VERB_ANY, 0, enable_unit },
+ { "switch-root", 2, VERB_ANY, VERB_NOCHROOT, switch_root },
+ { "list-dependencies", VERB_ANY, 2, VERB_NOCHROOT, list_dependencies },
+ { "set-default", 2, 2, 0, set_default },
+ { "get-default", VERB_ANY, 1, 0, get_default },
+ { "set-property", 3, VERB_ANY, VERB_NOCHROOT, set_property },
+ { "is-system-running", VERB_ANY, 1, 0, is_system_running },
+ { "add-wants", 3, VERB_ANY, 0, add_dependency },
+ { "add-requires", 3, VERB_ANY, 0, add_dependency },
+ { "edit", 2, VERB_ANY, VERB_NOCHROOT, edit },
{}
};
@@ -7499,7 +7760,7 @@ static int reload_with_fallback(void) {
return 0;
/* Nothing else worked, so let's try signals */
- assert(arg_action == ACTION_RELOAD || arg_action == ACTION_REEXEC);
+ assert(IN_SET(arg_action, ACTION_RELOAD, ACTION_REEXEC));
if (kill(1, arg_action == ACTION_RELOAD ? SIGHUP : SIGTERM) < 0)
return log_error_errno(errno, "kill() failed: %m");
@@ -7513,8 +7774,7 @@ static int start_with_fallback(void) {
if (start_unit(0, NULL, NULL) >= 0)
return 0;
- /* Nothing else worked, so let's try
- * /dev/initctl */
+ /* Nothing else worked, so let's try /dev/initctl */
if (talk_initctl() > 0)
return 0;
@@ -7580,8 +7840,6 @@ static int logind_schedule_shutdown(void) {
sd_bus *bus;
int r;
- (void) logind_set_wall_message();
-
r = acquire_bus(BUS_FULL, &bus);
if (r < 0)
return r;
@@ -7608,6 +7866,8 @@ static int logind_schedule_shutdown(void) {
if (arg_dry)
action = strjoina("dry-", action);
+ (void) logind_set_wall_message();
+
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
@@ -7736,6 +7996,7 @@ int main(int argc, char*argv[]) {
setlocale(LC_ALL, "");
log_parse_environment();
log_open();
+ sigbus_install();
/* Explicitly not on_tty() to avoid setting cached value.
* This becomes relevant for piping output which might be
@@ -7797,6 +8058,8 @@ int main(int argc, char*argv[]) {
}
finish:
+ release_busses();
+
pager_close();
ask_password_agent_close();
polkit_agent_close();
@@ -7808,9 +8071,6 @@ finish:
strv_free(arg_wall);
free(arg_root);
- release_busses();
-
/* Note that we return r here, not EXIT_SUCCESS, so that we can implement the LSB-like return codes */
-
return r < 0 ? EXIT_FAILURE : r;
}
diff --git a/src/grp-system/systemctl/systemctl.xml b/src/grp-system/systemctl/systemctl.xml
index 991e9bafaf..e7880d24f7 100644
--- a/src/grp-system/systemctl/systemctl.xml
+++ b/src/grp-system/systemctl/systemctl.xml
@@ -150,11 +150,11 @@
<term><option>--all</option></term>
<listitem>
- <para>When listing units, show all loaded units, regardless
- of their state, including inactive units. When showing
- unit/job/manager properties, show all properties regardless
- whether they are set or not.</para>
- <para>To list all units installed on the system, use the
+ <para>When listing units with <command>list-units</command>, also show inactive units and
+ units which are following other units. When showing unit/job/manager properties, show all
+ properties regardless whether they are set or not.</para>
+
+ <para>To list all units installed in the file system, use the
<command>list-unit-files</command> command instead.</para>
</listitem>
</varlistentry>
@@ -481,19 +481,19 @@
<para>When used with <command>enable</command>, overwrite
any existing conflicting symlinks.</para>
- <para>When used with <command>halt</command>,
- <command>poweroff</command>, <command>reboot</command> or
- <command>kexec</command>, execute the selected operation
- without shutting down all units. However, all processes will
- be killed forcibly and all file systems are unmounted or
- remounted read-only. This is hence a drastic but relatively
- safe option to request an immediate reboot. If
- <option>--force</option> is specified twice for these
- operations, they will be executed immediately without
- terminating any processes or unmounting any file
- systems. Warning: specifying <option>--force</option> twice
- with any of these operations might result in data
- loss.</para>
+ <para>When used with <command>edit</command>, create all of the
+ specified units which do not already exist.</para>
+
+ <para>When used with <command>halt</command>, <command>poweroff</command>, <command>reboot</command> or
+ <command>kexec</command>, execute the selected operation without shutting down all units. However, all
+ processes will be killed forcibly and all file systems are unmounted or remounted read-only. This is hence a
+ drastic but relatively safe option to request an immediate reboot. If <option>--force</option> is specified
+ twice for these operations (with the exception of <command>kexec</command>), they will be executed
+ immediately, without terminating any processes or unmounting any file systems. Warning: specifying
+ <option>--force</option> twice with any of these operations might result in data loss. Note that when
+ <option>--force</option> is specified twice the selected operation is executed by
+ <command>systemctl</command> itself, and the system manager is not contacted. This means the command should
+ succeed even when the system manager hangs or crashed.</para>
</listitem>
</varlistentry>
@@ -638,10 +638,13 @@
<term><command>list-units <optional><replaceable>PATTERN</replaceable>...</optional></command></term>
<listitem>
- <para>List known units (subject to limitations specified
- with <option>-t</option>). If one or more
- <replaceable>PATTERN</replaceable>s are specified, only
- units matching one of them are shown.</para>
+ <para>List units that <command>systemd</command> has loaded. This includes units that
+ are either referenced directly or through a dependency, or units that were active in the
+ past and have failed. By default only units which are active, have pending jobs, or have
+ failed are shown; this can be changed with option <option>--all</option>. If one or more
+ <replaceable>PATTERN</replaceable>s are specified, only units matching one of them are
+ shown. The units that are shown are additionally filtered by <option>--type=</option>
+ and <option>--state=</option> if those options are specified.</para>
<para>This is the default command.</para>
</listitem>
@@ -970,71 +973,61 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
<term><command>list-unit-files <optional><replaceable>PATTERN...</replaceable></optional></command></term>
<listitem>
- <para>List installed unit files and their enablement state
- (as reported by <command>is-enabled</command>). If one or
- more <replaceable>PATTERN</replaceable>s are specified,
- only units whose filename (just the last component of the
- path) matches one of them are shown.</para>
+ <para>List unit files installed on the system, in combination with their enablement state (as reported by
+ <command>is-enabled</command>). If one or more <replaceable>PATTERN</replaceable>s are specified, only unit
+ files whose name matches one of them are shown (patterns matching unit file system paths are not
+ supported).</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>enable <replaceable>NAME</replaceable>...</command></term>
+ <term><command>enable <replaceable>PATH</replaceable>...</command></term>
<listitem>
- <para>Enable one or more unit files or unit file instances,
- as specified on the command line. This will create a number
- of symlinks as encoded in the <literal>[Install]</literal>
- sections of the unit files. After the symlinks have been
- created, the systemd configuration is reloaded (in a way that
- is equivalent to <command>daemon-reload</command>) to ensure
- the changes are taken into account immediately. Note that
- this does <emphasis>not</emphasis> have the effect of also
- starting any of the units being enabled. If this
- is desired, either <option>--now</option> should be used
- together with this command, or an additional <command>start</command>
- command must be invoked for the unit. Also note that, in case of
- instance enablement, symlinks named the same as instances
- are created in the install location, however they all point to the
- same template unit file.</para>
-
- <para>This command will print the actions executed. This
- output may be suppressed by passing <option>--quiet</option>.
+ <para>Enable one or more units or unit instances. This will create a set of symlinks, as encoded in the
+ <literal>[Install]</literal> sections of the indicated unit files. After the symlinks have been created,
+ the system manager configuration is reloaded (in a way equivalent to <command>daemon-reload</command>), in
+ order to ensure the changes are taken into account immediately. Note that this does
+ <emphasis>not</emphasis> have the effect of also starting any of the units being enabled. If this is
+ desired, combine this command with the <option>--now</option> switch, or invoke <command>start</command>
+ with appropriate arguments later. Note that in case of unit instance enablement (i.e. enablement of units of
+ the form <filename>foo@bar.service</filename>), symlinks named the same as instances are created in the
+ unit configuration diectory, however they point to the single template unit file they are instantiated
+ from.</para>
+
+ <para>This command expects either valid unit names (in which case various unit file directories are
+ automatically searched for unit files with appropriate names), or absolute paths to unit files (in which
+ case these files are read directly). If a specified unit file is located outside of the usual unit file
+ directories, an additional symlink is created, linking it into the unit configuration path, thus ensuring
+ it is found when requested by commands such as <command>start</command>.</para>
+
+ <para>This command will print the file system operations executed. This output may be suppressed by passing
+ <option>--quiet</option>.
</para>
- <para>Note that this operation creates only the suggested
- symlinks for the units. While this command is the
- recommended way to manipulate the unit configuration
- directory, the administrator is free to make additional
- changes manually by placing or removing symlinks in the
- directory. This is particularly useful to create
- configurations that deviate from the suggested default
- installation. In this case, the administrator must make sure
- to invoke <command>daemon-reload</command> manually as
- necessary to ensure the changes are taken into account.
+ <para>Note that this operation creates only the symlinks suggested in the <literal>[Install]</literal>
+ section of the unit files. While this command is the recommended way to manipulate the unit configuration
+ directory, the administrator is free to make additional changes manually by placing or removing symlinks
+ below this directory. This is particularly useful to create configurations that deviate from the suggested
+ default installation. In this case, the administrator must make sure to invoke
+ <command>daemon-reload</command> manually as necessary, in order to ensure the changes are taken into
+ account.
</para>
- <para>Enabling units should not be confused with starting
- (activating) units, as done by the <command>start</command>
- command. Enabling and starting units is orthogonal: units
- may be enabled without being started and started without
- being enabled. Enabling simply hooks the unit into various
- suggested places (for example, so that the unit is
- automatically started on boot or when a particular kind of
- hardware is plugged in). Starting actually spawns the daemon
- process (in case of service units), or binds the socket (in
- case of socket units), and so on.</para>
-
- <para>Depending on whether <option>--system</option>,
- <option>--user</option>, <option>--runtime</option>,
- or <option>--global</option> is specified, this enables the unit
- for the system, for the calling user only, for only this boot of
- the system, or for all future logins of all users, or only this
- boot. Note that in the last case, no systemd daemon
- configuration is reloaded.</para>
-
- <para>Using <command>enable</command> on masked units
- results in an error.</para>
+ <para>Enabling units should not be confused with starting (activating) units, as done by the
+ <command>start</command> command. Enabling and starting units is orthogonal: units may be enabled without
+ being started and started without being enabled. Enabling simply hooks the unit into various suggested
+ places (for example, so that the unit is automatically started on boot or when a particular kind of
+ hardware is plugged in). Starting actually spawns the daemon process (in case of service units), or binds
+ the socket (in case of socket units), and so on.</para>
+
+ <para>Depending on whether <option>--system</option>, <option>--user</option>, <option>--runtime</option>,
+ or <option>--global</option> is specified, this enables the unit for the system, for the calling user only,
+ for only this boot of the system, or for all future logins of all users, or only this boot. Note that in
+ the last case, no systemd daemon configuration is reloaded.</para>
+
+ <para>Using <command>enable</command> on masked units is not supported and results in an error.</para>
</listitem>
</varlistentry>
@@ -1042,28 +1035,31 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
<term><command>disable <replaceable>NAME</replaceable>...</command></term>
<listitem>
- <para>Disables one or more units. This removes all symlinks
- to the specified unit files from the unit configuration
- directory, and hence undoes the changes made by
- <command>enable</command>. Note however that this removes
- all symlinks to the unit files (i.e. including manual
- additions), not just those actually created by
- <command>enable</command>. This call implicitly reloads the
- systemd daemon configuration after completing the disabling
- of the units. Note that this command does not implicitly
- stop the units that are being disabled. If this is desired, either
- <option>--now</option> should be used together with this command, or
- an additional <command>stop</command> command should be executed
- afterwards.</para>
-
- <para>This command will print the actions executed. This
- output may be suppressed by passing <option>--quiet</option>.
+ <para>Disables one or more units. This removes all symlinks to the unit files backing the specified units
+ from the unit configuration directory, and hence undoes any changes made by <command>enable</command> or
+ <command>link</command>. Note that this removes <emphasis>all</emphasis> symlinks to matching unit files,
+ including manually created symlinks, and not just those actually created by <command>enable</command> or
+ <command>link</command>. Note that while <command>disable</command> undoes the effect of
+ <command>enable</command>, the two commands are otherwise not symmetric, as <command>disable</command> may
+ remove more symlinks than a prior <command>enable</command> invocation of the same unit created.</para>
+
+ <para>This command expects valid unit names only, it does not accept paths to unit files.</para>
+
+ <para>In addition to the units specified as arguments, all units are disabled that are listed in the
+ <varname>Also=</varname> setting contained in the <literal>[Install]</literal> section of any of the unit
+ files being operated on.</para>
+
+ <para>This command implicitly reloads the system manager configuration after completing the operation. Note
+ that this command does not implicitly stop the units that are being disabled. If this is desired, either
+ combine this command with the <option>--now</option> switch, or invoke the <command>stop</command> command
+ with appropriate arguments later.</para>
+
+ <para>This command will print information about the file system operations (symlink removals)
+ executed. This output may be suppressed by passing <option>--quiet</option>.
</para>
- <para>This command honors <option>--system</option>,
- <option>--user</option>, <option>--runtime</option> and
- <option>--global</option> in a similar way as
- <command>enable</command>.</para>
+ <para>This command honors <option>--system</option>, <option>--user</option>, <option>--runtime</option>
+ and <option>--global</option> in a similar way as <command>enable</command>.</para>
</listitem>
</varlistentry>
@@ -1071,12 +1067,10 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
<term><command>reenable <replaceable>NAME</replaceable>...</command></term>
<listitem>
- <para>Reenable one or more unit files, as specified on the
- command line. This is a combination of
- <command>disable</command> and <command>enable</command> and
- is useful to reset the symlinks a unit is enabled with to
- the defaults configured in the <literal>[Install]</literal>
- section of the unit file.</para>
+ <para>Reenable one or more units, as specified on the command line. This is a combination of
+ <command>disable</command> and <command>enable</command> and is useful to reset the symlinks a unit file is
+ enabled with to the defaults configured in its <literal>[Install]</literal> section. This commands expects
+ a unit uname only, it does not accept paths to unit files.</para>
</listitem>
</varlistentry>
@@ -1207,16 +1201,13 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
<term><command>mask <replaceable>NAME</replaceable>...</command></term>
<listitem>
- <para>Mask one or more unit files, as specified on the
- command line. This will link these units to
- <filename>/dev/null</filename>, making it impossible to
- start them. This is a stronger version of
- <command>disable</command>, since it prohibits all kinds of
- activation of the unit, including enablement and manual
- activation. Use this option with care. This honors the
- <option>--runtime</option> option to only mask temporarily
- until the next reboot of the system. The <option>--now</option>
- option can be used to ensure that the units are also stopped.</para>
+ <para>Mask one or more units, as specified on the command line. This will link these unit files to
+ <filename>/dev/null</filename>, making it impossible to start them. This is a stronger version of
+ <command>disable</command>, since it prohibits all kinds of activation of the unit, including enablement
+ and manual activation. Use this option with care. This honors the <option>--runtime</option> option to only
+ mask temporarily until the next reboot of the system. The <option>--now</option> option may be used to
+ ensure that the units are also stopped. This command expects valid unit names only, it does not accept unit
+ file paths.</para>
</listitem>
</varlistentry>
@@ -1224,23 +1215,20 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
<term><command>unmask <replaceable>NAME</replaceable>...</command></term>
<listitem>
- <para>Unmask one or more unit files, as specified on the
- command line. This will undo the effect of
- <command>mask</command>.</para>
+ <para>Unmask one or more unit files, as specified on the command line. This will undo the effect of
+ <command>mask</command>. This command expects valid unit names only, it does not accept unit file
+ paths.</para>
</listitem>
</varlistentry>
<varlistentry>
- <term><command>link <replaceable>FILENAME</replaceable>...</command></term>
+ <term><command>link <replaceable>PATH</replaceable>...</command></term>
<listitem>
- <para>Link a unit file that is not in the unit file search
- paths into the unit file search path. This requires an
- absolute path to a unit file. The effect of this can be
- undone with <command>disable</command>. The effect of this
- command is that a unit file is available for
- <command>start</command> and other commands although it
- is not installed directly in the unit search path.</para>
+ <para>Link a unit file that is not in the unit file search paths into the unit file search path. This
+ command expects an absolute path to a unit file. The effect of this may be undone with
+ <command>disable</command>. The effect of this command is that a unit file is made available for commands
+ such as <command>start</command>, even though it is not installed directly in the unit search path.</para>
</listitem>
</varlistentry>
@@ -1304,6 +1292,9 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
<para>If <option>--full</option> is specified, this will copy the
original units instead of creating drop-in files.</para>
+ <para>If <option>--force</option> is specified and any units do
+ not already exist, new unit files will be opened for editing.</para>
+
<para>If <option>--runtime</option> is specified, the changes will
be made temporarily in <filename>/run</filename> and they will be
lost on the next reboot.</para>
@@ -1600,48 +1591,45 @@ kobject-uevent 1 systemd-udevd-kernel.socket systemd-udevd.service
<term><command>halt</command></term>
<listitem>
- <para>Shut down and halt the system. This is mostly equivalent to
- <command>start halt.target --job-mode=replace-irreversibly</command>, but also
- prints a wall message to all users. If combined with
- <option>--force</option>, shutdown of all running services is
- skipped, however all processes are killed and all file
- systems are unmounted or mounted read-only, immediately
- followed by the system halt. If <option>--force</option> is
- specified twice, the operation is immediately executed
- without terminating any processes or unmounting any file
- systems. This may result in data loss.</para>
+ <para>Shut down and halt the system. This is mostly equivalent to <command>start halt.target
+ --job-mode=replace-irreversibly</command>, but also prints a wall message to all users. If combined with
+ <option>--force</option>, shutdown of all running services is skipped, however all processes are killed and
+ all file systems are unmounted or mounted read-only, immediately followed by the system halt. If
+ <option>--force</option> is specified twice, the operation is immediately executed without terminating any
+ processes or unmounting any file systems. This may result in data loss. Note that when
+ <option>--force</option> is specified twice the halt operation is executed by
+ <command>systemctl</command> itself, and the system manager is not contacted. This means the command should
+ succeed even when the system manager hangs or crashed.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>poweroff</command></term>
<listitem>
- <para>Shut down and power-off the system. This is mostly
- equivalent to <command>start poweroff.target --job-mode=replace-irreversibly</command>,
- but also prints a wall message to all users. If combined with
- <option>--force</option>, shutdown of all running services is
- skipped, however all processes are killed and all file
- systems are unmounted or mounted read-only, immediately
- followed by the powering off. If <option>--force</option> is
- specified twice, the operation is immediately executed
- without terminating any processes or unmounting any file
- systems. This may result in data loss.</para>
+ <para>Shut down and power-off the system. This is mostly equivalent to <command>start poweroff.target
+ --job-mode=replace-irreversibly</command>, but also prints a wall message to all users. If combined with
+ <option>--force</option>, shutdown of all running services is skipped, however all processes are killed and
+ all file systems are unmounted or mounted read-only, immediately followed by the powering off. If
+ <option>--force</option> is specified twice, the operation is immediately executed without terminating any
+ processes or unmounting any file systems. This may result in data loss. Note that when
+ <option>--force</option> is specified twice the power-off operation is executed by
+ <command>systemctl</command> itself, and the system manager is not contacted. This means the command should
+ succeed even when the system manager hangs or crashed.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><command>reboot <optional><replaceable>arg</replaceable></optional></command></term>
<listitem>
- <para>Shut down and reboot the system. This is mostly
- equivalent to <command>start reboot.target --job-mode=replace-irreversibly</command>,
- but also prints a wall message to all users. If combined with
- <option>--force</option>, shutdown of all running services is
- skipped, however all processes are killed and all file
- systems are unmounted or mounted read-only, immediately
- followed by the reboot. If <option>--force</option> is
- specified twice, the operation is immediately executed
- without terminating any processes or unmounting any file
- systems. This may result in data loss.</para>
+ <para>Shut down and reboot the system. This is mostly equivalent to <command>start reboot.target
+ --job-mode=replace-irreversibly</command>, but also prints a wall message to all users. If combined with
+ <option>--force</option>, shutdown of all running services is skipped, however all processes are killed and
+ all file systems are unmounted or mounted read-only, immediately followed by the reboot. If
+ <option>--force</option> is specified twice, the operation is immediately executed without terminating any
+ processes or unmounting any file systems. This may result in data loss. Note that when
+ <option>--force</option> is specified twice the reboot operation is executed by
+ <command>systemctl</command> itself, and the system manager is not contacted. This means the command should
+ succeed even when the system manager hangs or crashed.</para>
<para>If the optional argument
<replaceable>arg</replaceable> is given, it will be passed
diff --git a/src/grp-system/systemd-shutdown/Makefile b/src/grp-system/systemd-shutdown/Makefile
index 257a057823..c56f0f9adc 100644
--- a/src/grp-system/systemd-shutdown/Makefile
+++ b/src/grp-system/systemd-shutdown/Makefile
@@ -34,7 +34,7 @@ systemd_shutdown_SOURCES = \
src/core/killall.c
systemd_shutdown_LDADD = \
- libshared.la
+ libsystemd-shared.la
sd.CPPFLAGS += -DSYSTEM_SHUTDOWN_PATH=\"$(systemshutdowndir)\"
sd.CPPFLAGS += -DKEXEC=\"$(KEXEC)\"
diff --git a/src/grp-system/systemd-shutdown/shutdown.c b/src/grp-system/systemd-shutdown/shutdown.c
index bf74b5ec99..093b6eea87 100644
--- a/src/grp-system/systemd-shutdown/shutdown.c
+++ b/src/grp-system/systemd-shutdown/shutdown.c
@@ -159,7 +159,6 @@ static int switch_root_initramfs(void) {
return switch_root("/run/initramfs", "/oldroot", false, MS_BIND);
}
-
int main(int argc, char *argv[]) {
bool need_umount, need_swapoff, need_loop_detach, need_dm_detach;
bool in_container, use_watchdog = false;
@@ -205,20 +204,25 @@ int main(int argc, char *argv[]) {
}
(void) cg_get_root_path(&cgroup);
+ in_container = detect_container() > 0;
use_watchdog = !!getenv("WATCHDOG_USEC");
- /* lock us into memory */
+ /* Lock us into memory */
mlockall(MCL_CURRENT|MCL_FUTURE);
+ /* Synchronize everything that is not written to disk yet at this point already. This is a good idea so that
+ * slow IO is processed here already and the final process killing spree is not impacted by processes
+ * desperately trying to sync IO to disk within their timeout. */
+ if (!in_container)
+ sync();
+
log_info("Sending SIGTERM to remaining processes...");
broadcast_signal(SIGTERM, true, true);
log_info("Sending SIGKILL to remaining processes...");
broadcast_signal(SIGKILL, true, false);
- in_container = detect_container() > 0;
-
need_umount = !in_container;
need_swapoff = !in_container;
need_loop_detach = !in_container;
@@ -347,10 +351,10 @@ int main(int argc, char *argv[]) {
need_loop_detach ? " loop devices," : "",
need_dm_detach ? " DM devices," : "");
- /* The kernel will automaticall flush ATA disks and suchlike
- * on reboot(), but the file systems need to be synce'd
- * explicitly in advance. So let's do this here, but not
- * needlessly slow down containers. */
+ /* The kernel will automatically flush ATA disks and suchlike on reboot(), but the file systems need to be
+ * sync'ed explicitly in advance. So let's do this here, but not needlessly slow down containers. Note that we
+ * sync'ed things already once above, but we did some more work since then which might have caused IO, hence
+ * let's doit once more. */
if (!in_container)
sync();
diff --git a/src/grp-system/systemd-shutdown/systemd-shutdown.xml b/src/grp-system/systemd-shutdown/systemd-shutdown.xml
index 749158e5da..b1d1f87ce9 100644
--- a/src/grp-system/systemd-shutdown/systemd-shutdown.xml
+++ b/src/grp-system/systemd-shutdown/systemd-shutdown.xml
@@ -57,6 +57,7 @@
<para><filename>systemd-reboot.service</filename></para>
<para><filename>systemd-kexec.service</filename></para>
<para><filename>/usr/lib/systemd/systemd-shutdown</filename></para>
+ <para><filename>/usr/lib/systemd/system-shutdown/</filename></para>
</refsynopsisdiv>
<refsect1>
diff --git a/src/grp-system/systemd/Makefile b/src/grp-system/systemd/Makefile
index 3efc406281..2f9d9ac819 100644
--- a/src/grp-system/systemd/Makefile
+++ b/src/grp-system/systemd/Makefile
@@ -66,6 +66,9 @@ EXTRA_DIST += \
src/core/macros.systemd.in \
src/core/triggers.systemd.in
+dist_xinitrc_SCRIPTS = \
+ xorg/50-systemd-user.sh
+
dist_systemunit_DATA_busnames += \
units/org.freedesktop.systemd1.busname
diff --git a/src/grp-system/systemd/macros.systemd.in b/src/grp-system/systemd/macros.systemd.in
index 2cace3d3ba..6e8a3b3e3d 100644
--- a/src/grp-system/systemd/macros.systemd.in
+++ b/src/grp-system/systemd/macros.systemd.in
@@ -29,6 +29,8 @@
%_sysusersdir @sysusersdir@
%_sysctldir @sysctldir@
%_binfmtdir @binfmtdir@
+%_systemdgeneratordir @systemgeneratordir@
+%_systemdusergeneratordir @usergeneratordir@
%systemd_requires \
Requires(post): systemd \
@@ -36,6 +38,12 @@ Requires(preun): systemd \
Requires(postun): systemd \
%{nil}
+%systemd_ordering \
+OrderWithRequires(post): systemd \
+OrderWithRequires(preun): systemd \
+OrderWithRequires(postun): systemd \
+%{nil}
+
%systemd_post() \
if [ $1 -eq 1 ] ; then \
# Initial installation \
diff --git a/src/grp-system/systemd/main.c b/src/grp-system/systemd/main.c
index aa7c126fcf..c558a4b21c 100644
--- a/src/grp-system/systemd/main.c
+++ b/src/grp-system/systemd/main.c
@@ -47,7 +47,6 @@
#include "basic/def.h"
#include "basic/env-util.h"
#include "basic/fd-util.h"
-#include "basic/fdset.h"
#include "basic/fileio.h"
#include "basic/formats-util.h"
#include "basic/fs-util.h"
@@ -56,6 +55,7 @@
#include "basic/parse-util.h"
#include "basic/proc-cmdline.h"
#include "basic/process-util.h"
+#include "basic/raw-clone.h"
#include "basic/rlimit-util.h"
#include "basic/selinux-util.h"
#include "basic/signal-util.h"
@@ -81,6 +81,7 @@
#include "selinux-setup.h"
#include "shared/bus-util.h"
#include "shared/conf-parser.h"
+#include "shared/fdset.h"
#include "shared/pager.h"
#include "shared/switch-root.h"
#include "shared/watchdog.h"
@@ -126,7 +127,7 @@ static bool arg_default_io_accounting = false;
static bool arg_default_blockio_accounting = false;
static bool arg_default_memory_accounting = false;
static bool arg_default_tasks_accounting = true;
-static uint64_t arg_default_tasks_max = UINT64_C(512);
+static uint64_t arg_default_tasks_max = UINT64_MAX;
static sd_id128_t arg_machine_id = {};
noreturn static void freeze_or_reboot(void) {
@@ -162,7 +163,7 @@ noreturn static void crash(int sig) {
/* We want to wait for the core process, hence let's enable SIGCHLD */
(void) sigaction(SIGCHLD, &sa, NULL);
- pid = raw_clone(SIGCHLD, NULL);
+ pid = raw_clone(SIGCHLD);
if (pid < 0)
log_emergency_errno(errno, "Caught <%s>, cannot fork for core dump: %m", signal_to_string(sig));
else if (pid == 0) {
@@ -221,7 +222,7 @@ noreturn static void crash(int sig) {
log_notice("Executing crash shell in 10s...");
(void) sleep(10);
- pid = raw_clone(SIGCHLD, NULL);
+ pid = raw_clone(SIGCHLD);
if (pid < 0)
log_emergency_errno(errno, "Failed to fork off crash shell: %m");
else if (pid == 0) {
@@ -290,14 +291,16 @@ static int parse_crash_chvt(const char *value) {
}
static int set_machine_id(const char *m) {
+ sd_id128_t t;
assert(m);
- if (sd_id128_from_string(m, &arg_machine_id) < 0)
+ if (sd_id128_from_string(m, &t) < 0)
return -EINVAL;
- if (sd_id128_is_null(arg_machine_id))
+ if (sd_id128_is_null(t))
return -EINVAL;
+ arg_machine_id = t;
return 0;
}
@@ -408,7 +411,7 @@ static int parse_proc_cmdline_item(const char *key, const char *value) {
if (detect_container() > 0)
log_set_target(LOG_TARGET_CONSOLE);
- } else if (!in_initrd() && !value) {
+ } else if (!value) {
const char *target;
/* SysV compatibility */
@@ -1293,6 +1296,40 @@ static int bump_unix_max_dgram_qlen(void) {
return 1;
}
+static int fixup_environment(void) {
+ _cleanup_free_ char *term = NULL;
+ int r;
+
+ /* We expect the environment to be set correctly
+ * if run inside a container. */
+ if (detect_container() > 0)
+ return 0;
+
+ /* When started as PID1, the kernel uses /dev/console
+ * for our stdios and uses TERM=linux whatever the
+ * backend device used by the console. We try to make
+ * a better guess here since some consoles might not
+ * have support for color mode for example.
+ *
+ * However if TERM was configured through the kernel
+ * command line then leave it alone. */
+
+ r = get_proc_cmdline_key("TERM=", &term);
+ if (r < 0)
+ return r;
+
+ if (r == 0) {
+ term = strdup(default_term_for_tty("/dev/console") + 5);
+ if (!term)
+ return -ENOMEM;
+ }
+
+ if (setenv("TERM", term, 1) < 0)
+ return -errno;
+
+ return 0;
+}
+
int main(int argc, char *argv[]) {
Manager *m = NULL;
int r, retval = EXIT_FAILURE;
@@ -1352,7 +1389,6 @@ int main(int argc, char *argv[]) {
saved_argv = argv;
saved_argc = argc;
- log_show_color(colors_enabled());
log_set_upgrade_syslog_to_journal(true);
/* Disable the umask logic */
@@ -1363,7 +1399,6 @@ int main(int argc, char *argv[]) {
/* Running outside of a container as PID 1 */
arg_system = true;
- make_null_stdio();
log_set_target(LOG_TARGET_KMSG);
log_open();
@@ -1416,7 +1451,7 @@ int main(int argc, char *argv[]) {
/*
* Do a dummy very first call to seal the kernel's time warp magic.
*
- * Do not call this this from inside the initrd. The initrd might not
+ * Do not call this from inside the initrd. The initrd might not
* carry /etc/adjtime with LOCAL, but the real system could be set up
* that way. In such case, we need to delay the time-warp or the sealing
* until we reach the real system.
@@ -1479,6 +1514,19 @@ int main(int argc, char *argv[]) {
(void) write_string_file("/proc/sys/kernel/core_pattern", "|/bin/false", 0);
}
+ if (arg_system) {
+ if (fixup_environment() < 0) {
+ error_message = "Failed to fix up PID1 environment";
+ goto finish;
+ }
+
+ /* Try to figure out if we can use colors with the console. No
+ * need to do that for user instances since they never log
+ * into the console. */
+ log_show_color(colors_enabled());
+ make_null_stdio();
+ }
+
/* Initialize default unit */
r = free_and_strdup(&arg_default_unit, SPECIAL_DEFAULT_TARGET);
if (r < 0) {
@@ -1512,6 +1560,8 @@ int main(int argc, char *argv[]) {
(void) reset_all_signal_handlers();
(void) ignore_signals(SIGNALS_IGNORE, -1);
+ arg_default_tasks_max = system_tasks_max_scale(15U, 100U); /* 15% the system PIDs equals 4915 by default. */
+
if (parse_config_file() < 0) {
error_message = "Failed to parse config file";
goto finish;
@@ -1673,7 +1723,7 @@ int main(int argc, char *argv[]) {
status_welcome();
hostname_setup();
- machine_id_setup(NULL, arg_machine_id);
+ machine_id_setup(NULL, arg_machine_id, NULL);
loopback_setup();
bump_unix_max_dgram_qlen();
@@ -1966,6 +2016,9 @@ finish:
log_error_errno(r, "Failed to switch root, trying to continue: %m");
}
+ /* Reopen the console */
+ (void) make_console_stdio();
+
args_size = MAX(6, argc+1);
args = newa(const char*, args_size);
@@ -1991,10 +2044,6 @@ finish:
args[i++] = sfd;
args[i++] = NULL;
- /* do not pass along the environment we inherit from the kernel or initrd */
- if (switch_root_dir)
- (void) clearenv();
-
assert(i <= args_size);
/*
@@ -2017,9 +2066,6 @@ finish:
arg_serialization = safe_fclose(arg_serialization);
fds = fdset_free(fds);
- /* Reopen the console */
- (void) make_console_stdio();
-
for (j = 1, i = 1; j < (unsigned) argc; j++)
args[i++] = argv[j];
args[i++] = NULL;
diff --git a/src/grp-system/systemd/system.conf b/src/grp-system/systemd/system.conf
index db8b7acd78..c6bb050aac 100644
--- a/src/grp-system/systemd/system.conf
+++ b/src/grp-system/systemd/system.conf
@@ -42,7 +42,7 @@
#DefaultBlockIOAccounting=no
#DefaultMemoryAccounting=no
#DefaultTasksAccounting=yes
-#DefaultTasksMax=512
+#DefaultTasksMax=15%
#DefaultLimitCPU=
#DefaultLimitFSIZE=
#DefaultLimitDATA=
diff --git a/src/grp-system/systemd/systemd-system.conf.xml b/src/grp-system/systemd/systemd-system.conf.xml
index 8833e73c72..1bb40fd234 100644
--- a/src/grp-system/systemd/systemd-system.conf.xml
+++ b/src/grp-system/systemd/systemd-system.conf.xml
@@ -325,12 +325,11 @@
<varlistentry>
<term><varname>DefaultTasksMax=</varname></term>
- <listitem><para>Configure the default value for the per-unit
- <varname>TasksMax=</varname> setting. See
+ <listitem><para>Configure the default value for the per-unit <varname>TasksMax=</varname> setting. See
<citerefentry><refentrytitle>systemd.resource-control</refentrytitle><manvolnum>5</manvolnum></citerefentry>
- for details. This setting applies to all unit types that
- support resource control settings, with the exception of slice
- units. Defaults to 512.</para></listitem>
+ for details. This setting applies to all unit types that support resource control settings, with the exception
+ of slice units. Defaults to 15%, which equals 4915 with the kernel's defaults on the host, but might be smaller
+ in OS containers.</para></listitem>
</varlistentry>
<varlistentry>
diff --git a/src/grp-system/systemd/systemd.exec.xml b/src/grp-system/systemd/systemd.exec.xml
index 3cf6de8256..41ae6e76de 100644
--- a/src/grp-system/systemd/systemd.exec.xml
+++ b/src/grp-system/systemd/systemd.exec.xml
@@ -107,7 +107,8 @@
<varlistentry>
<term><varname>WorkingDirectory=</varname></term>
- <listitem><para>Takes an absolute directory path, or the
+ <listitem><para>Takes a directory path relative to the service's root
+ directory specified by <varname>RootDirectory=</varname>, or the
special value <literal>~</literal>. Sets the working directory
for executed processes. If set to <literal>~</literal>, the
home directory of the user specified in
@@ -116,7 +117,10 @@
and the respective user's home directory if run as user. If
the setting is prefixed with the <literal>-</literal>
character, a missing working directory is not considered
- fatal. Note that setting this parameter might result in
+ fatal. If <varname>RootDirectory=</varname> is not set, then
+ <varname>WorkingDirectory=</varname> is relative to the root of
+ the system running the service manager.
+ Note that setting this parameter might result in
additional dependencies to be added to the unit (see
above).</para></listitem>
</varlistentry>
@@ -124,7 +128,8 @@
<varlistentry>
<term><varname>RootDirectory=</varname></term>
- <listitem><para>Takes an absolute directory path. Sets the
+ <listitem><para>Takes a directory path relative to the host's root directory
+ (i.e. the root of the system running the service manager). Sets the
root directory for executed processes, with the <citerefentry
project='man-pages'><refentrytitle>chroot</refentrytitle><manvolnum>2</manvolnum></citerefentry>
system call. If this is used, it must be ensured that the
@@ -141,7 +146,7 @@
<listitem><para>Sets the Unix user or group that the processes
are executed as, respectively. Takes a single user or group
name or ID as argument. If no group is set, the default group
- of the user is chosen.</para></listitem>
+ of the user is chosen. These do not affect commands prefixed with <literal>+</literal>.</para></listitem>
</varlistentry>
<varlistentry>
@@ -156,7 +161,7 @@
this one will have no effect. In any way, this option does not
override, but extends the list of supplementary groups
configured in the system group database for the
- user.</para></listitem>
+ user. This does not affect commands prefixed with <literal>+</literal>.</para></listitem>
</varlistentry>
<varlistentry>
@@ -790,7 +795,8 @@
process are enforced. This option may appear more than once, in which case the bounding sets are merged. If the
empty string is assigned to this option, the bounding set is reset to the empty capability set, and all prior
settings have no effect. If set to <literal>~</literal> (without any further argument), the bounding set is
- reset to the full set of available capabilities, also undoing any previous settings.</para></listitem>
+ reset to the full set of available capabilities, also undoing any previous settings. This does not affect
+ commands prefixed with <literal>+</literal>.</para></listitem>
</varlistentry>
<varlistentry>
@@ -819,7 +825,8 @@
as a non-privileged user but still want to give it some capabilities.
Note that in this case option <constant>keep-caps</constant> is
automatically added to <varname>SecureBits=</varname> to retain the
- capabilities over the user change.</para></listitem>
+ capabilities over the user change. <varname>AmbientCapabilities=</varname> does not affect
+ commands prefixed with <literal>+</literal>.</para></listitem>
</varlistentry>
<varlistentry>
@@ -835,43 +842,46 @@
<option>noroot-locked</option>.
This option may appear more than once, in which case the secure
bits are ORed. If the empty string is assigned to this option,
- the bits are reset to 0. See
- <citerefentry project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+ the bits are reset to 0. This does not affect commands prefixed with <literal>+</literal>.
+ See <citerefentry project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
for details.</para></listitem>
</varlistentry>
<varlistentry>
- <term><varname>ReadWriteDirectories=</varname></term>
- <term><varname>ReadOnlyDirectories=</varname></term>
- <term><varname>InaccessibleDirectories=</varname></term>
+ <term><varname>ReadWritePaths=</varname></term>
+ <term><varname>ReadOnlyPaths=</varname></term>
+ <term><varname>InaccessiblePaths=</varname></term>
<listitem><para>Sets up a new file system namespace for
executed processes. These options may be used to limit access
a process might have to the main file system hierarchy. Each
- setting takes a space-separated list of absolute directory
- paths. Directories listed in
- <varname>ReadWriteDirectories=</varname> are accessible from
+ setting takes a space-separated list of paths relative to
+ the host's root directory (i.e. the system running the service manager).
+ Note that if entries contain symlinks, they are resolved from the host's root directory as well.
+ Entries (files or directories) listed in
+ <varname>ReadWritePaths=</varname> are accessible from
within the namespace with the same access rights as from
- outside. Directories listed in
- <varname>ReadOnlyDirectories=</varname> are accessible for
+ outside. Entries listed in
+ <varname>ReadOnlyPaths=</varname> are accessible for
reading only, writing will be refused even if the usual file
- access controls would permit this. Directories listed in
- <varname>InaccessibleDirectories=</varname> will be made
+ access controls would permit this. Entries listed in
+ <varname>InaccessiblePaths=</varname> will be made
inaccessible for processes inside the namespace, and may not
countain any other mountpoints, including those specified by
- <varname>ReadWriteDirectories=</varname> or
- <varname>ReadOnlyDirectories=</varname>.
+ <varname>ReadWritePaths=</varname> or
+ <varname>ReadOnlyPaths=</varname>.
Note that restricting access with these options does not extend
- to submounts of a directory that are created later on. These
+ to submounts of a directory that are created later on.
+ Non-directory paths can be specified as well. These
options may be specified more than once, in which case all
- directories listed will have limited access from within the
+ paths listed will have limited access from within the
namespace. If the empty string is assigned to this option, the
specific list is reset, and all prior assignments have no
effect.</para>
<para>Paths in
- <varname>ReadOnlyDirectories=</varname>
+ <varname>ReadOnlyPaths=</varname>
and
- <varname>InaccessibleDirectories=</varname>
+ <varname>InaccessiblePaths=</varname>
may be prefixed with
<literal>-</literal>, in which case
they will be ignored when they do not
@@ -1026,9 +1036,9 @@
<varname>PrivateDevices=</varname>,
<varname>ProtectSystem=</varname>,
<varname>ProtectHome=</varname>,
- <varname>ReadOnlyDirectories=</varname>,
- <varname>InaccessibleDirectories=</varname> and
- <varname>ReadWriteDirectories=</varname>) require that mount
+ <varname>ReadOnlyPaths=</varname>,
+ <varname>InaccessiblePaths=</varname> and
+ <varname>ReadWritePaths=</varname>) require that mount
and unmount propagation from the unit's file system namespace
is disabled, and hence downgrade <option>shared</option> to
<option>slave</option>. </para></listitem>
@@ -1091,8 +1101,8 @@
domain transition. However, the policy still needs to
authorize the transition. This directive is ignored if SELinux
is disabled. If prefixed by <literal>-</literal>, all errors
- will be ignored. See
- <citerefentry project='die-net'><refentrytitle>setexeccon</refentrytitle><manvolnum>3</manvolnum></citerefentry>
+ will be ignored. This does not affect commands prefixed with <literal>+</literal>.
+ See <citerefentry project='die-net'><refentrytitle>setexeccon</refentrytitle><manvolnum>3</manvolnum></citerefentry>
for details.</para></listitem>
</varlistentry>
@@ -1104,7 +1114,7 @@
Profiles must already be loaded in the kernel, or the unit
will fail. This result in a non operation if AppArmor is not
enabled. If prefixed by <literal>-</literal>, all errors will
- be ignored. </para></listitem>
+ be ignored. This does not affect commands prefixed with <literal>+</literal>.</para></listitem>
</varlistentry>
<varlistentry>
@@ -1123,7 +1133,8 @@
<para>The value may be prefixed by <literal>-</literal>, in
which case all errors will be ignored. An empty value may be
- specified to unset previous assignments.</para>
+ specified to unset previous assignments. This does not affect
+ commands prefixed with <literal>+</literal>.</para>
</listitem>
</varlistentry>
@@ -1160,7 +1171,7 @@
effect is inverted: only the listed system calls will result
in immediate process termination (blacklisting). If running in
user mode, or in system mode, but without the
- <constant>CAP_SYS_ADMIN</constant> capabiblity (e.g. setting
+ <constant>CAP_SYS_ADMIN</constant> capability (e.g. setting
<varname>User=nobody</varname>),
<varname>NoNewPrivileges=yes</varname> is implied. This
feature makes use of the Secure Computing Mode 2 interfaces of
@@ -1174,7 +1185,7 @@
listed explicitly. This option may be specified more than once,
in which case the filter masks are merged. If the empty string
is assigned, the filter is reset, all prior assignments will
- have no effect.</para>
+ have no effect. This does not affect commands prefixed with <literal>+</literal>.</para>
<para>If you specify both types of this option (i.e.
whitelisting and blacklisting), the first encountered will
@@ -1187,7 +1198,84 @@
<function>read</function> and <function>write</function>, and
right after it add a blacklisting of
<function>write</function>, then <function>write</function>
- will be removed from the set.) </para></listitem>
+ will be removed from the set.)</para>
+
+ <para>As the number of possible system
+ calls is large, predefined sets of system calls are provided.
+ A set starts with <literal>@</literal> character, followed by
+ name of the set.
+
+ <table>
+ <title>Currently predefined system call sets</title>
+
+ <tgroup cols='2'>
+ <colspec colname='set' />
+ <colspec colname='description' />
+ <thead>
+ <row>
+ <entry>Set</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry>@clock</entry>
+ <entry>System calls for changing the system clock (<citerefentry project='man-pages'><refentrytitle>adjtimex</refentrytitle><manvolnum>2</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>settimeofday</refentrytitle><manvolnum>2</manvolnum></citerefentry>, and related calls)</entry>
+ </row>
+ <row>
+ <entry>@cpu-emulation</entry>
+ <entry>System calls for CPU emulation functionality (<citerefentry project='man-pages'><refentrytitle>vm86</refentrytitle><manvolnum>2</manvolnum></citerefentry> and related calls)</entry>
+ </row>
+ <row>
+ <entry>@debug</entry>
+ <entry>Debugging, performance monitoring and tracing functionality (<citerefentry project='man-pages'><refentrytitle>ptrace</refentrytitle><manvolnum>2</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>perf_event_open</refentrytitle><manvolnum>2</manvolnum></citerefentry> and related calls)</entry>
+ </row>
+ <row>
+ <entry>@io-event</entry>
+ <entry>Event loop system calls (<citerefentry project='man-pages'><refentrytitle>poll</refentrytitle><manvolnum>2</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>select</refentrytitle><manvolnum>2</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>epoll</refentrytitle><manvolnum>7</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>eventfd</refentrytitle><manvolnum>2</manvolnum></citerefentry> and related calls)</entry>
+ </row>
+ <row>
+ <entry>@ipc</entry>
+ <entry>SysV IPC, POSIX Message Queues or other IPC (<citerefentry project='man-pages'><refentrytitle>mq_overview</refentrytitle><manvolnum>7</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>svipc</refentrytitle><manvolnum>7</manvolnum></citerefentry>)</entry>
+ </row>
+ <row>
+ <entry>@keyring</entry>
+ <entry>Kernel keyring access (<citerefentry project='man-pages'><refentrytitle>keyctl</refentrytitle><manvolnum>2</manvolnum></citerefentry> and related calls)</entry>
+ </row>
+ <row>
+ <entry>@module</entry>
+ <entry>Kernel module control (<citerefentry project='man-pages'><refentrytitle>init_module</refentrytitle><manvolnum>2</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>delete_module</refentrytitle><manvolnum>2</manvolnum></citerefentry> and related calls)</entry>
+ </row>
+ <row>
+ <entry>@mount</entry>
+ <entry>File system mounting and unmounting (<citerefentry project='man-pages'><refentrytitle>mount</refentrytitle><manvolnum>2</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>chroot</refentrytitle><manvolnum>2</manvolnum></citerefentry>, and related calls)</entry>
+ </row>
+ <row>
+ <entry>@network-io</entry>
+ <entry>Socket I/O (including local AF_UNIX): <citerefentry project='man-pages'><refentrytitle>socket</refentrytitle><manvolnum>7</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>unix</refentrytitle><manvolnum>7</manvolnum></citerefentry></entry>
+ </row>
+ <row>
+ <entry>@obsolete</entry>
+ <entry>Unusual, obsolete or unimplemented (<citerefentry project='man-pages'><refentrytitle>create_module</refentrytitle><manvolnum>2</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>gtty</refentrytitle><manvolnum>2</manvolnum></citerefentry>, …)</entry>
+ </row>
+ <row>
+ <entry>@privileged</entry>
+ <entry>All system calls which need super-user capabilities (<citerefentry project='man-pages'><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>)</entry>
+ </row>
+ <row>
+ <entry>@process</entry>
+ <entry>Process control, execution, namespaces (<citerefentry project='man-pages'><refentrytitle>execve</refentrytitle><manvolnum>2</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>kill</refentrytitle><manvolnum>2</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>namespaces</refentrytitle><manvolnum>7</manvolnum></citerefentry>, …</entry>
+ </row>
+ <row>
+ <entry>@raw-io</entry>
+ <entry>Raw I/O port access (<citerefentry project='man-pages'><refentrytitle>ioperm</refentrytitle><manvolnum>2</manvolnum></citerefentry>, <citerefentry project='man-pages'><refentrytitle>iopl</refentrytitle><manvolnum>2</manvolnum></citerefentry>, <function>pciconfig_read()</function>, …</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ Note, that as new system calls are added to the kernel, additional system calls might be added to the groups
+ above, so the contents of the sets may change between systemd versions.</para></listitem>
</varlistentry>
<varlistentry>
@@ -1222,7 +1310,7 @@
more strictly: to the architecture the system manager is
compiled for). If running in user mode, or in system mode,
but without the <constant>CAP_SYS_ADMIN</constant>
- capabiblity (e.g. setting <varname>User=nobody</varname>),
+ capability (e.g. setting <varname>User=nobody</varname>),
<varname>NoNewPrivileges=yes</varname> is implied. Note
that setting this option to a non-empty list implies that
<constant>native</constant> is included too. By default, this
@@ -1254,7 +1342,7 @@
has no effect on 32-bit x86 and is ignored (but works
correctly on x86-64). If running in user mode, or in system
mode, but without the <constant>CAP_SYS_ADMIN</constant>
- capabiblity (e.g. setting <varname>User=nobody</varname>),
+ capability (e.g. setting <varname>User=nobody</varname>),
<varname>NoNewPrivileges=yes</varname> is implied. By
default, no restriction applies, all address families are
accessible to processes. If assigned the empty string, any
@@ -1266,7 +1354,7 @@
family should be included in the configured whitelist as it is
frequently used for local communication, including for
<citerefentry><refentrytitle>syslog</refentrytitle><manvolnum>2</manvolnum></citerefentry>
- logging.</para></listitem>
+ logging. This does not affect commands prefixed with <literal>+</literal>.</para></listitem>
</varlistentry>
<varlistentry>
@@ -1311,6 +1399,35 @@
<citerefentry><refentrytitle>tmpfiles.d</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>MemoryDenyWriteExecute=</varname></term>
+
+ <listitem><para>Takes a boolean argument. If set, attempts to create memory mappings that are writable and
+ executable at the same time, or to change existing memory mappings to become executable are prohibited.
+ Specifically, a system call filter is added that rejects
+ <citerefentry><refentrytitle>mmap</refentrytitle><manvolnum>2</manvolnum></citerefentry>
+ system calls with both <constant>PROT_EXEC</constant> and <constant>PROT_WRITE</constant> set
+ and <citerefentry><refentrytitle>mprotect</refentrytitle><manvolnum>2</manvolnum></citerefentry>
+ system calls with <constant>PROT_EXEC</constant> set. Note that this option is incompatible with programs
+ that generate program code dynamically at runtime, such as JIT execution engines, or programs compiled making
+ use of the code "trampoline" feature of various C compilers. This option improves service security, as it makes
+ harder for software exploits to change running code dynamically.
+ </para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>RestrictRealtime=</varname></term>
+
+ <listitem><para>Takes a boolean argument. If set, any attempts to enable realtime scheduling in a process of
+ the unit are refused. This restricts access to realtime task scheduling policies such as
+ <constant>SCHED_FIFO</constant>, <constant>SCHED_RR</constant> or <constant>SCHED_DEADLINE</constant>. See
+ <citerefentry><refentrytitle>sched</refentrytitle><manvolnum>7</manvolnum></citerefentry> for details about
+ these scheduling policies. Realtime scheduling policies may be used to monopolize CPU time for longer periods
+ of time, and may hence be used to lock up or otherwise trigger Denial-of-Service situations on the system. It
+ is hence recommended to restrict access to realtime scheduling to the few programs that actually require
+ them. Defaults to off.</para></listitem>
+ </varlistentry>
+
</variablelist>
</refsect1>
@@ -1437,6 +1554,26 @@
<citerefentry project='man-pages'><refentrytitle>termcap</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
</para></listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><varname>$JOURNAL_STREAM</varname></term>
+
+ <listitem><para>If the standard output or standard error output of the executed processes are connected to the
+ journal (for example, by setting <varname>StandardError=journal</varname>) <varname>$JOURNAL_STREAM</varname>
+ contains the device and inode numbers of the connection file descriptor, formatted in decimal, separated by a
+ colon (<literal>:</literal>). This permits invoked processes to safely detect whether their standard output or
+ standard error output are connected to the journal. The device and inode numbers of the file descriptors should
+ be compared with the values set in the environment variable to determine whether the process output is still
+ connected to the journal. Note that it is generally not sufficient to only check whether
+ <varname>$JOURNAL_STREAM</varname> is set at all as services might invoke external processes replacing their
+ standard output or standard error output, without unsetting the environment variable.</para>
+
+ <para>This environment variable is primarily useful to allow services to optionally upgrade their used log
+ protocol to the native journal protocol (using
+ <citerefentry><refentrytitle>sd_journal_print</refentrytitle><manvolnum>3</manvolnum></citerefentry> and other
+ functions) if their standard output or standard error output is connected to the journal anyway, thus enabling
+ delivery of structured metadata along with logged messages.</para></listitem>
+ </varlistentry>
</variablelist>
<para>Additional variables may be configured by the following
diff --git a/src/grp-system/systemd/systemd.generator.xml b/src/grp-system/systemd/systemd.generator.xml
index 4b80dab108..b268104c9d 100644
--- a/src/grp-system/systemd/systemd.generator.xml
+++ b/src/grp-system/systemd/systemd.generator.xml
@@ -166,7 +166,7 @@
process. That includes simple things such as logging to
<citerefentry project='man-pages'><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
or <command>systemd</command> itself (this means: no
- <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>)!.
+ <citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>)!
Non-essential file systems like
<filename>/var</filename> and <filename>/home</filename>
are mounted after generators have run. Generators
@@ -309,12 +309,12 @@
<para><citerefentry><refentrytitle>systemd-system-update-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
temporarily redirects <filename>default.target</filename> to
- <filename>system-update.target</filename> if a system update is
+ <filename>system-update.target</filename>, if a system update is
scheduled. Since this needs to override the default user
configuration for <filename>default.target</filename>, it uses
argv[2]. For details about this logic, see
- <ulink url="http://www.freedesktop.org/wiki/Software/systemd/SystemUpdates">Implementing
- Offline System Updates</ulink>.</para>
+ <citerefentry><refentrytitle>systemd.offline-updates</refentrytitle><manvolnum>7</manvolnum></citerefentry>.
+ </para>
</example>
<example>
diff --git a/src/grp-system/systemd/systemd.netdev.xml b/src/grp-system/systemd/systemd.netdev.xml
index 8d12c305d2..a5c6f0fa40 100644
--- a/src/grp-system/systemd/systemd.netdev.xml
+++ b/src/grp-system/systemd/systemd.netdev.xml
@@ -124,7 +124,7 @@
<entry>An IPv4 or IPv6 tunnel over IPv6</entry></row>
<row><entry><varname>ip6gretap</varname></entry>
- <entry>An Level 2 GRE tunnel over IPv6.</entry></row>
+ <entry>A Level 2 GRE tunnel over IPv6.</entry></row>
<row><entry><varname>ipip</varname></entry>
<entry>An IPv4 over IPv4 tunnel.</entry></row>
@@ -161,6 +161,10 @@
<row><entry><varname>vxlan</varname></entry>
<entry>A virtual extensible LAN (vxlan), for connecting Cloud computing deployments.</entry></row>
+
+ <row><entry><varname>vrf</varname></entry>
+ <entry>A Virtual Routing and Forwarding (<ulink url="https://www.kernel.org/doc/Documentation/networking/vrf.txt">VRF</ulink>) interface to create separate routing and forwarding domains.</entry></row>
+
</tbody>
</tgroup>
</table>
@@ -330,6 +334,15 @@
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>VLANFiltering=</varname></term>
+ <listitem>
+ <para>A boolean. This setting controls the IFLA_BR_VLAN_FILTERING option in the kernel.
+ If enabled, the bridge will be started in VLAN-filtering mode. When unset, the kernel's
+ default setting applies.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
</refsect1>
@@ -630,6 +643,33 @@
</listitem>
</varlistentry>
<varlistentry>
+ <term><varname>Key=</varname></term>
+ <listitem>
+ <para>The <varname>Key=</varname> parameter specifies the same key to use in
+ both directions (<varname>InputKey=</varname> and <varname>OutputKey=</varname>).
+ The <varname>Key=</varname> is either a number or an IPv4 address-like dotted quad.
+ It is used as mark-configured SAD/SPD entry as part of the lookup key (both in data
+ and control path) in ip xfrm (framework used to implement IPsec protocol).
+ See <ulink url="http://man7.org/linux/man-pages/man8/ip-xfrm.8.html">
+ ip-xfrm — transform configuration</ulink> for details. It is only used for VTI/VTI6
+ tunnels.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>InputKey=</varname></term>
+ <listitem>
+ <para>The <varname>InputKey=</varname> parameter specifies the key to use for input.
+ The format is same as <varname>Key=</varname>. It is only used for VTI/VTI6 tunnels.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>OutputKey=</varname></term>
+ <listitem>
+ <para>The <varname>OutputKey=</varname> parameter specifies the key to use for output.
+ The format is same as <varname>Key=</varname>. It is only used for VTI/VTI6 tunnels.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term><varname>Mode=</varname></term>
<listitem>
<para>An <literal>ip6tnl</literal> tunnel can be in one of three
@@ -768,8 +808,7 @@
<literal>layer2</literal>,
<literal>layer3+4</literal>,
<literal>layer2+3</literal>,
- <literal>encap2+3</literal>,
- <literal>802.3ad</literal>, and
+ <literal>encap2+3</literal>, and
<literal>encap3+4</literal>.
</para>
</listitem>
@@ -1101,7 +1140,16 @@ Name=dummy-test
Kind=dummy
MACAddress=12:34:56:78:9a:bc</programlisting>
</example>
+ <example>
+ <title>/etc/systemd/network/25-vrf.netdev</title>
+ <para>Create a VRF interface with table 42.</para>
+ <programlisting>[NetDev]
+Name=vrf-test
+Kind=vrf
+[VRF]
+TableId=42</programlisting>
+ </example>
</refsect1>
<refsect1>
<title>See Also</title>
diff --git a/src/grp-system/systemd/systemd.network.xml b/src/grp-system/systemd/systemd.network.xml
index 821e22aff8..4541a55490 100644
--- a/src/grp-system/systemd/systemd.network.xml
+++ b/src/grp-system/systemd/systemd.network.xml
@@ -240,7 +240,7 @@
By enabling DHCPv6 support explicitly, the DHCPv6 client will
be started regardless of the presence of routers on the link,
or what flags the routers pass. See
- <literal>IPv6AcceptRouterAdvertisements=</literal>.</para>
+ <literal>IPv6AcceptRA=</literal>.</para>
<para>Furthermore, note that by default the domain name
specified through DHCP is not used for name resolution.
@@ -527,24 +527,20 @@
<literal>no</literal>.</para></listitem>
</varlistentry>
<varlistentry>
- <term><varname>IPv6AcceptRouterAdvertisements=</varname></term>
- <listitem><para>Force the setting of the <filename>accept_ra</filename>
- (router advertisements) setting for the interface.
- When unset, the kernel default is used, and router
- advertisements are accepted only when local forwarding
- is disabled for that interface.
- When router advertisements are accepted, they will
- trigger the start of the DHCPv6 client if the relevant
- flags are passed, or if no routers are found on the link.
- Takes a boolean. If true, router advertisements are
- accepted, when false, router advertisements are ignored,
- independently of the local forwarding state.</para>
-
- <para>See
- <ulink url="https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt">ip-sysctl.txt</ulink>
- in the kernel documentation, but note that systemd's
- setting of <constant>1</constant> corresponds to
- kernel's setting of <constant>2</constant>.</para>
+ <term><varname>IPv6AcceptRA=</varname></term>
+ <listitem><para>Enable or disable IPv6 Router Advertisement (RA) reception support for the interface. Takes
+ a boolean parameter. If true, RAs are accepted; if false, RAs are ignored, independently of the local
+ forwarding state. When not set, the kernel default is used, and RAs are accepted only when local forwarding
+ is disabled for that interface. When RAs are accepted, they may trigger the start of the DHCPv6 client if
+ the relevant flags are set in the RA data, or if no routers are found on the link.</para>
+
+ <para>Further settings for the IPv6 RA support may be configured in the
+ <literal>[IPv6AcceptRA]</literal> section, see below.</para>
+
+ <para>Also see <ulink
+ url="https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt">ip-sysctl.txt</ulink> in the kernel
+ documentation regarding <literal>accept_ra</literal>, but note that systemd's setting of
+ <constant>1</constant> (i.e. true) corresponds to kernel's setting of <constant>2</constant>.</para>
</listitem>
</varlistentry>
<varlistentry>
@@ -583,6 +579,12 @@
</listitem>
</varlistentry>
<varlistentry>
+ <term><varname>VRF=</varname></term>
+ <listitem>
+ <para>The name of the VRF to add the link to.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term><varname>VLAN=</varname></term>
<listitem>
<para>The name of a VLAN to create on the link. This
@@ -799,7 +801,7 @@
false.</para>
<para>It is recommended to enable this option only on trusted networks, as setting this affects resolution
- of all host names, in particular to single-label names. It is generally safer to use the supplied domain
+ of all host names, in particular of single-label names. It is generally safer to use the supplied domain
only as routing domain, rather than as search domain, in order to not have it affect local resolution of
single-label names.</para>
@@ -839,7 +841,7 @@
<term><varname>ClientIdentifier=</varname></term>
<listitem>
<para>The DHCPv4 client identifier to use. Either <literal>mac</literal> to use the MAC address of the link
- or <literal>duid</literal> (the default, see below) to use a RFC4361-compliant Client ID.</para>
+ or <literal>duid</literal> (the default, see below) to use an RFC4361-compliant Client ID.</para>
</listitem>
</varlistentry>
@@ -899,6 +901,47 @@
</refsect1>
<refsect1>
+ <title>[IPv6AcceptRA] Section Options</title>
+ <para>The <literal>[IPv6AcceptRA]</literal> section configures the IPv6 Router Advertisement
+ (RA) client, if it is enabled with the <varname>IPv6AcceptRA=</varname> setting described
+ above:</para>
+
+ <variablelist class='network-directives'>
+ <varlistentry>
+ <term><varname>UseDNS=</varname></term>
+ <listitem>
+ <para>When true (the default), the DNS servers received in the Router Advertisement will be used and take
+ precedence over any statically configured ones.</para>
+
+ <para>This corresponds to the <option>nameserver</option> option in <citerefentry
+ project='man-pages'><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>UseDomains=</varname></term>
+ <listitem>
+ <para>Takes a boolean argument, or the special value <literal>route</literal>. When true, the domain name
+ received via IPv6 Router Advertisement (RA) will be used as DNS search domain over this link, similar to
+ the effect of the <option>Domains=</option> setting. If set to <literal>route</literal>, the domain name
+ received via IPv6 RA will be used for routing DNS queries only, but not for searching, similar to the
+ effect of the <option>Domains=</option> setting when the argument is prefixed with
+ <literal>~</literal>. Defaults to false.</para>
+
+ <para>It is recommended to enable this option only on trusted networks, as setting this affects resolution
+ of all host names, in particular of single-label names. It is generally safer to use the supplied domain
+ only as routing domain, rather than as search domain, in order to not have it affect local resolution of
+ single-label names.</para>
+
+ <para>When set to true, this setting corresponds to the <option>domain</option> option in <citerefentry
+ project='man-pages'><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+
+ <refsect1>
<title>[DHCPServer] Section Options</title>
<para>The <literal>[DHCPServer]</literal> section contains
settings for the DHCP server, if enabled via the
@@ -1093,6 +1136,39 @@
</varlistentry>
</variablelist>
</refsect1>
+ <refsect1>
+ <title>[BridgeVLAN] Section Options</title>
+ <para>The <literal>[BridgeVLAN]</literal> section manages the VLAN ID configuration of a bridge port and accepts
+ the following keys. Specify several <literal>[BridgeVLAN]</literal> sections to configure several VLAN entries.
+ The <varname>VLANFiltering=</varname> option has to be enabled, see <literal>[Bridge]</literal> section in
+ <citerefentry><refentrytitle>systemd.netdev</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+
+ <variablelist class='network-directives'>
+ <varlistentry>
+ <term><varname>VLAN=</varname></term>
+ <listitem>
+ <para>The VLAN ID allowed on the port. This can be either a single ID or a range M-N. VLAN IDs are valid
+ from 1 to 4094.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>EgressUntagged=</varname></term>
+ <listitem>
+ <para>The VLAN ID specified here will be used to untag frames on egress. Configuring
+ <varname>EgressUntagged=</varname> implicates the use of <varname>VLAN=</varname> above and will enable the
+ VLAN ID for ingress as well. This can be either a single ID or a range M-N.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><varname>PVID=</varname></term>
+ <listitem>
+ <para>The Port VLAN ID specified here is assigned to all untagged frames at ingress.
+ <varname>PVID=</varname> can be used only once. Configuring <varname>PVID=</varname> implicates the use of
+ <varname>VLAN=</varname> above and will enable the VLAN ID for ingress as well.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
<refsect1>
<title>Example</title>
@@ -1139,6 +1215,26 @@ Name=enp2s0
Bridge=bridge0</programlisting>
</example>
<example>
+ <title>/etc/systemd/network/25-bridge-slave-interface-vlan.network</title>
+
+ <programlisting>[Match]
+Name=enp2s0
+
+[Network]
+Bridge=bridge0
+
+[BridgeVLAN]
+VLAN=1-32
+PVID=42
+EgressUntagged=42
+
+[BridgeVLAN]
+VLAN=100-200
+
+[BridgeVLAN]
+EgressUntagged=300-400</programlisting>
+ </example>
+ <example>
<title>/etc/systemd/network/25-ipip.network</title>
<programlisting>[Match]
@@ -1189,6 +1285,17 @@ DHCP=yes
</programlisting>
</example>
+ <example>
+ <title>/etc/systemd/network/25-vrf.network</title>
+ <para>Add the bond1 interface to the VRF master interface vrf-test. This will redirect routes generated on this interface to be within the routing table defined during VRF creation. Traffic won't be redirected towards the VRFs routing table unless specific ip-rules are added.</para>
+ <programlisting>[Match]
+Name=bond1
+
+[Network]
+VRF=vrf-test
+</programlisting>
+ </example>
+
</refsect1>
<refsect1>
diff --git a/src/grp-system/systemd/systemd.nspawn.xml b/src/grp-system/systemd/systemd.nspawn.xml
index 3683412c14..b1344d6c10 100644
--- a/src/grp-system/systemd/systemd.nspawn.xml
+++ b/src/grp-system/systemd/systemd.nspawn.xml
@@ -146,7 +146,8 @@
specified parameters using <varname>Parameters=</varname> are passed as additional arguments to the
<filename>init</filename> process. This setting corresponds to the <option>--boot</option> switch on the
<command>systemd-nspawn</command> command line. This option may not be combined with
- <varname>ProcessTwo=yes</varname>.</para></listitem>
+ <varname>ProcessTwo=yes</varname>. This option is the default if the
+ <filename>systemd-nspawn@.service</filename> template unit file is used.</para></listitem>
</varlistentry>
<varlistentry>
@@ -257,7 +258,17 @@
<listitem><para>Configures support for usernamespacing. This is equivalent to the
<option>--private-users=</option> command line switch, and takes the same options. This option is privileged
- (see above). </para></listitem>
+ (see above). This option is the default if the <filename>systemd-nspawn@.service</filename> template unit file
+ is used.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>NotifyReady=</varname></term>
+
+ <listitem><para>Configures support for notifications from the container's init process.
+ This is equivalent to use <option>--notify-ready=</option> command line switch,
+ and takes the same options. See <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ for details about the specific options supported.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
@@ -358,13 +369,11 @@
<varlistentry>
<term><varname>VirtualEthernet=</varname></term>
- <listitem><para>Takes a boolean argument. Configures whether
- to create a virtual Ethernet connection
- (<literal>veth</literal>) between host and the container. This
- setting implies <varname>Private=yes</varname>. This setting
- corresponds to the <option>--network-veth</option> command
- line switch. This option is privileged (see
- above).</para></listitem>
+ <listitem><para>Takes a boolean argument. Configures whether to create a virtual Ethernet connection
+ (<literal>veth</literal>) between host and the container. This setting implies
+ <varname>Private=yes</varname>. This setting corresponds to the <option>--network-veth</option> command line
+ switch. This option is privileged (see above). This option is the default if the
+ <filename>systemd-nspawn@.service</filename> template unit file is used.</para></listitem>
</varlistentry>
<varlistentry>
diff --git a/src/grp-system/systemd/systemd.offline-updates.xml b/src/grp-system/systemd/systemd.offline-updates.xml
index 946234ad90..ae53b8552d 100644
--- a/src/grp-system/systemd/systemd.offline-updates.xml
+++ b/src/grp-system/systemd/systemd.offline-updates.xml
@@ -93,7 +93,7 @@
<listitem>
<para>As the first step, the update script should check if the
- <filename>/system-update</filename> symlink points to the the location used by that update
+ <filename>/system-update</filename> symlink points to the location used by that update
script. In case it does not exists or points to a different location, the script must exit
without error. It is possible for multiple update services to be installed, and for multiple
update scripts to be launched in parallel, and only the one that corresponds to the tool
diff --git a/src/grp-system/systemd/systemd.resource-control.xml b/src/grp-system/systemd/systemd.resource-control.xml
index 066f2cc19b..bf44a68345 100644
--- a/src/grp-system/systemd/systemd.resource-control.xml
+++ b/src/grp-system/systemd/systemd.resource-control.xml
@@ -92,16 +92,14 @@
<refsect1>
<title>Automatic Dependencies</title>
- <para>Units with the <varname>Slice=</varname> setting set get
- automatic <varname>Requires=</varname> and
- <varname>After=</varname> dependencies on the specified slice
- unit.</para>
+ <para>Units with the <varname>Slice=</varname> setting set automatically acquire <varname>Requires=</varname> and
+ <varname>After=</varname> dependencies on the specified slice unit.</para>
</refsect1>
<refsect1>
<title>Unified and Legacy Control Group Hierarchies</title>
- <para>Unified control group hierarchy is the new version of kernel control group interface. Depending on the
+ <para>The unified control group hierarchy is the new version of kernel control group interface. Depending on the
resource type, there are differences in resource control capabilities. Also, because of interface changes, some
resource types have a separate set of options on the unified hierarchy.</para>
@@ -114,6 +112,13 @@
prefixed ones. On unified hierarchy, IO resource control also applies to buffered writes.</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>Memory</option></term>
+ <listitem>
+ <para><varname>MemoryMax=</varname> replaces <varname>MemoryLimit=</varname>. <varname>MemoryLow=</varname>
+ and <varname>MemoryHigh=</varname> are effective only on unified hierarchy.</para>
+ </listitem>
+ </varlistentry>
</variablelist>
</para>
@@ -213,23 +218,89 @@
</varlistentry>
<varlistentry>
+ <term><varname>MemoryLow=<replaceable>bytes</replaceable></varname></term>
+
+ <listitem>
+ <para>Specify the best-effort memory usage protection of the executed processes in this unit. If the memory
+ usages of this unit and all its ancestors are below their low boundaries, this unit's memory won't be
+ reclaimed as long as memory can be reclaimed from unprotected units.</para>
+
+ <para>Takes a memory size in bytes. If the value is suffixed with K, M, G or T, the specified memory size is
+ parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. Alternatively, a
+ percentage value may be specified, which is taken relative to the installed physical memory on the
+ system. This controls the <literal>memory.low</literal> control group attribute. For details about this
+ control group attribute, see <ulink
+ url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink>.</para>
+
+ <para>Implies <literal>MemoryAccounting=true</literal>.</para>
+
+ <para>This setting is supported only if the unified control group hierarchy is used.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>MemoryHigh=<replaceable>bytes</replaceable></varname></term>
+
+ <listitem>
+ <para>Specify the high limit on memory usage of the executed processes in this unit. Memory usage may go
+ above the limit if unavoidable, but the processes are heavily slowed down and memory is taken away
+ aggressively in such cases. This is the main mechanism to control memory usage of a unit.</para>
+
+ <para>Takes a memory size in bytes. If the value is suffixed with K, M, G or T, the specified memory size is
+ parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. Alternatively, a
+ percentage value may be specified, which is taken relative to the installed physical memory on the
+ system. If assigned the
+ special value <literal>infinity</literal>, no memory limit is applied. This controls the
+ <literal>memory.high</literal> control group attribute. For details about this control group attribute, see
+ <ulink url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink>.</para>
+
+ <para>Implies <literal>MemoryAccounting=true</literal>.</para>
+
+ <para>This setting is supported only if the unified control group hierarchy is used.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>MemoryMax=<replaceable>bytes</replaceable></varname></term>
+
+ <listitem>
+ <para>Specify the absolute limit on memory usage of the executed processes in this unit. If memory usage
+ cannot be contained under the limit, out-of-memory killer is invoked inside the unit. It is recommended to
+ use <varname>MemoryHigh=</varname> as the main control mechanism and use <varname>MemoryMax=</varname> as the
+ last line of defense.</para>
+
+ <para>Takes a memory size in bytes. If the value is suffixed with K, M, G or T, the specified memory size is
+ parsed as Kilobytes, Megabytes, Gigabytes, or Terabytes (with the base 1024), respectively. Alternatively, a
+ percentage value may be specified, which is taken relative to the installed physical memory on the system. If
+ assigned the special value <literal>infinity</literal>, no memory limit is applied. This controls the
+ <literal>memory.max</literal> control group attribute. For details about this control group attribute, see
+ <ulink url="https://www.kernel.org/doc/Documentation/cgroup-v2.txt">cgroup-v2.txt</ulink>.</para>
+
+ <para>Implies <literal>MemoryAccounting=true</literal>.</para>
+
+ <para>This setting is supported only if the unified control group hierarchy is used. Use
+ <varname>MemoryLimit=</varname> on systems using the legacy control group hierarchy.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><varname>MemoryLimit=<replaceable>bytes</replaceable></varname></term>
<listitem>
- <para>Specify the limit on maximum memory usage of the
- executed processes. The limit specifies how much process and
- kernel memory can be used by tasks in this unit. Takes a
- memory size in bytes. If the value is suffixed with K, M, G
- or T, the specified memory size is parsed as Kilobytes,
- Megabytes, Gigabytes, or Terabytes (with the base 1024),
- respectively. If assigned the special value
- <literal>infinity</literal>, no memory limit is applied. This
- controls the <literal>memory.limit_in_bytes</literal>
- control group attribute. For details about this control
- group attribute, see <ulink
+ <para>Specify the limit on maximum memory usage of the executed processes. The limit specifies how much
+ process and kernel memory can be used by tasks in this unit. Takes a memory size in bytes. If the value is
+ suffixed with K, M, G or T, the specified memory size is parsed as Kilobytes, Megabytes, Gigabytes, or
+ Terabytes (with the base 1024), respectively. Alternatively, a percentage value may be specified, which is
+ taken relative to the installed physical memory on the system. If assigned the special value
+ <literal>infinity</literal>, no memory limit is applied. This controls the
+ <literal>memory.limit_in_bytes</literal> control group attribute. For details about this control group
+ attribute, see <ulink
url="https://www.kernel.org/doc/Documentation/cgroup-v1/memory.txt">memory.txt</ulink>.</para>
<para>Implies <literal>MemoryAccounting=true</literal>.</para>
+
+ <para>This setting is supported only if the legacy control group hierarchy is used. Use
+ <varname>MemoryMax=</varname> on systems using the unified control group hierarchy.</para>
</listitem>
</varlistentry>
@@ -256,15 +327,12 @@
<term><varname>TasksMax=<replaceable>N</replaceable></varname></term>
<listitem>
- <para>Specify the maximum number of tasks that may be
- created in the unit. This ensures that the number of tasks
- accounted for the unit (see above) stays below a specific
- limit. If assigned the special value
- <literal>infinity</literal>, no tasks limit is applied. This
- controls the <literal>pids.max</literal> control group
- attribute. For details about this control group attribute,
- see <ulink
- url="https://www.kernel.org/doc/Documentation/cgroup-v1/pids.txt">pids.txt</ulink>.</para>
+ <para>Specify the maximum number of tasks that may be created in the unit. This ensures that the number of
+ tasks accounted for the unit (see above) stays below a specific limit. This either takes an absolute number
+ of tasks or a percentage value that is taken relative to the configured maximum number of tasks on the
+ system. If assigned the special value <literal>infinity</literal>, no tasks limit is applied. This controls
+ the <literal>pids.max</literal> control group attribute. For details about this control group attribute, see
+ <ulink url="https://www.kernel.org/doc/Documentation/cgroup-v1/pids.txt">pids.txt</ulink>.</para>
<para>Implies <literal>TasksAccounting=true</literal>. The
system default for this setting may be controlled with
diff --git a/src/grp-system/systemd/systemd.service.xml b/src/grp-system/systemd/systemd.service.xml
index 6641dfed4f..875d368fcf 100644
--- a/src/grp-system/systemd/systemd.service.xml
+++ b/src/grp-system/systemd/systemd.service.xml
@@ -202,8 +202,9 @@
notification message has been sent. If this option is used,
<varname>NotifyAccess=</varname> (see below) should be set to
open access to the notification socket provided by systemd. If
- <varname>NotifyAccess=</varname> is not set, it will be
- implicitly set to <option>main</option>. Note that currently
+ <varname>NotifyAccess=</varname> is missing or set to
+ <option>none</option>, it will be forcibly set to
+ <option>main</option>. Note that currently
<varname>Type=</varname><option>notify</option> will not work
if used in combination with
<varname>PrivateNetwork=</varname><option>yes</option>.</para>
@@ -287,17 +288,14 @@
<varname>ExecStart=</varname> is specified, then the service
must have <varname>RemainAfterExit=yes</varname> set.</para>
- <para>For each of the specified commands, the first argument
- must be an absolute path to an executable. Optionally, if this
- file name is prefixed with <literal>@</literal>, the second
- token will be passed as <literal>argv[0]</literal> to the
- executed process, followed by the further arguments specified.
- If the absolute filename is prefixed with
- <literal>-</literal>, an exit code of the command normally
- considered a failure (i.e. non-zero exit status or abnormal
- exit due to signal) is ignored and considered success. If both
- <literal>-</literal> and <literal>@</literal> are used, they
- can appear in either order.</para>
+ <para>For each of the specified commands, the first argument must be an absolute path to an
+ executable. Optionally, if this file name is prefixed with <literal>@</literal>, the second token will be
+ passed as <literal>argv[0]</literal> to the executed process, followed by the further arguments specified. If
+ the absolute filename is prefixed with <literal>-</literal>, an exit code of the command normally considered a
+ failure (i.e. non-zero exit status or abnormal exit due to signal) is ignored and considered success. If the
+ absolute path is prefixed with <literal>+</literal> then it is executed with full
+ privileges. <literal>-</literal>, <literal>@</literal>, and <literal>+</literal> may be used together and they
+ can appear in any order.</para>
<para>If more than one command is specified, the commands are
invoked sequentially in the order they appear in the unit
diff --git a/src/grp-system/systemd/systemd.special.xml b/src/grp-system/systemd/systemd.special.xml
index 26974ed73f..18ad8f92e5 100644
--- a/src/grp-system/systemd/systemd.special.xml
+++ b/src/grp-system/systemd/systemd.special.xml
@@ -127,9 +127,9 @@
<listitem>
<para>A special target unit covering basic boot-up.</para>
- <para>systemd automatically adds dependencies of the types
- <varname>Requires=</varname> and <varname>After=</varname>
- for this target unit to all services (except for those with
+ <para>systemd automatically adds dependency of the type
+ <varname>After=</varname> for this target unit to all
+ services (except for those with
<varname>DefaultDependencies=no</varname>).</para>
<para>Usually, this should pull-in all local mount points plus
@@ -473,7 +473,7 @@
<citerefentry><refentrytitle>systemd-fstab-generator</refentrytitle><manvolnum>3</manvolnum></citerefentry>
and
<citerefentry><refentrytitle>systemd-gpt-auto-generator</refentrytitle><manvolnum>3</manvolnum></citerefentry>
- automatically setup the appropiate dependencies to make this happen.
+ automatically setup the appropriate dependencies to make this happen.
</para>
</listitem>
</varlistentry>
@@ -497,8 +497,8 @@
<para>These are targets that are called whenever the SysV
compatibility code asks for runlevel 2, 3, 4, 5,
respectively. It is a good idea to make this an alias for
- (i.e. symlink to) <filename>multi-user.target</filename>
- (for runlevel 2) or <filename>graphical.target</filename>
+ (i.e. symlink to) <filename>graphical.target</filename>
+ (for runlevel 5) or <filename>multi-user.target</filename>
(the others).</para>
</listitem>
</varlistentry>
@@ -509,8 +509,9 @@
system shutdown.</para>
<para>Services that shall be terminated on system shutdown
- shall add <varname>Conflicts=</varname> dependencies to this
- unit for their service unit, which is implicitly done when
+ shall add <varname>Conflicts=</varname> and
+ <varname>Before=</varname> dependencies to this unit for
+ their service unit, which is implicitly done when
<varname>DefaultDependencies=yes</varname> is set (the
default).</para>
</listitem>
@@ -579,6 +580,11 @@
<varlistentry>
<term><filename>sysinit.target</filename></term>
<listitem>
+ <para>systemd automatically adds dependencies of the types
+ <varname>Requires=</varname> and <varname>After=</varname>
+ for this target unit to all services (except for those with
+ <varname>DefaultDependencies=no</varname>).</para>
+
<para>This target pulls in the services required for system
initialization. System services pulled in by this target should
declare <varname>DefaultDependencies=no</varname> and specify
diff --git a/src/grp-system/systemd/systemd.target.xml b/src/grp-system/systemd/systemd.target.xml
index ab910d75dd..2e35e54fc4 100644
--- a/src/grp-system/systemd/systemd.target.xml
+++ b/src/grp-system/systemd/systemd.target.xml
@@ -82,11 +82,20 @@
<refsect1>
<title>Automatic Dependencies</title>
- <para>Unless <varname>DefaultDependencies=</varname> in the <literal>[Unit]</literal> section is set to
- <option>no</option>, target units will implicitly complement all configured dependencies of type
- <varname>Wants=</varname>, <varname>Requires=</varname> with dependencies of type <varname>After=</varname>, unless
- an ordering dependency of any kind between the target and the respective other unit is already in place. Note that
- this behaviour is disabled if either unit has <varname>DefaultDependencies=no</varname>.</para>
+ <para>Unless <varname>DefaultDependencies=</varname> is set to
+ <option>no</option> in either of releated units or an explicit ordering
+ dependency is already defined, target units will implicitly complement all
+ configured dependencies of type <varname>Wants=</varname> or
+ <varname>Requires=</varname> with dependencies of type
+ <varname>After=</varname>. Note that <varname>Wants=</varname> or
+ <varname>Requires=</varname> must be defined in the target unit itself — if
+ you for example define <varname>Wants=</varname>some.target in
+ some.service, the implicit ordering will not be added.</para>
+
+ <para>All target units automatically gain <varname>Conflicts=</varname>
+ dependency against shutdown.target unless <varname>DefaultDependencies=</varname>
+ is set to <option>no</option>.</para>
+
</refsect1>
<refsect1>
diff --git a/src/grp-system/systemd/systemd.time.xml b/src/grp-system/systemd/systemd.time.xml
index ffcac82263..aae3accb6c 100644
--- a/src/grp-system/systemd/systemd.time.xml
+++ b/src/grp-system/systemd/systemd.time.xml
@@ -217,8 +217,8 @@
should consist of one or more English language weekday names,
either in the abbreviated (Wed) or non-abbreviated (Wednesday)
form (case does not matter), separated by commas. Specifying two
- weekdays separated by <literal>-</literal> refers to a range of
- continuous weekdays. <literal>,</literal> and <literal>-</literal>
+ weekdays separated by <literal>..</literal> refers to a range of
+ continuous weekdays. <literal>,</literal> and <literal>..</literal>
may be combined freely.</para>
<para>In the date and time specifications, any component may be
@@ -226,8 +226,9 @@
match. Alternatively, each component can be specified as a list of
values separated by commas. Values may also be suffixed with
<literal>/</literal> and a repetition value, which indicates that
- the value and all values plus multiples of the repetition value
- are matched.</para>
+ the value itself and the value plus all multiples of the repetition value
+ are matched. Each component may also contain a range of values
+ separated by <literal>..</literal>.</para>
<para>The seconds component may contain decimal fractions both in
the value and the repetition. All fractions are rounded to 6
@@ -262,17 +263,18 @@
<para>Examples for valid timestamps and their
normalized form:</para>
-<programlisting> Sat,Thu,Mon-Wed,Sat-Sun → Mon-Thu,Sat,Sun *-*-* 00:00:00
+<programlisting> Sat,Thu,Mon..Wed,Sat..Sun → Mon..Thu,Sat,Sun *-*-* 00:00:00
Mon,Sun 12-*-* 2,1:23 → Mon,Sun 2012-*-* 01,02:23:00
Wed *-1 → Wed *-*-01 00:00:00
- Wed-Wed,Wed *-1 → Wed *-*-01 00:00:00
+ Wed..Wed,Wed *-1 → Wed *-*-01 00:00:00
Wed, 17:48 → Wed *-*-* 17:48:00
-Wed-Sat,Tue 12-10-15 1:2:3 → Tue-Sat 2012-10-15 01:02:03
+Wed..Sat,Tue 12-10-15 1:2:3 → Tue..Sat 2012-10-15 01:02:03
*-*-7 0:0:0 → *-*-07 00:00:00
10-15 → *-10-15 00:00:00
monday *-12-* 17:00 → Mon *-12-* 17:00:00
Mon,Fri *-*-3,1,2 *:30:45 → Mon,Fri *-*-01,02,03 *:30:45
12,14,13,12:20,10,30 → *-*-* 12,13,14:10,20,30:00
+ 12..14:10,20,30 → *-*-* 12,13,14:10,20,30:00
mon,fri *-1/2-1,3 *:30:45 → Mon,Fri *-01/2-01,03 *:30:45
03-05 08:05:40 → *-03-05 08:05:40
08:05:40 → *-*-* 08:05:40
@@ -281,6 +283,7 @@ Wed-Sat,Tue 12-10-15 1:2:3 → Tue-Sat 2012-10-15 01:02:03
Sat,Sun 08:05:40 → Sat,Sun *-*-* 08:05:40
2003-03-05 05:40 → 2003-03-05 05:40:00
05:40:23.4200004/3.1700005 → 05:40:23.420000/3.170001
+ 2003-02..04-05 → 2003-02,03,04-05 00:00:00
2003-03-05 05:40 UTC → 2003-03-05 05:40:00 UTC
2003-03-05 → 2003-03-05 00:00:00
03-05 → *-03-05 00:00:00
diff --git a/src/grp-system/systemd/systemd.timer.xml b/src/grp-system/systemd/systemd.timer.xml
index 0fa95e97a8..4fe140e4bc 100644
--- a/src/grp-system/systemd/systemd.timer.xml
+++ b/src/grp-system/systemd/systemd.timer.xml
@@ -76,7 +76,7 @@
<para>Note that in case the unit to activate is already active at the time the timer elapses it is not restarted,
but simply left running. There is no concept of spawning new service instances in this case. Due to this, services
- with <varname>RemainAfterExit=</varname> set (which stay around continously even after the service's main process
+ with <varname>RemainAfterExit=</varname> set (which stay around continuously even after the service's main process
exited) are usually not suitable for activation via repetitive timers, as they will only be activated once, and
then stay around forever.</para>
</refsect1>
diff --git a/src/grp-system/systemd/systemd.unit.xml b/src/grp-system/systemd/systemd.unit.xml
index 341789cd47..85a7b12d76 100644
--- a/src/grp-system/systemd/systemd.unit.xml
+++ b/src/grp-system/systemd/systemd.unit.xml
@@ -1234,7 +1234,7 @@
<row>
<entry><literal>%f</literal></entry>
<entry>Unescaped filename</entry>
- <entry>This is either the unescaped instance name (if applicable) with <filename>/</filename> prepended (if applicable), or the prefix name prepended with <filename>/</filename>.</entry>
+ <entry>This is either the unescaped instance name (if applicable) with <filename>/</filename> prepended (if applicable), or the unescaped prefix name prepended with <filename>/</filename>.</entry>
</row>
<row>
<entry><literal>%c</literal></entry>
diff --git a/src/grp-system/systemd/systemd.xml b/src/grp-system/systemd/systemd.xml
index e05a9d6e29..4f0201fc76 100644
--- a/src/grp-system/systemd/systemd.xml
+++ b/src/grp-system/systemd/systemd.xml
@@ -1024,25 +1024,27 @@
<varlistentry>
<term><varname>emergency</varname></term>
+ <term><varname>rd.emergency</varname></term>
<term><varname>-b</varname></term>
<listitem><para>Boot into emergency mode. This is equivalent
- to <varname>systemd.unit=emergency.target</varname> and
- provided for compatibility reasons and to be easier to
- type.</para></listitem>
+ to <varname>systemd.unit=emergency.target</varname> or
+ <varname>rd.systemd.unit=emergency.target</varname>, respectively, and
+ provided for compatibility reasons and to be easier to type.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>rescue</varname></term>
+ <term><varname>rd.rescue</varname></term>
<term><varname>single</varname></term>
<term><varname>s</varname></term>
<term><varname>S</varname></term>
<term><varname>1</varname></term>
<listitem><para>Boot into rescue mode. This is equivalent to
- <varname>systemd.unit=rescue.target</varname> and provided for
- compatibility reasons and to be easier to
- type.</para></listitem>
+ <varname>systemd.unit=rescue.target</varname> or
+ <varname>rd.systemd.unit=rescue.target</varname>, respectively, and
+ provided for compatibility reasons and to be easier to type.</para></listitem>
</varlistentry>
<varlistentry>