summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO7
-rw-r--r--man/systemctl.xml12
-rw-r--r--man/systemd-cgls.xml21
-rw-r--r--man/systemd.exec.xml2
-rw-r--r--shell-completion/bash/systemctl.in2
-rw-r--r--shell-completion/zsh/_systemctl.in1
-rw-r--r--src/basic/cgroup-util.c3
-rw-r--r--src/basic/copy.c2
-rw-r--r--src/basic/hexdecoct.c4
-rw-r--r--src/basic/path-util.c25
-rw-r--r--src/basic/path-util.h2
-rw-r--r--src/basic/rm-rf.c2
-rw-r--r--src/basic/socket-util.c2
-rw-r--r--src/boot/efi/boot.c2
-rw-r--r--src/boot/efi/stub.c2
-rw-r--r--src/cgls/cgls.c160
-rw-r--r--src/cgtop/cgtop.c67
-rw-r--r--src/core/execute.c62
-rw-r--r--src/core/killall.c29
-rw-r--r--src/core/timer.c2
-rw-r--r--src/cryptsetup/cryptsetup.c4
-rw-r--r--src/gpt-auto-generator/gpt-auto-generator.c2
-rw-r--r--src/journal/journal-file.c84
-rw-r--r--src/journal/journalctl.c4
-rw-r--r--src/login/loginctl.c25
-rw-r--r--src/login/logind-dbus.c10
-rw-r--r--src/machine/machinectl.c24
-rw-r--r--src/nspawn/nspawn-patch-uid.c2
-rw-r--r--src/resolve/resolved-manager.c2
-rw-r--r--src/shared/cgroup-show.c86
-rw-r--r--src/shared/cgroup-show.h11
-rw-r--r--src/shared/clean-ipc.c4
-rw-r--r--src/system-update-generator/system-update-generator.c25
-rw-r--r--src/systemctl/systemctl.c1
-rw-r--r--src/test/test-fs-util.c11
-rw-r--r--src/tmpfiles/tmpfiles.c6
36 files changed, 428 insertions, 282 deletions
diff --git a/TODO b/TODO
index c06a47b7ea..2004c394be 100644
--- a/TODO
+++ b/TODO
@@ -24,6 +24,13 @@ Janitorial Clean-ups:
Features:
+* journald: when we recv a log datagram via the native or syslog transports,
+ search for the PID in the active stream connections, and let's make sure to
+ always process the datagrams before the streams. Then, cache client metadata
+ per stream in the stream object. This way we can somewhat fix the race with
+ quickly exiting processes which log as long as they had their own stream
+ connection...
+
* Maybe add a small tool invoked early at boot, that adds in or resizes
partitions automatically, to be used when the media used is actually larger
than the image written onto it is.
diff --git a/man/systemctl.xml b/man/systemctl.xml
index 87cf52172b..25db00e5f6 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -393,10 +393,14 @@
<xi:include href="user-system-options.xml" xpointer="user" />
<xi:include href="user-system-options.xml" xpointer="system" />
- <!-- we do not document -failed here, as it has been made
- redundant by -state=failed, which it predates. To keep
- things simple, we only document the new switch, while
- keeping the old one around for compatibility only. -->
+ <varlistentry>
+ <term><option>--failed</option></term>
+
+ <listitem>
+ <para>List units in failed state. This is equivalent to
+ <option>--state=failed</option>.</para>
+ </listitem>
+ </varlistentry>
<varlistentry>
<term><option>--no-wall</option></term>
diff --git a/man/systemd-cgls.xml b/man/systemd-cgls.xml
index e8f0368f48..219514b183 100644
--- a/man/systemd-cgls.xml
+++ b/man/systemd-cgls.xml
@@ -54,6 +54,12 @@
<arg choice="opt" rep="repeat">OPTIONS</arg>
<arg choice="opt" rep="repeat">CGROUP</arg>
</cmdsynopsis>
+ <cmdsynopsis>
+ <command>systemd-cgls</command>
+ <arg choice="opt" rep="repeat">OPTIONS</arg>
+ <arg choice="plain"><option>--unit</option>|<option>--user-unit</option></arg>
+ <arg choice="opt" rep="repeat">UNIT</arg>
+ </cmdsynopsis>
</refsynopsisdiv>
<refsect1>
@@ -96,6 +102,21 @@
</varlistentry>
<varlistentry>
+ <term><option>-u</option></term>
+ <term><option>--unit</option></term>
+
+ <listitem><para>Show cgroup subtrees for the specified units.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--user-unit</option></term>
+
+ <listitem><para>Show cgroup subtrees for the specified user units.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><option>-k</option></term>
<listitem><para>Include kernel threads in output.
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index f57e15e38c..699f6e263f 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -981,7 +981,7 @@
source path, destination path and option string, where the latter two are optional. If only a source path is
specified the source and destination is taken to be the same. The option string may be either
<literal>rbind</literal> or <literal>norbind</literal> for configuring a recursive or non-recursive bind
- mount. If the destination parth is omitted, the option string must be omitted too.</para>
+ mount. If the destination path is omitted, the option string must be omitted too.</para>
<para><varname>BindPaths=</varname> creates regular writable bind mounts (unless the source file system mount
is already marked read-only), while <varname>BindReadOnlyPaths=</varname> creates read-only bind mounts. These
diff --git a/shell-completion/bash/systemctl.in b/shell-completion/bash/systemctl.in
index 7765010869..e4ccad8799 100644
--- a/shell-completion/bash/systemctl.in
+++ b/shell-completion/bash/systemctl.in
@@ -126,7 +126,7 @@ _systemctl () {
[STANDALONE]='--all -a --reverse --after --before --defaults --force -f --full -l --global
--help -h --no-ask-password --no-block --no-legend --no-pager --no-reload --no-wall --now
--quiet -q --privileged -P --system --user --version --runtime --recursive -r --firmware-setup
- --show-types -i --ignore-inhibitors --plain'
+ --show-types -i --ignore-inhibitors --plain --failed'
[ARG]='--host -H --kill-who --property -p --signal -s --type -t --state --job-mode --root
--preset-mode -n --lines -o --output -M --machine'
)
diff --git a/shell-completion/zsh/_systemctl.in b/shell-completion/zsh/_systemctl.in
index 553216da5e..92a56ba99a 100644
--- a/shell-completion/zsh/_systemctl.in
+++ b/shell-completion/zsh/_systemctl.in
@@ -386,4 +386,5 @@ _arguments -s \
{-o+,--output=}'[Change journal output mode]:modes:_sd_outputmodes' \
'--firmware-setup[Tell the firmware to show the setup menu on next boot]' \
'--plain[When used with list-dependencies, print output as a list]' \
+ '--failed[Show failed units]' \
'*::systemctl command:_systemctl_command'
diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c
index d2d18f13f0..6948ed3931 100644
--- a/src/basic/cgroup-util.c
+++ b/src/basic/cgroup-util.c
@@ -182,8 +182,7 @@ int cg_read_subgroup(DIR *d, char **fn) {
if (de->d_type != DT_DIR)
continue;
- if (streq(de->d_name, ".") ||
- streq(de->d_name, ".."))
+ if (dot_or_dot_dot(de->d_name))
continue;
b = strdup(de->d_name);
diff --git a/src/basic/copy.c b/src/basic/copy.c
index 9883f5fa31..e9a7efd232 100644
--- a/src/basic/copy.c
+++ b/src/basic/copy.c
@@ -331,7 +331,7 @@ static int fd_copy_directory(
struct stat buf;
int q;
- if (STR_IN_SET(de->d_name, ".", ".."))
+ if (dot_or_dot_dot(de->d_name))
continue;
if (fstatat(dirfd(d), de->d_name, &buf, AT_SYMLINK_NOFOLLOW) < 0) {
diff --git a/src/basic/hexdecoct.c b/src/basic/hexdecoct.c
index 6843aedd0a..2d6e377f0a 100644
--- a/src/basic/hexdecoct.c
+++ b/src/basic/hexdecoct.c
@@ -72,10 +72,10 @@ int unhexchar(char c) {
}
char *hexmem(const void *p, size_t l) {
- char *r, *z;
const uint8_t *x;
+ char *r, *z;
- z = r = malloc(l * 2 + 1);
+ z = r = new(char, l * 2 + 1);
if (!r)
return NULL;
diff --git a/src/basic/path-util.c b/src/basic/path-util.c
index 9a51e0d8bc..1313a52c9c 100644
--- a/src/basic/path-util.c
+++ b/src/basic/path-util.c
@@ -699,10 +699,7 @@ bool filename_is_valid(const char *p) {
if (isempty(p))
return false;
- if (streq(p, "."))
- return false;
-
- if (streq(p, ".."))
+ if (dot_or_dot_dot(p))
return false;
e = strchrnul(p, '/');
@@ -720,14 +717,17 @@ bool path_is_safe(const char *p) {
if (isempty(p))
return false;
- if (streq(p, "..") || startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../"))
+ if (dot_or_dot_dot(p))
+ return false;
+
+ if (startswith(p, "../") || endswith(p, "/..") || strstr(p, "/../"))
return false;
if (strlen(p)+1 > PATH_MAX)
return false;
/* The following two checks are not really dangerous, but hey, they still are confusing */
- if (streq(p, ".") || startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./"))
+ if (startswith(p, "./") || endswith(p, "/.") || strstr(p, "/./"))
return false;
if (strstr(p, "//"))
@@ -892,3 +892,16 @@ int systemd_installation_has_version(const char *root, unsigned minimal_version)
return false;
}
+
+bool dot_or_dot_dot(const char *path) {
+ if (!path)
+ return false;
+ if (path[0] != '.')
+ return false;
+ if (path[1] == 0)
+ return true;
+ if (path[1] != '.')
+ return false;
+
+ return path[2] == 0;
+}
diff --git a/src/basic/path-util.h b/src/basic/path-util.h
index 349cdac7d6..35aef3adc8 100644
--- a/src/basic/path-util.h
+++ b/src/basic/path-util.h
@@ -141,3 +141,5 @@ bool is_device_path(const char *path);
bool is_deviceallow_pattern(const char *path);
int systemd_installation_has_version(const char *root, unsigned minimal_version);
+
+bool dot_or_dot_dot(const char *path);
diff --git a/src/basic/rm-rf.c b/src/basic/rm-rf.c
index 07d42f78dd..08497af729 100644
--- a/src/basic/rm-rf.c
+++ b/src/basic/rm-rf.c
@@ -83,7 +83,7 @@ int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {
bool is_dir;
struct stat st;
- if (streq(de->d_name, ".") || streq(de->d_name, ".."))
+ if (dot_or_dot_dot(de->d_name))
continue;
if (de->d_type == DT_UNKNOWN ||
diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c
index 77f81a60ba..17e90a8994 100644
--- a/src/basic/socket-util.c
+++ b/src/basic/socket-util.c
@@ -877,7 +877,7 @@ bool ifname_valid(const char *p) {
if (strlen(p) >= IFNAMSIZ)
return false;
- if (STR_IN_SET(p, ".", ".."))
+ if (dot_or_dot_dot(p))
return false;
while (*p) {
diff --git a/src/boot/efi/boot.c b/src/boot/efi/boot.c
index 44ea6215dc..7cc54a8cdd 100644
--- a/src/boot/efi/boot.c
+++ b/src/boot/efi/boot.c
@@ -1647,7 +1647,7 @@ static EFI_STATUS image_start(EFI_HANDLE parent_image, const Config *config, con
loaded_image->LoadOptionsSize = (StrLen(loaded_image->LoadOptions)+1) * sizeof(CHAR16);
#ifdef SD_BOOT_LOG_TPM
- /* Try to log any options to the TPM, escpecially to catch manually edited options */
+ /* Try to log any options to the TPM, especially to catch manually edited options */
err = tpm_log_event(SD_TPM_PCR,
(EFI_PHYSICAL_ADDRESS) loaded_image->LoadOptions,
loaded_image->LoadOptionsSize, loaded_image->LoadOptions);
diff --git a/src/boot/efi/stub.c b/src/boot/efi/stub.c
index 1e250f34f4..7c1ffb1bca 100644
--- a/src/boot/efi/stub.c
+++ b/src/boot/efi/stub.c
@@ -100,7 +100,7 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
cmdline = line;
#ifdef SD_BOOT_LOG_TPM
- /* Try to log any options to the TPM, escpecially manually edited options */
+ /* Try to log any options to the TPM, especially manually edited options */
err = tpm_log_event(SD_TPM_PCR,
(EFI_PHYSICAL_ADDRESS) loaded_image->LoadOptions,
loaded_image->LoadOptionsSize, loaded_image->LoadOptions);
diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c
index b55aa86a40..82b4d9ccb3 100644
--- a/src/cgls/cgls.c
+++ b/src/cgls/cgls.c
@@ -26,7 +26,6 @@
#include "sd-bus.h"
#include "alloc-util.h"
-#include "bus-error.h"
#include "bus-util.h"
#include "cgroup-show.h"
#include "cgroup-util.h"
@@ -35,12 +34,21 @@
#include "output-mode.h"
#include "pager.h"
#include "path-util.h"
+#include "strv.h"
#include "unit-name.h"
#include "util.h"
static bool arg_no_pager = false;
static bool arg_kernel_threads = false;
static bool arg_all = false;
+
+static enum {
+ SHOW_UNIT_NONE,
+ SHOW_UNIT_SYSTEM,
+ SHOW_UNIT_USER,
+} arg_show_unit = SHOW_UNIT_NONE;
+static char **arg_names = NULL;
+
static int arg_full = -1;
static char* arg_machine = NULL;
@@ -51,6 +59,8 @@ static void help(void) {
" --version Show package version\n"
" --no-pager Do not pipe output into a pager\n"
" -a --all Show all groups, including empty\n"
+ " -u --unit Show the subtrees of specifified system units\n"
+ " --user-unit Show the subtrees of specifified user units\n"
" -l --full Do not ellipsize output\n"
" -k Include kernel threads in output\n"
" -M --machine= Show container\n"
@@ -62,15 +72,18 @@ static int parse_argv(int argc, char *argv[]) {
enum {
ARG_NO_PAGER = 0x100,
ARG_VERSION,
+ ARG_USER_UNIT,
};
static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, ARG_VERSION },
- { "no-pager", no_argument, NULL, ARG_NO_PAGER },
- { "all", no_argument, NULL, 'a' },
- { "full", no_argument, NULL, 'l' },
- { "machine", required_argument, NULL, 'M' },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, ARG_VERSION },
+ { "no-pager", no_argument, NULL, ARG_NO_PAGER },
+ { "all", no_argument, NULL, 'a' },
+ { "full", no_argument, NULL, 'l' },
+ { "machine", required_argument, NULL, 'M' },
+ { "unit", optional_argument, NULL, 'u' },
+ { "user-unit", optional_argument, NULL, ARG_USER_UNIT },
{}
};
@@ -79,7 +92,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 1);
assert(argv);
- while ((c = getopt_long(argc, argv, "hkalM:", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "-hkalM:u::", options, NULL)) >= 0)
switch (c) {
@@ -98,6 +111,24 @@ static int parse_argv(int argc, char *argv[]) {
arg_all = true;
break;
+ case 'u':
+ arg_show_unit = SHOW_UNIT_SYSTEM;
+ if (strv_push(&arg_names, optarg) < 0) /* push optarg if not empty */
+ return log_oom();
+ break;
+
+ case ARG_USER_UNIT:
+ arg_show_unit = SHOW_UNIT_USER;
+ if (strv_push(&arg_names, optarg) < 0) /* push optarg if not empty */
+ return log_oom();
+ break;
+
+ case 1:
+ /* positional argument */
+ if (strv_push(&arg_names, optarg) < 0)
+ return log_oom();
+ break;
+
case 'l':
arg_full = true;
break;
@@ -117,51 +148,12 @@ static int parse_argv(int argc, char *argv[]) {
assert_not_reached("Unhandled option");
}
- return 1;
-}
-
-static int get_cgroup_root(char **ret) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
- _cleanup_free_ char *unit = NULL, *path = NULL;
- const char *m;
- int r;
-
- if (!arg_machine) {
- r = cg_get_root_path(ret);
- if (r == -ENOMEDIUM)
- return log_error_errno(r, "Failed to get root control group path: No cgroup filesystem mounted on /sys/fs/cgroup");
- else if (r < 0)
- return log_error_errno(r, "Failed to get root control group path: %m");
-
- return 0;
+ if (arg_machine && arg_show_unit != SHOW_UNIT_NONE) {
+ log_error("Cannot combine --unit or --user-unit with --machine.");
+ return -EINVAL;
}
- m = strjoina("/run/systemd/machines/", arg_machine);
- r = parse_env_file(m, NEWLINE, "SCOPE", &unit, NULL);
- if (r < 0)
- return log_error_errno(r, "Failed to load machine data: %m");
-
- path = unit_dbus_path_from_name(unit);
- if (!path)
- return log_oom();
-
- r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL, false, &bus);
- if (r < 0)
- return log_error_errno(r, "Failed to create bus connection: %m");
-
- r = sd_bus_get_property_string(
- bus,
- "org.freedesktop.systemd1",
- path,
- unit_dbus_interface_from_name(unit),
- "ControlGroup",
- &error,
- ret);
- if (r < 0)
- return log_error_errno(r, "Failed to query unit control group path: %s", bus_error_message(&error, r));
-
- return 0;
+ return 1;
}
static void show_cg_info(const char *controller, const char *path) {
@@ -194,31 +186,65 @@ int main(int argc, char *argv[]) {
(arg_full > 0) * OUTPUT_FULL_WIDTH |
arg_kernel_threads * OUTPUT_KERNEL_THREADS;
- if (optind < argc) {
+ if (arg_names) {
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_free_ char *root = NULL;
- int i;
+ char **name;
- r = get_cgroup_root(&root);
- if (r < 0)
- goto finish;
-
- for (i = optind; i < argc; i++) {
+ STRV_FOREACH(name, arg_names) {
int q;
- if (path_startswith(argv[i], "/sys/fs/cgroup")) {
+ if (arg_show_unit != SHOW_UNIT_NONE) {
+ /* Command line arguments are unit names */
+ _cleanup_free_ char *cgroup = NULL;
+
+ if (!bus) {
+ /* Connect to the bus only if necessary */
+ r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL,
+ arg_show_unit == SHOW_UNIT_USER,
+ &bus);
+ if (r < 0) {
+ log_error_errno(r, "Failed to create bus connection: %m");
+ goto finish;
+ }
+ }
+
+ q = show_cgroup_get_unit_path_and_warn(bus, *name, &cgroup);
+ if (q < 0)
+ goto failed;
+
+ if (isempty(cgroup)) {
+ log_warning("Unit %s not found.", *name);
+ q = -ENOENT;
+ goto failed;
+ }
+
+ printf("Unit %s (%s):\n", *name, cgroup);
+ fflush(stdout);
+
+ q = show_cgroup_by_path(cgroup, NULL, 0, output_flags);
- printf("Directory %s:\n", argv[i]);
+ } else if (path_startswith(*name, "/sys/fs/cgroup")) {
+
+ printf("Directory %s:\n", *name);
fflush(stdout);
- q = show_cgroup_by_path(argv[i], NULL, 0, output_flags);
+ q = show_cgroup_by_path(*name, NULL, 0, output_flags);
} else {
_cleanup_free_ char *c = NULL, *p = NULL, *j = NULL;
const char *controller, *path;
- r = cg_split_spec(argv[i], &c, &p);
+ if (!root) {
+ /* Query root only if needed, treat error as fatal */
+ r = show_cgroup_get_path_and_warn(arg_machine, NULL, &root);
+ if (r < 0)
+ goto finish;
+ }
+
+ r = cg_split_spec(*name, &c, &p);
if (r < 0) {
- log_error_errno(r, "Failed to split argument %s: %m", argv[i]);
- goto finish;
+ log_error_errno(r, "Failed to split argument %s: %m", *name);
+ goto failed;
}
controller = c ?: SYSTEMD_CGROUP_CONTROLLER;
@@ -239,7 +265,8 @@ int main(int argc, char *argv[]) {
q = show_cgroup(controller, path, NULL, 0, output_flags);
}
- if (q < 0)
+ failed:
+ if (q < 0 && r >= 0)
r = q;
}
@@ -267,7 +294,7 @@ int main(int argc, char *argv[]) {
if (!done) {
_cleanup_free_ char *root = NULL;
- r = get_cgroup_root(&root);
+ r = show_cgroup_get_path_and_warn(arg_machine, NULL, &root);
if (r < 0)
goto finish;
@@ -283,6 +310,7 @@ int main(int argc, char *argv[]) {
finish:
pager_close();
+ free(arg_names); /* don't free the strings */
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/cgtop/cgtop.c b/src/cgtop/cgtop.c
index af5c3d8695..50ac6a58b0 100644
--- a/src/cgtop/cgtop.c
+++ b/src/cgtop/cgtop.c
@@ -31,6 +31,7 @@
#include "alloc-util.h"
#include "bus-error.h"
#include "bus-util.h"
+#include "cgroup-show.h"
#include "cgroup-util.h"
#include "fd-util.h"
#include "fileio.h"
@@ -862,13 +863,9 @@ static int parse_argv(int argc, char *argv[]) {
assert_not_reached("Unhandled option");
}
- if (optind == argc-1) {
- if (arg_machine) {
- log_error("Specifying a control group path together with the -M option is not allowed");
- return -EINVAL;
- }
+ if (optind == argc - 1)
arg_root = argv[optind];
- } else if (optind < argc) {
+ else if (optind < argc) {
log_error("Too many arguments.");
return -EINVAL;
}
@@ -890,59 +887,6 @@ static const char* counting_what(void) {
return "userspace processes (excl. kernel)";
}
-static int get_cgroup_root(char **ret) {
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
- _cleanup_free_ char *unit = NULL, *path = NULL;
- const char *m;
- int r;
-
- if (arg_root) {
- char *aux;
-
- aux = strdup(arg_root);
- if (!aux)
- return log_oom();
-
- *ret = aux;
- return 0;
- }
-
- if (!arg_machine) {
- r = cg_get_root_path(ret);
- if (r < 0)
- return log_error_errno(r, "Failed to get root control group path: %m");
-
- return 0;
- }
-
- m = strjoina("/run/systemd/machines/", arg_machine);
- r = parse_env_file(m, NEWLINE, "SCOPE", &unit, NULL);
- if (r < 0)
- return log_error_errno(r, "Failed to load machine data: %m");
-
- path = unit_dbus_path_from_name(unit);
- if (!path)
- return log_oom();
-
- r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL, false, &bus);
- if (r < 0)
- return log_error_errno(r, "Failed to create bus connection: %m");
-
- r = sd_bus_get_property_string(
- bus,
- "org.freedesktop.systemd1",
- path,
- unit_dbus_interface_from_name(unit),
- "ControlGroup",
- &error,
- ret);
- if (r < 0)
- return log_error_errno(r, "Failed to query unit control group path: %s", bus_error_message(&error, r));
-
- return 0;
-}
-
int main(int argc, char *argv[]) {
int r;
Hashmap *a = NULL, *b = NULL;
@@ -967,11 +911,12 @@ int main(int argc, char *argv[]) {
if (r <= 0)
goto finish;
- r = get_cgroup_root(&root);
+ r = show_cgroup_get_path_and_warn(arg_machine, arg_root, &root);
if (r < 0) {
log_error_errno(r, "Failed to get root control group path: %m");
goto finish;
- }
+ } else
+ log_debug("Cgroup path: %s", root);
a = hashmap_new(&string_hash_ops);
b = hashmap_new(&string_hash_ops);
diff --git a/src/core/execute.c b/src/core/execute.c
index d0faba5a85..47cc4311c1 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -1685,25 +1685,31 @@ static int setup_private_users(uid_t uid, gid_t gid) {
* child then writes the UID mapping, under full privileges. The parent waits for the child to finish and
* continues execution normally. */
- if (uid != 0 && uid_is_valid(uid))
- asprintf(&uid_map,
- "0 0 1\n" /* Map root → root */
- UID_FMT " " UID_FMT " 1\n", /* Map $UID → $UID */
- uid, uid);
- else
+ if (uid != 0 && uid_is_valid(uid)) {
+ r = asprintf(&uid_map,
+ "0 0 1\n" /* Map root → root */
+ UID_FMT " " UID_FMT " 1\n", /* Map $UID → $UID */
+ uid, uid);
+ if (r < 0)
+ return -ENOMEM;
+ } else {
uid_map = strdup("0 0 1\n"); /* The case where the above is the same */
- if (!uid_map)
- return -ENOMEM;
+ if (!uid_map)
+ return -ENOMEM;
+ }
- if (gid != 0 && gid_is_valid(gid))
- asprintf(&gid_map,
- "0 0 1\n" /* Map root → root */
- GID_FMT " " GID_FMT " 1\n", /* Map $GID → $GID */
- gid, gid);
- else
+ if (gid != 0 && gid_is_valid(gid)) {
+ r = asprintf(&gid_map,
+ "0 0 1\n" /* Map root → root */
+ GID_FMT " " GID_FMT " 1\n", /* Map $GID → $GID */
+ gid, gid);
+ if (r < 0)
+ return -ENOMEM;
+ } else {
gid_map = strdup("0 0 1\n"); /* The case where the above is the same */
- if (!gid_map)
- return -ENOMEM;
+ if (!gid_map)
+ return -ENOMEM;
+ }
/* Create a communication channel so that the parent can tell the child when it finished creating the user
* namespace. */
@@ -3096,7 +3102,7 @@ const char* exec_context_fdname(const ExecContext *c, int fd_index) {
int exec_context_named_iofds(Unit *unit, const ExecContext *c, const ExecParameters *p, int named_iofds[3]) {
unsigned i, targets;
- const char *stdio_fdname[3];
+ const char* stdio_fdname[3];
assert(c);
assert(p);
@@ -3109,18 +3115,32 @@ int exec_context_named_iofds(Unit *unit, const ExecContext *c, const ExecParamet
stdio_fdname[i] = exec_context_fdname(c, i);
for (i = 0; i < p->n_fds && targets > 0; i++)
- if (named_iofds[STDIN_FILENO] < 0 && c->std_input == EXEC_INPUT_NAMED_FD && stdio_fdname[STDIN_FILENO] && streq(p->fd_names[i], stdio_fdname[STDIN_FILENO])) {
+ if (named_iofds[STDIN_FILENO] < 0 &&
+ c->std_input == EXEC_INPUT_NAMED_FD &&
+ stdio_fdname[STDIN_FILENO] &&
+ streq(p->fd_names[i], stdio_fdname[STDIN_FILENO])) {
+
named_iofds[STDIN_FILENO] = p->fds[i];
targets--;
- } else if (named_iofds[STDOUT_FILENO] < 0 && c->std_output == EXEC_OUTPUT_NAMED_FD && stdio_fdname[STDOUT_FILENO] && streq(p->fd_names[i], stdio_fdname[STDOUT_FILENO])) {
+
+ } else if (named_iofds[STDOUT_FILENO] < 0 &&
+ c->std_output == EXEC_OUTPUT_NAMED_FD &&
+ stdio_fdname[STDOUT_FILENO] &&
+ streq(p->fd_names[i], stdio_fdname[STDOUT_FILENO])) {
+
named_iofds[STDOUT_FILENO] = p->fds[i];
targets--;
- } else if (named_iofds[STDERR_FILENO] < 0 && c->std_error == EXEC_OUTPUT_NAMED_FD && stdio_fdname[STDERR_FILENO] && streq(p->fd_names[i], stdio_fdname[STDERR_FILENO])) {
+
+ } else if (named_iofds[STDERR_FILENO] < 0 &&
+ c->std_error == EXEC_OUTPUT_NAMED_FD &&
+ stdio_fdname[STDERR_FILENO] &&
+ streq(p->fd_names[i], stdio_fdname[STDERR_FILENO])) {
+
named_iofds[STDERR_FILENO] = p->fds[i];
targets--;
}
- return (targets == 0 ? 0 : -ENOENT);
+ return targets == 0 ? 0 : -ENOENT;
}
int exec_context_load_environment(Unit *unit, const ExecContext *c, char ***l) {
diff --git a/src/core/killall.c b/src/core/killall.c
index b3aa22adc5..7a9df546ee 100644
--- a/src/core/killall.c
+++ b/src/core/killall.c
@@ -66,29 +66,26 @@ static bool ignore_proc(pid_t pid, bool warn_rootfs) {
if (count <= 0)
return true;
- /* Processes with argv[0][0] = '@' we ignore from the killing
- * spree.
+ /* Processes with argv[0][0] = '@' we ignore from the killing spree.
*
* http://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons */
- if (c == '@' && warn_rootfs) {
- _cleanup_free_ char *comm = NULL;
+ if (c != '@')
+ return false;
- r = pid_from_same_root_fs(pid);
- if (r < 0)
- return true;
+ if (warn_rootfs &&
+ pid_from_same_root_fs(pid) == 0) {
+
+ _cleanup_free_ char *comm = NULL;
get_process_comm(pid, &comm);
- if (r)
- 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));
- return true;
- } else if (c == '@')
- return true;
+ 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));
+ }
- return false;
+ return true;
}
static void wait_for_children(Set *pids, sigset_t *mask) {
diff --git a/src/core/timer.c b/src/core/timer.c
index 5ee14669d2..d7441d638f 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -232,7 +232,7 @@ static void timer_dump(Unit *u, FILE *f, const char *prefix) {
if (v->base == TIMER_CALENDAR) {
_cleanup_free_ char *p = NULL;
- calendar_spec_to_string(v->calendar_spec, &p);
+ (void) calendar_spec_to_string(v->calendar_spec, &p);
fprintf(f,
"%s%s: %s\n",
diff --git a/src/cryptsetup/cryptsetup.c b/src/cryptsetup/cryptsetup.c
index cefd1b85df..91c653312a 100644
--- a/src/cryptsetup/cryptsetup.c
+++ b/src/cryptsetup/cryptsetup.c
@@ -594,7 +594,7 @@ static int help(void) {
int main(int argc, char *argv[]) {
struct crypt_device *cd = NULL;
- int r;
+ int r = -EINVAL;
if (argc <= 1) {
r = help();
@@ -603,7 +603,6 @@ int main(int argc, char *argv[]) {
if (argc < 3) {
log_error("This program requires at least two arguments.");
- r = -EINVAL;
goto finish;
}
@@ -750,7 +749,6 @@ int main(int argc, char *argv[]) {
} else {
log_error("Unknown verb %s.", argv[1]);
- r = -EINVAL;
goto finish;
}
diff --git a/src/gpt-auto-generator/gpt-auto-generator.c b/src/gpt-auto-generator/gpt-auto-generator.c
index e61ef8f249..b958070c90 100644
--- a/src/gpt-auto-generator/gpt-auto-generator.c
+++ b/src/gpt-auto-generator/gpt-auto-generator.c
@@ -658,7 +658,7 @@ static int get_block_device_harder(const char *path, dev_t *dev) {
FOREACH_DIRENT_ALL(de, d, return -errno) {
- if (STR_IN_SET(de->d_name, ".", ".."))
+ if (dot_or_dot_dot(de->d_name))
continue;
if (!IN_SET(de->d_type, DT_LNK, DT_UNKNOWN))
diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c
index 93b9ff2da0..ef87b176fa 100644
--- a/src/journal/journal-file.c
+++ b/src/journal/journal-file.c
@@ -42,6 +42,7 @@
#include "sd-event.h"
#include "set.h"
#include "string-util.h"
+#include "strv.h"
#include "xattr-util.h"
#define DEFAULT_DATA_HASH_TABLE_SIZE (2047ULL*sizeof(HashItem))
@@ -507,42 +508,58 @@ static int journal_file_refresh_header(JournalFile *f) {
return r;
}
-static int journal_file_verify_header(JournalFile *f) {
+static bool warn_wrong_flags(const JournalFile *f, bool compatible) {
+ const uint32_t any = compatible ? HEADER_COMPATIBLE_ANY : HEADER_INCOMPATIBLE_ANY,
+ supported = compatible ? HEADER_COMPATIBLE_SUPPORTED : HEADER_INCOMPATIBLE_SUPPORTED;
+ const char *type = compatible ? "compatible" : "incompatible";
uint32_t flags;
+ flags = le32toh(compatible ? f->header->compatible_flags : f->header->incompatible_flags);
+
+ if (flags & ~supported) {
+ if (flags & ~any)
+ log_debug("Journal file %s has unknown %s flags 0x%"PRIx32,
+ f->path, type, flags & ~any);
+ flags = (flags & any) & ~supported;
+ if (flags) {
+ const char* strv[3];
+ unsigned n = 0;
+ _cleanup_free_ char *t = NULL;
+
+ if (compatible && (flags & HEADER_COMPATIBLE_SEALED))
+ strv[n++] = "sealed";
+ if (!compatible && (flags & HEADER_INCOMPATIBLE_COMPRESSED_XZ))
+ strv[n++] = "xz-compressed";
+ if (!compatible && (flags & HEADER_INCOMPATIBLE_COMPRESSED_LZ4))
+ strv[n++] = "lz4-compressed";
+ strv[n] = NULL;
+ assert(n < ELEMENTSOF(strv));
+
+ t = strv_join((char**) strv, ", ");
+ log_debug("Journal file %s uses %s %s %s disabled at compilation time.",
+ f->path, type, n > 1 ? "flags" : "flag", strnull(t));
+ }
+ return true;
+ }
+
+ return false;
+}
+
+static int journal_file_verify_header(JournalFile *f) {
assert(f);
assert(f->header);
if (memcmp(f->header->signature, HEADER_SIGNATURE, 8))
return -EBADMSG;
- /* In both read and write mode we refuse to open files with
- * incompatible flags we don't know */
- flags = le32toh(f->header->incompatible_flags);
- if (flags & ~HEADER_INCOMPATIBLE_SUPPORTED) {
- if (flags & ~HEADER_INCOMPATIBLE_ANY)
- log_debug("Journal file %s has unknown incompatible flags %"PRIx32,
- f->path, flags & ~HEADER_INCOMPATIBLE_ANY);
- flags = (flags & HEADER_INCOMPATIBLE_ANY) & ~HEADER_INCOMPATIBLE_SUPPORTED;
- if (flags)
- log_debug("Journal file %s uses incompatible flags %"PRIx32
- " disabled at compilation time.", f->path, flags);
+ /* In both read and write mode we refuse to open files with incompatible
+ * flags we don't know. */
+ if (warn_wrong_flags(f, false))
return -EPROTONOSUPPORT;
- }
- /* When open for writing we refuse to open files with
- * compatible flags, too */
- flags = le32toh(f->header->compatible_flags);
- if (f->writable && (flags & ~HEADER_COMPATIBLE_SUPPORTED)) {
- if (flags & ~HEADER_COMPATIBLE_ANY)
- log_debug("Journal file %s has unknown compatible flags %"PRIx32,
- f->path, flags & ~HEADER_COMPATIBLE_ANY);
- flags = (flags & HEADER_COMPATIBLE_ANY) & ~HEADER_COMPATIBLE_SUPPORTED;
- if (flags)
- log_debug("Journal file %s uses compatible flags %"PRIx32
- " disabled at compilation time.", f->path, flags);
+ /* When open for writing we refuse to open files with compatible flags, too. */
+ if (f->writable && warn_wrong_flags(f, true))
return -EPROTONOSUPPORT;
- }
if (f->header->state >= _STATE_MAX)
return -EBADMSG;
@@ -3087,13 +3104,18 @@ int journal_file_open(
}
}
- if (fname)
+ if (fname) {
f->path = strdup(fname);
- else /* If we don't know the path, fill in something explanatory and vaguely useful */
- asprintf(&f->path, "/proc/self/%i", fd);
- if (!f->path) {
- r = -ENOMEM;
- goto fail;
+ if (!f->path) {
+ r = -ENOMEM;
+ goto fail;
+ }
+ } else {
+ /* If we don't know the path, fill in something explanatory and vaguely useful */
+ if (asprintf(&f->path, "/proc/self/%i", fd) < 0) {
+ r = -ENOMEM;
+ goto fail;
+ }
}
f->chain_cache = ordered_hashmap_new(&uint64_hash_ops);
diff --git a/src/journal/journalctl.c b/src/journal/journalctl.c
index 2a5f2b37e8..2639fd6cf5 100644
--- a/src/journal/journalctl.c
+++ b/src/journal/journalctl.c
@@ -1910,7 +1910,9 @@ static int access_check(sd_journal *j) {
break;
case EPROTONOSUPPORT:
- log_warning_errno(err, "Journal file %s uses an unsupported feature, ignoring file.", path);
+ log_warning_errno(err, "Journal file %1$s uses an unsupported feature, ignoring file.\n"
+ "Use SYSTEMD_LOG_LEVEL=debug journalctl --file=%1$s to see the details.",
+ path);
break;
case EBADMSG:
diff --git a/src/login/loginctl.c b/src/login/loginctl.c
index 4c618ed19e..1aac7ae979 100644
--- a/src/login/loginctl.c
+++ b/src/login/loginctl.c
@@ -240,7 +240,6 @@ static int list_seats(int argc, char *argv[], void *userdata) {
sd_bus *bus = userdata;
unsigned k = 0;
int r;
-
assert(bus);
assert(argv);
@@ -280,35 +279,17 @@ static int list_seats(int argc, char *argv[], void *userdata) {
}
static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit, pid_t leader) {
+ _cleanup_free_ char *cgroup = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- _cleanup_free_ char *path = NULL;
- const char *cgroup;
unsigned c;
int r;
assert(bus);
assert(unit);
- path = unit_dbus_path_from_name(unit);
- if (!path)
- return log_oom();
-
- r = sd_bus_get_property(
- bus,
- "org.freedesktop.systemd1",
- path,
- interface,
- "ControlGroup",
- &error,
- &reply,
- "s");
- if (r < 0)
- return log_error_errno(r, "Failed to query ControlGroup: %s", bus_error_message(&error, r));
-
- r = sd_bus_message_read(reply, "s", &cgroup);
+ r = show_cgroup_get_unit_path_and_warn(bus, unit, &cgroup);
if (r < 0)
- return bus_log_parse_error(r);
+ return r;
if (isempty(cgroup))
return 0;
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 3873bf3e96..ad44ca290e 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -2396,13 +2396,9 @@ static int method_set_wall_message(
if (r == 0)
return 1; /* Will call us back */
- if (isempty(wall_message))
- m->wall_message = mfree(m->wall_message);
- else {
- r = free_and_strdup(&m->wall_message, wall_message);
- if (r < 0)
- return log_oom();
- }
+ r = free_and_strdup(&m->wall_message, empty_to_null(wall_message));
+ if (r < 0)
+ return log_oom();
m->enable_wall_messages = enable_wall_messages;
diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c
index 31a40d47c3..4f5f659c7c 100644
--- a/src/machine/machinectl.c
+++ b/src/machine/machinectl.c
@@ -477,35 +477,17 @@ static int list_images(int argc, char *argv[], void *userdata) {
}
static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
+ _cleanup_free_ char *cgroup = NULL;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
- _cleanup_free_ char *path = NULL;
- const char *cgroup;
int r;
unsigned c;
assert(bus);
assert(unit);
- path = unit_dbus_path_from_name(unit);
- if (!path)
- return log_oom();
-
- r = sd_bus_get_property(
- bus,
- "org.freedesktop.systemd1",
- path,
- unit_dbus_interface_from_name(unit),
- "ControlGroup",
- &error,
- &reply,
- "s");
- if (r < 0)
- return log_error_errno(r, "Failed to query ControlGroup: %s", bus_error_message(&error, r));
-
- r = sd_bus_message_read(reply, "s", &cgroup);
+ r = show_cgroup_get_unit_path_and_warn(bus, unit, &cgroup);
if (r < 0)
- return bus_log_parse_error(r);
+ return r;
if (isempty(cgroup))
return 0;
diff --git a/src/nspawn/nspawn-patch-uid.c b/src/nspawn/nspawn-patch-uid.c
index ded5866d05..1a3f129db0 100644
--- a/src/nspawn/nspawn-patch-uid.c
+++ b/src/nspawn/nspawn-patch-uid.c
@@ -375,7 +375,7 @@ static int recurse_fd(int fd, bool donate_fd, const struct stat *st, uid_t shift
FOREACH_DIRENT_ALL(de, d, r = -errno; goto finish) {
struct stat fst;
- if (STR_IN_SET(de->d_name, ".", ".."))
+ if (dot_or_dot_dot(de->d_name))
continue;
if (fstatat(dirfd(d), de->d_name, &fst, AT_SYMLINK_NOFOLLOW) < 0) {
diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c
index 0954641c20..667774b906 100644
--- a/src/resolve/resolved-manager.c
+++ b/src/resolve/resolved-manager.c
@@ -1349,7 +1349,7 @@ void manager_cleanup_saved_user(Manager *m) {
if (!IN_SET(de->d_type, DT_UNKNOWN, DT_REG))
continue;
- if (STR_IN_SET(de->d_name, ".", ".."))
+ if (dot_or_dot_dot(de->d_name))
continue;
r = parse_ifindex(de->d_name, &ifindex);
diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c
index 5d21742a09..8765cf2f49 100644
--- a/src/shared/cgroup-show.c
+++ b/src/shared/cgroup-show.c
@@ -24,10 +24,15 @@
#include <stdlib.h>
#include <string.h>
+#include <systemd/sd-bus.h>
+
#include "alloc-util.h"
+#include "bus-error.h"
+#include "bus-util.h"
#include "cgroup-show.h"
#include "cgroup-util.h"
#include "fd-util.h"
+#include "fileio.h"
#include "format-util.h"
#include "locale-util.h"
#include "macro.h"
@@ -36,6 +41,7 @@
#include "process-util.h"
#include "string-util.h"
#include "terminal-util.h"
+#include "unit-name.h"
static void show_pid_array(
pid_t pids[],
@@ -73,7 +79,7 @@ static void show_pid_array(
for (i = 0; i < n_pids; i++) {
_cleanup_free_ char *t = NULL;
- get_process_cmdline(pids[i], n_columns, true, &t);
+ (void) get_process_cmdline(pids[i], n_columns, true, &t);
if (extra)
printf("%s%s ", prefix, special_glyph(TRIANGULAR_BULLET));
@@ -310,3 +316,81 @@ int show_cgroup_and_extra_by_spec(
return show_cgroup_and_extra(controller, path, prefix, n_columns, extra_pids, n_extra_pids, flags);
}
+
+int show_cgroup_get_unit_path_and_warn(
+ sd_bus *bus,
+ const char *unit,
+ char **ret) {
+
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
+ _cleanup_free_ char *path = NULL;
+ int r;
+
+ path = unit_dbus_path_from_name(unit);
+ if (!path)
+ return log_oom();
+
+ r = sd_bus_get_property_string(
+ bus,
+ "org.freedesktop.systemd1",
+ path,
+ unit_dbus_interface_from_name(unit),
+ "ControlGroup",
+ &error,
+ ret);
+ if (r < 0)
+ return log_error_errno(r, "Failed to query unit control group path: %s",
+ bus_error_message(&error, r));
+
+ return 0;
+}
+
+int show_cgroup_get_path_and_warn(
+ const char *machine,
+ const char *prefix,
+ char **ret) {
+
+ int r;
+ _cleanup_free_ char *root = NULL;
+
+ if (machine) {
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+ _cleanup_free_ char *unit = NULL;
+ const char *m;
+
+ m = strjoina("/run/systemd/machines/", machine);
+ r = parse_env_file(m, NEWLINE, "SCOPE", &unit, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to load machine data: %m");
+
+ r = bus_connect_transport_systemd(BUS_TRANSPORT_LOCAL, NULL, false, &bus);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create bus connection: %m");
+
+ r = show_cgroup_get_unit_path_and_warn(bus, unit, &root);
+ if (r < 0)
+ return r;
+ } else {
+ r = cg_get_root_path(&root);
+ if (r == -ENOMEDIUM)
+ return log_error_errno(r, "Failed to get root control group path.\n"
+ "No cgroup filesystem mounted on /sys/fs/cgroup");
+ else if (r < 0)
+ return log_error_errno(r, "Failed to get root control group path: %m");
+ }
+
+ if (prefix) {
+ char *t;
+
+ t = strjoin(root, prefix);
+ if (!t)
+ return log_oom();
+
+ *ret = t;
+ } else {
+ *ret = root;
+ root = NULL;
+ }
+
+ return 0;
+}
diff --git a/src/shared/cgroup-show.h b/src/shared/cgroup-show.h
index 5c1d6e6d98..736f0f34c8 100644
--- a/src/shared/cgroup-show.h
+++ b/src/shared/cgroup-show.h
@@ -22,6 +22,8 @@
#include <stdbool.h>
#include <sys/types.h>
+#include <systemd/sd-bus.h>
+
#include "logs-show.h"
#include "output-mode.h"
@@ -30,3 +32,12 @@ int show_cgroup(const char *controller, const char *path, const char *prefix, un
int show_cgroup_and_extra_by_spec(const char *spec, const char *prefix, unsigned n_columns, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags);
int show_cgroup_and_extra(const char *controller, const char *path, const char *prefix, unsigned n_columns, const pid_t extra_pids[], unsigned n_extra_pids, OutputFlags flags);
+
+int show_cgroup_get_unit_path_and_warn(
+ sd_bus *bus,
+ const char *unit,
+ char **ret);
+int show_cgroup_get_path_and_warn(
+ const char *machine,
+ const char *prefix,
+ char **ret);
diff --git a/src/shared/clean-ipc.c b/src/shared/clean-ipc.c
index f2d1555c13..f59f6f23ae 100644
--- a/src/shared/clean-ipc.c
+++ b/src/shared/clean-ipc.c
@@ -225,7 +225,7 @@ static int clean_posix_shm_internal(DIR *dir, uid_t uid, gid_t gid) {
FOREACH_DIRENT_ALL(de, dir, goto fail) {
struct stat st;
- if (STR_IN_SET(de->d_name, "..", "."))
+ if (dot_or_dot_dot(de->d_name))
continue;
if (fstatat(dirfd(dir), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
@@ -310,7 +310,7 @@ static int clean_posix_mq(uid_t uid, gid_t gid) {
struct stat st;
char fn[1+strlen(de->d_name)+1];
- if (STR_IN_SET(de->d_name, "..", "."))
+ if (dot_or_dot_dot(de->d_name))
continue;
if (fstatat(dirfd(dir), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
diff --git a/src/system-update-generator/system-update-generator.c b/src/system-update-generator/system-update-generator.c
index 6ffb169b21..f1514c9638 100644
--- a/src/system-update-generator/system-update-generator.c
+++ b/src/system-update-generator/system-update-generator.c
@@ -22,6 +22,7 @@
#include "fs-util.h"
#include "log.h"
+#include "proc-cmdline.h"
#include "special.h"
#include "string-util.h"
#include "util.h"
@@ -47,11 +48,27 @@ static int generate_symlink(void) {
if (symlink(SYSTEM_DATA_UNIT_PATH "/system-update.target", p) < 0)
return log_error_errno(errno, "Failed to create symlink %s: %m", p);
+ return 1;
+}
+
+static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
+ assert(key);
+
+ /* Check if a run level is specified on the kernel command line. The
+ * command line has higher priority than any on-disk configuration, so
+ * it'll make any symlink we create moot.
+ */
+
+ if (streq(key, "systemd.unit") && !proc_cmdline_value_missing(key, value))
+ log_warning("Offline system update overriden by kernel command line systemd.unit= setting");
+ else if (!value && runlevel_to_target(key))
+ log_warning("Offline system update overriden by runlevel \"%s\" on the kernel command line", key);
+
return 0;
}
int main(int argc, char *argv[]) {
- int r;
+ int r, k;
if (argc > 1 && argc != 4) {
log_error("This program takes three or no arguments.");
@@ -69,5 +86,11 @@ int main(int argc, char *argv[]) {
r = generate_symlink();
+ if (r > 0) {
+ k = proc_cmdline_parse(parse_proc_cmdline_item, NULL, 0);
+ if (k < 0)
+ log_warning_errno(k, "Failed to parse kernel command line, ignoring: %m");
+ }
+
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index a20ca1bcb5..8f80559baf 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -6937,6 +6937,7 @@ static void systemctl_help(void) {
" -a --all Show all properties/all units currently in memory,\n"
" including dead/empty ones. To list all units installed on\n"
" the system, use the 'list-unit-files' command instead.\n"
+ " --failed Same as --state=failed\n"
" -l --full Don't ellipsize unit names on output\n"
" -r --recursive Show unit list of host and local containers\n"
" --reverse Show reverse dependencies with 'list-dependencies'\n"
diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c
index 4cb465d0d2..e774f567e0 100644
--- a/src/test/test-fs-util.c
+++ b/src/test/test-fs-util.c
@@ -305,12 +305,23 @@ static void test_var_tmp(void) {
}
}
+static void test_dot_or_dot_dot(void) {
+ assert_se(!dot_or_dot_dot(NULL));
+ assert_se(!dot_or_dot_dot(""));
+ assert_se(!dot_or_dot_dot("xxx"));
+ assert_se(dot_or_dot_dot("."));
+ assert_se(dot_or_dot_dot(".."));
+ assert_se(!dot_or_dot_dot(".foo"));
+ assert_se(!dot_or_dot_dot("..foo"));
+}
+
int main(int argc, char *argv[]) {
test_unlink_noerrno();
test_readlink_and_make_absolute();
test_get_files_in_directory();
test_var_tmp();
test_chase_symlinks();
+ test_dot_or_dot_dot();
return 0;
}
diff --git a/src/tmpfiles/tmpfiles.c b/src/tmpfiles/tmpfiles.c
index f4ce9791fb..c4f4d46ca1 100644
--- a/src/tmpfiles/tmpfiles.c
+++ b/src/tmpfiles/tmpfiles.c
@@ -385,7 +385,7 @@ static int dir_cleanup(
usec_t age;
_cleanup_free_ char *sub_path = NULL;
- if (STR_IN_SET(dent->d_name, ".", ".."))
+ if (dot_or_dot_dot(dent->d_name))
continue;
if (fstatat(dirfd(d), dent->d_name, &s, AT_SYMLINK_NOFOLLOW) < 0) {
@@ -1070,9 +1070,7 @@ static int item_do_children(Item *i, const char *path, action_t action) {
_cleanup_free_ char *p = NULL;
int q;
- errno = 0;
-
- if (STR_IN_SET(de->d_name, ".", ".."))
+ if (dot_or_dot_dot(de->d_name))
continue;
p = strjoin(path, "/", de->d_name);