summaryrefslogtreecommitdiff
path: root/src/shared
diff options
context:
space:
mode:
Diffstat (limited to 'src/shared')
-rw-r--r--src/shared/acl-util.c3
-rw-r--r--src/shared/acl-util.h1
-rw-r--r--src/shared/acpi-fpdt.c1
-rw-r--r--src/shared/acpi-fpdt.h1
-rw-r--r--src/shared/apparmor-util.c1
-rw-r--r--src/shared/apparmor-util.h1
-rw-r--r--src/shared/ask-password-api.c7
-rw-r--r--src/shared/ask-password-api.h1
-rw-r--r--src/shared/base-filesystem.c1
-rw-r--r--src/shared/base-filesystem.h1
-rw-r--r--src/shared/boot-timestamps.c1
-rw-r--r--src/shared/boot-timestamps.h1
-rw-r--r--src/shared/bootspec.c654
-rw-r--r--src/shared/bootspec.h64
-rw-r--r--src/shared/bus-unit-util.c434
-rw-r--r--src/shared/bus-unit-util.h1
-rw-r--r--src/shared/bus-util.c10
-rw-r--r--src/shared/bus-util.h1
-rw-r--r--src/shared/cgroup-show.c1
-rw-r--r--src/shared/cgroup-show.h1
-rw-r--r--src/shared/clean-ipc.c1
-rw-r--r--src/shared/clean-ipc.h1
-rw-r--r--src/shared/condition.c9
-rw-r--r--src/shared/condition.h1
-rw-r--r--src/shared/conf-parser.c173
-rw-r--r--src/shared/conf-parser.h19
-rw-r--r--src/shared/dev-setup.c1
-rw-r--r--src/shared/dev-setup.h1
-rw-r--r--src/shared/dissect-image.c336
-rw-r--r--src/shared/dissect-image.h26
-rw-r--r--src/shared/dns-domain.c26
-rw-r--r--src/shared/dns-domain.h2
-rw-r--r--src/shared/dropin.c7
-rw-r--r--src/shared/dropin.h1
-rw-r--r--src/shared/efivars.c30
-rw-r--r--src/shared/efivars.h1
-rw-r--r--src/shared/fdset.c1
-rw-r--r--src/shared/fdset.h1
-rw-r--r--src/shared/firewall-util.c4
-rw-r--r--src/shared/firewall-util.h1
-rw-r--r--src/shared/fstab-util.c1
-rw-r--r--src/shared/fstab-util.h1
-rw-r--r--src/shared/gcrypt-util.c1
-rw-r--r--src/shared/gcrypt-util.h1
-rw-r--r--src/shared/generator.c225
-rw-r--r--src/shared/generator.h22
-rw-r--r--src/shared/gpt.h1
-rw-r--r--src/shared/ima-util.c1
-rw-r--r--src/shared/ima-util.h1
-rw-r--r--src/shared/import-util.c1
-rw-r--r--src/shared/import-util.h1
-rw-r--r--src/shared/install-printf.c31
-rw-r--r--src/shared/install-printf.h1
-rw-r--r--src/shared/install.c130
-rw-r--r--src/shared/install.h1
-rw-r--r--src/shared/journal-util.c39
-rw-r--r--src/shared/journal-util.h4
-rw-r--r--src/shared/linux/auto_dev-ioctl.h1
-rw-r--r--src/shared/logs-show.c203
-rw-r--r--src/shared/logs-show.h2
-rw-r--r--src/shared/loop-util.c5
-rw-r--r--src/shared/loop-util.h1
-rw-r--r--src/shared/machine-image.c274
-rw-r--r--src/shared/machine-image.h15
-rw-r--r--src/shared/machine-pool.c1
-rw-r--r--src/shared/machine-pool.h1
-rw-r--r--src/shared/meson.build21
-rw-r--r--src/shared/nsflags.c1
-rw-r--r--src/shared/nsflags.h1
-rw-r--r--src/shared/output-mode.c1
-rw-r--r--src/shared/output-mode.h1
-rw-r--r--src/shared/pager.c6
-rw-r--r--src/shared/pager.h1
-rw-r--r--src/shared/path-lookup.c82
-rw-r--r--src/shared/path-lookup.h9
-rw-r--r--src/shared/ptyfwd.c51
-rw-r--r--src/shared/ptyfwd.h3
-rw-r--r--src/shared/resolve-util.c1
-rw-r--r--src/shared/resolve-util.h1
-rw-r--r--src/shared/seccomp-util.c34
-rw-r--r--src/shared/seccomp-util.h5
-rw-r--r--src/shared/sleep-config.c9
-rw-r--r--src/shared/sleep-config.h1
-rw-r--r--src/shared/spawn-ask-password-agent.c1
-rw-r--r--src/shared/spawn-ask-password-agent.h1
-rw-r--r--src/shared/spawn-polkit-agent.c1
-rw-r--r--src/shared/spawn-polkit-agent.h18
-rw-r--r--src/shared/specifier.c103
-rw-r--r--src/shared/specifier.h14
-rw-r--r--src/shared/switch-root.c1
-rw-r--r--src/shared/switch-root.h1
-rw-r--r--src/shared/sysctl-util.c3
-rw-r--r--src/shared/sysctl-util.h1
-rw-r--r--src/shared/test-tables.h1
-rw-r--r--src/shared/tests.c1
-rw-r--r--src/shared/tests.h1
-rw-r--r--src/shared/tomoyo-util.c33
-rw-r--r--src/shared/tomoyo-util.h25
-rw-r--r--src/shared/udev-util.c1
-rw-r--r--src/shared/udev-util.h1
-rw-r--r--src/shared/uid-range.c1
-rw-r--r--src/shared/uid-range.h1
-rw-r--r--src/shared/utmp-wtmp.c3
-rw-r--r--src/shared/utmp-wtmp.h1
-rw-r--r--src/shared/vlan-util.c1
-rw-r--r--src/shared/vlan-util.h1
-rw-r--r--src/shared/volatile-util.c1
-rw-r--r--src/shared/volatile-util.h1
-rw-r--r--src/shared/watchdog.c10
-rw-r--r--src/shared/watchdog.h6
110 files changed, 2683 insertions, 571 deletions
diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c
index 79a3b9591d..889a971d88 100644
--- a/src/shared/acl-util.c
+++ b/src/shared/acl-util.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -225,7 +226,7 @@ int acl_search_groups(const char *path, char ***ret_groups) {
}
int parse_acl(const char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask) {
- _cleanup_free_ char **a = NULL, **d = NULL; /* strings are not be freed */
+ _cleanup_free_ char **a = NULL, **d = NULL; /* strings are not freed */
_cleanup_strv_free_ char **split;
char **entry;
int r = -EINVAL;
diff --git a/src/shared/acl-util.h b/src/shared/acl-util.h
index a0e31d8e29..6b581cbc42 100644
--- a/src/shared/acl-util.h
+++ b/src/shared/acl-util.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/acpi-fpdt.c b/src/shared/acpi-fpdt.c
index 6779691c28..1a640f4f1b 100644
--- a/src/shared/acpi-fpdt.c
+++ b/src/shared/acpi-fpdt.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
diff --git a/src/shared/acpi-fpdt.h b/src/shared/acpi-fpdt.h
index fc28175d0a..4521a1e686 100644
--- a/src/shared/acpi-fpdt.h
+++ b/src/shared/acpi-fpdt.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/apparmor-util.c b/src/shared/apparmor-util.c
index edd695fd23..e9c4081892 100644
--- a/src/shared/apparmor-util.c
+++ b/src/shared/apparmor-util.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
diff --git a/src/shared/apparmor-util.h b/src/shared/apparmor-util.h
index 524f740152..33ebd4d612 100644
--- a/src/shared/apparmor-util.h
+++ b/src/shared/apparmor-util.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c
index e33d8b11cf..17928a9732 100644
--- a/src/shared/ask-password-api.c
+++ b/src/shared/ask-password-api.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -251,11 +252,13 @@ int ask_password_tty(
}
if (colors_enabled())
- loop_write(ttyfd, ANSI_HIGHLIGHT, strlen(ANSI_HIGHLIGHT), false);
+ loop_write(ttyfd, ANSI_HIGHLIGHT,
+ STRLEN(ANSI_HIGHLIGHT), false);
loop_write(ttyfd, message, strlen(message), false);
loop_write(ttyfd, " ", 1, false);
if (colors_enabled())
- loop_write(ttyfd, ANSI_NORMAL, strlen(ANSI_NORMAL), false);
+ loop_write(ttyfd, ANSI_NORMAL, STRLEN(ANSI_NORMAL),
+ false);
new_termios = old_termios;
new_termios.c_lflag &= ~(ICANON|ECHO);
diff --git a/src/shared/ask-password-api.h b/src/shared/ask-password-api.h
index 9d7f65130c..f3ca6743a9 100644
--- a/src/shared/ask-password-api.h
+++ b/src/shared/ask-password-api.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/base-filesystem.c b/src/shared/base-filesystem.c
index 903a187861..3c25aa534c 100644
--- a/src/shared/base-filesystem.c
+++ b/src/shared/base-filesystem.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
diff --git a/src/shared/base-filesystem.h b/src/shared/base-filesystem.h
index 49599f0a60..5d134b4eb9 100644
--- a/src/shared/base-filesystem.h
+++ b/src/shared/base-filesystem.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/boot-timestamps.c b/src/shared/boot-timestamps.c
index 7e0152761c..543e01a364 100644
--- a/src/shared/boot-timestamps.c
+++ b/src/shared/boot-timestamps.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
diff --git a/src/shared/boot-timestamps.h b/src/shared/boot-timestamps.h
index 6f691026be..8c67d302b4 100644
--- a/src/shared/boot-timestamps.h
+++ b/src/shared/boot-timestamps.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/bootspec.c b/src/shared/bootspec.c
new file mode 100644
index 0000000000..c0a10417d8
--- /dev/null
+++ b/src/shared/bootspec.c
@@ -0,0 +1,654 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2017 Zbigniew Jędrzejewski-Szmek
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdio.h>
+#include <linux/magic.h>
+
+#include "alloc-util.h"
+#include "blkid-util.h"
+#include "bootspec.h"
+#include "conf-files.h"
+#include "def.h"
+#include "device-nodes.h"
+#include "efivars.h"
+#include "fd-util.h"
+#include "fileio.h"
+#include "parse-util.h"
+#include "stat-util.h"
+#include "string-util.h"
+#include "strv.h"
+#include "virt.h"
+
+void boot_entry_free(BootEntry *entry) {
+ assert(entry);
+
+ free(entry->filename);
+ free(entry->title);
+ free(entry->show_title);
+ free(entry->version);
+ free(entry->machine_id);
+ free(entry->architecture);
+ strv_free(entry->options);
+ free(entry->kernel);
+ free(entry->efi);
+ strv_free(entry->initrd);
+ free(entry->device_tree);
+}
+
+int boot_entry_load(const char *path, BootEntry *entry) {
+ _cleanup_fclose_ FILE *f = NULL;
+ unsigned line = 1;
+ _cleanup_(boot_entry_free) BootEntry tmp = {};
+ int r;
+
+ assert(path);
+ assert(entry);
+
+ f = fopen(path, "re");
+ if (!f)
+ return log_error_errno(errno, "Failed to open \"%s\": %m", path);
+
+ tmp.filename = strdup(basename(path));
+ if (!tmp.filename)
+ return log_oom();
+
+ for (;;) {
+ _cleanup_free_ char *buf = NULL;
+ char *p;
+
+ r = read_line(f, LONG_LINE_MAX, &buf);
+ if (r == 0)
+ break;
+ if (r == -ENOBUFS)
+ return log_error_errno(r, "%s:%u: Line too long", path, line);
+ if (r < 0)
+ return log_error_errno(r, "%s:%u: Error while reading: %m", path, line);
+
+ line++;
+
+ if (IN_SET(*strstrip(buf), '#', '\0'))
+ continue;
+
+ p = strchr(buf, ' ');
+ if (!p) {
+ log_warning("%s:%u: Bad syntax", path, line);
+ continue;
+ }
+ *p = '\0';
+ p = strstrip(p + 1);
+
+ if (streq(buf, "title"))
+ r = free_and_strdup(&tmp.title, p);
+ else if (streq(buf, "version"))
+ r = free_and_strdup(&tmp.version, p);
+ else if (streq(buf, "machine-id"))
+ r = free_and_strdup(&tmp.machine_id, p);
+ else if (streq(buf, "architecture"))
+ r = free_and_strdup(&tmp.architecture, p);
+ else if (streq(buf, "options"))
+ r = strv_extend(&tmp.options, p);
+ else if (streq(buf, "linux"))
+ r = free_and_strdup(&tmp.kernel, p);
+ else if (streq(buf, "efi"))
+ r = free_and_strdup(&tmp.efi, p);
+ else if (streq(buf, "initrd"))
+ r = strv_extend(&tmp.initrd, p);
+ else if (streq(buf, "devicetree"))
+ r = free_and_strdup(&tmp.device_tree, p);
+ else {
+ log_notice("%s:%u: Unknown line \"%s\"", path, line, buf);
+ continue;
+ }
+ if (r < 0)
+ return log_error_errno(r, "%s:%u: Error while reading: %m", path, line);
+ }
+
+ *entry = tmp;
+ tmp = (BootEntry) {};
+ return 0;
+}
+
+void boot_config_free(BootConfig *config) {
+ unsigned i;
+
+ assert(config);
+
+ free(config->default_pattern);
+ free(config->timeout);
+ free(config->editor);
+
+ free(config->entry_oneshot);
+ free(config->entry_default);
+
+ for (i = 0; i < config->n_entries; i++)
+ boot_entry_free(config->entries + i);
+ free(config->entries);
+}
+
+int boot_loader_read_conf(const char *path, BootConfig *config) {
+ _cleanup_fclose_ FILE *f = NULL;
+ unsigned line = 1;
+ int r;
+
+ assert(path);
+ assert(config);
+
+ f = fopen(path, "re");
+ if (!f)
+ return log_error_errno(errno, "Failed to open \"%s\": %m", path);
+
+ for (;;) {
+ _cleanup_free_ char *buf = NULL;
+ char *p;
+
+ r = read_line(f, LONG_LINE_MAX, &buf);
+ if (r == 0)
+ break;
+ if (r == -ENOBUFS)
+ return log_error_errno(r, "%s:%u: Line too long", path, line);
+ if (r < 0)
+ return log_error_errno(r, "%s:%u: Error while reading: %m", path, line);
+
+ line++;
+
+ if (IN_SET(*strstrip(buf), '#', '\0'))
+ continue;
+
+ p = strchr(buf, ' ');
+ if (!p) {
+ log_warning("%s:%u: Bad syntax", path, line);
+ continue;
+ }
+ *p = '\0';
+ p = strstrip(p + 1);
+
+ if (streq(buf, "default"))
+ r = free_and_strdup(&config->default_pattern, p);
+ else if (streq(buf, "timeout"))
+ r = free_and_strdup(&config->timeout, p);
+ else if (streq(buf, "editor"))
+ r = free_and_strdup(&config->editor, p);
+ else {
+ log_notice("%s:%u: Unknown line \"%s\"", path, line, buf);
+ continue;
+ }
+ if (r < 0)
+ return log_error_errno(r, "%s:%u: Error while reading: %m", path, line);
+ }
+
+ return 0;
+}
+
+/* This is a direct translation of str_verscmp from boot.c */
+static bool is_digit(int c) {
+ return c >= '0' && c <= '9';
+}
+
+static int c_order(int c) {
+ if (c == '\0')
+ return 0;
+ if (is_digit(c))
+ return 0;
+ else if ((c >= 'a') && (c <= 'z'))
+ return c;
+ else
+ return c + 0x10000;
+}
+
+static int str_verscmp(const char *s1, const char *s2) {
+ const char *os1 = s1;
+ const char *os2 = s2;
+
+ while (*s1 || *s2) {
+ int first;
+
+ while ((*s1 && !is_digit(*s1)) || (*s2 && !is_digit(*s2))) {
+ int order;
+
+ order = c_order(*s1) - c_order(*s2);
+ if (order)
+ return order;
+ s1++;
+ s2++;
+ }
+
+ while (*s1 == '0')
+ s1++;
+ while (*s2 == '0')
+ s2++;
+
+ first = 0;
+ while (is_digit(*s1) && is_digit(*s2)) {
+ if (first == 0)
+ first = *s1 - *s2;
+ s1++;
+ s2++;
+ }
+
+ if (is_digit(*s1))
+ return 1;
+ if (is_digit(*s2))
+ return -1;
+
+ if (first != 0)
+ return first;
+ }
+
+ return strcmp(os1, os2);
+}
+
+static int boot_entry_compare(const void *a, const void *b) {
+ const BootEntry *aa = a;
+ const BootEntry *bb = b;
+
+ return str_verscmp(aa->filename, bb->filename);
+}
+
+int boot_entries_find(const char *dir, BootEntry **ret_entries, size_t *ret_n_entries) {
+ _cleanup_strv_free_ char **files = NULL;
+ char **f;
+ int r;
+ BootEntry *array = NULL;
+ size_t n_allocated = 0, n = 0;
+
+ assert(dir);
+ assert(ret_entries);
+ assert(ret_n_entries);
+
+ r = conf_files_list(&files, ".conf", NULL, 0, dir, NULL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to list files in \"%s\": %m", dir);
+
+ STRV_FOREACH(f, files) {
+ if (!GREEDY_REALLOC0(array, n_allocated, n + 1))
+ return log_oom();
+
+ r = boot_entry_load(*f, array + n);
+ if (r < 0)
+ continue;
+
+ n++;
+ }
+
+ qsort_safe(array, n, sizeof(BootEntry), boot_entry_compare);
+
+ *ret_entries = array;
+ *ret_n_entries = n;
+
+ return 0;
+}
+
+static bool find_nonunique(BootEntry *entries, size_t n_entries, bool *arr) {
+ unsigned i, j;
+ bool non_unique = false;
+
+ assert(entries || n_entries == 0);
+ assert(arr || n_entries == 0);
+
+ for (i = 0; i < n_entries; i++)
+ arr[i] = false;
+
+ for (i = 0; i < n_entries; i++)
+ for (j = 0; j < n_entries; j++)
+ if (i != j && streq(boot_entry_title(entries + i),
+ boot_entry_title(entries + j)))
+ non_unique = arr[i] = arr[j] = true;
+
+ return non_unique;
+}
+
+static int boot_entries_uniquify(BootEntry *entries, size_t n_entries) {
+ char *s;
+ unsigned i;
+ int r;
+ bool arr[n_entries];
+
+ assert(entries || n_entries == 0);
+
+ /* Find _all_ non-unique titles */
+ if (!find_nonunique(entries, n_entries, arr))
+ return 0;
+
+ /* Add version to non-unique titles */
+ for (i = 0; i < n_entries; i++)
+ if (arr[i] && entries[i].version) {
+ r = asprintf(&s, "%s (%s)", boot_entry_title(entries + i), entries[i].version);
+ if (r < 0)
+ return -ENOMEM;
+
+ free_and_replace(entries[i].show_title, s);
+ }
+
+ if (!find_nonunique(entries, n_entries, arr))
+ return 0;
+
+ /* Add machine-id to non-unique titles */
+ for (i = 0; i < n_entries; i++)
+ if (arr[i] && entries[i].machine_id) {
+ r = asprintf(&s, "%s (%s)", boot_entry_title(entries + i), entries[i].machine_id);
+ if (r < 0)
+ return -ENOMEM;
+
+ free_and_replace(entries[i].show_title, s);
+ }
+
+ if (!find_nonunique(entries, n_entries, arr))
+ return 0;
+
+ /* Add file name to non-unique titles */
+ for (i = 0; i < n_entries; i++)
+ if (arr[i]) {
+ r = asprintf(&s, "%s (%s)", boot_entry_title(entries + i), entries[i].filename);
+ if (r < 0)
+ return -ENOMEM;
+
+ free_and_replace(entries[i].show_title, s);
+ }
+
+ return 0;
+}
+
+static int boot_entries_select_default(const BootConfig *config) {
+ int i;
+
+ assert(config);
+
+ if (config->entry_oneshot)
+ for (i = config->n_entries - 1; i >= 0; i--)
+ if (streq(config->entry_oneshot, config->entries[i].filename)) {
+ log_debug("Found default: filename \"%s\" is matched by LoaderEntryOneShot",
+ config->entries[i].filename);
+ return i;
+ }
+
+ if (config->entry_default)
+ for (i = config->n_entries - 1; i >= 0; i--)
+ if (streq(config->entry_default, config->entries[i].filename)) {
+ log_debug("Found default: filename \"%s\" is matched by LoaderEntryDefault",
+ config->entries[i].filename);
+ return i;
+ }
+
+ if (config->default_pattern)
+ for (i = config->n_entries - 1; i >= 0; i--)
+ if (fnmatch(config->default_pattern, config->entries[i].filename, FNM_CASEFOLD) == 0) {
+ log_debug("Found default: filename \"%s\" is matched by pattern \"%s\"",
+ config->entries[i].filename, config->default_pattern);
+ return i;
+ }
+
+ if (config->n_entries > 0)
+ log_debug("Found default: last entry \"%s\"", config->entries[config->n_entries - 1].filename);
+ else
+ log_debug("Found no default boot entry :(");
+
+ return config->n_entries - 1; /* -1 means "no default" */
+}
+
+int boot_entries_load_config(const char *esp_path, BootConfig *config) {
+ const char *p;
+ int r;
+
+ assert(esp_path);
+ assert(config);
+
+ p = strjoina(esp_path, "/loader/loader.conf");
+ r = boot_loader_read_conf(p, config);
+ if (r < 0)
+ return log_error_errno(r, "Failed to read boot config from \"%s\": %m", p);
+
+ p = strjoina(esp_path, "/loader/entries");
+ r = boot_entries_find(p, &config->entries, &config->n_entries);
+ if (r < 0)
+ return log_error_errno(r, "Failed to read boot entries from \"%s\": %m", p);
+
+ r = boot_entries_uniquify(config->entries, config->n_entries);
+ if (r < 0)
+ return log_error_errno(r, "Failed to uniquify boot entries: %m");
+
+ r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderEntryOneShot", &config->entry_oneshot);
+ if (r < 0 && r != -ENOENT)
+ return log_error_errno(r, "Failed to read EFI var \"LoaderEntryOneShot\": %m");
+
+ r = efi_get_variable_string(EFI_VENDOR_LOADER, "LoaderEntryDefault", &config->entry_default);
+ if (r < 0 && r != -ENOENT)
+ return log_error_errno(r, "Failed to read EFI var \"LoaderEntryDefault\": %m");
+
+ config->default_entry = boot_entries_select_default(config);
+ return 0;
+}
+
+/********************************************************************************/
+
+static int verify_esp(
+ const char *p,
+ bool searching,
+ bool unprivileged_mode,
+ uint32_t *ret_part,
+ uint64_t *ret_pstart,
+ uint64_t *ret_psize,
+ sd_id128_t *ret_uuid) {
+#if HAVE_BLKID
+ _cleanup_blkid_free_probe_ blkid_probe b = NULL;
+ char t[DEV_NUM_PATH_MAX];
+ const char *v;
+#endif
+ uint64_t pstart = 0, psize = 0;
+ struct stat st, st2;
+ const char *t2;
+ struct statfs sfs;
+ sd_id128_t uuid = SD_ID128_NULL;
+ uint32_t part = 0;
+ int r;
+
+ assert(p);
+
+ /* Non-root user can only check the status, so if an error occured in the following, it does not cause any
+ * issues. Let's also, silence the error messages. */
+
+ if (statfs(p, &sfs) < 0) {
+ /* If we are searching for the mount point, don't generate a log message if we can't find the path */
+ if (errno == ENOENT && searching)
+ return -ENOENT;
+
+ return log_full_errno(unprivileged_mode && errno == EACCES ? LOG_DEBUG : LOG_ERR, errno,
+ "Failed to check file system type of \"%s\": %m", p);
+ }
+
+ if (!F_TYPE_EQUAL(sfs.f_type, MSDOS_SUPER_MAGIC)) {
+ if (searching)
+ return -EADDRNOTAVAIL;
+
+ log_error("File system \"%s\" is not a FAT EFI System Partition (ESP) file system.", p);
+ return -ENODEV;
+ }
+
+ if (stat(p, &st) < 0)
+ return log_full_errno(unprivileged_mode && errno == EACCES ? LOG_DEBUG : LOG_ERR, errno,
+ "Failed to determine block device node of \"%s\": %m", p);
+
+ if (major(st.st_dev) == 0) {
+ log_error("Block device node of %p is invalid.", p);
+ return -ENODEV;
+ }
+
+ t2 = strjoina(p, "/..");
+ r = stat(t2, &st2);
+ if (r < 0)
+ return log_full_errno(unprivileged_mode && errno == EACCES ? LOG_DEBUG : LOG_ERR, errno,
+ "Failed to determine block device node of parent of \"%s\": %m", p);
+
+ if (st.st_dev == st2.st_dev) {
+ log_error("Directory \"%s\" is not the root of the EFI System Partition (ESP) file system.", p);
+ return -ENODEV;
+ }
+
+ /* In a container we don't have access to block devices, skip this part of the verification, we trust the
+ * container manager set everything up correctly on its own. Also skip the following verification for non-root user. */
+ if (detect_container() > 0 || unprivileged_mode)
+ goto finish;
+
+#if HAVE_BLKID
+ xsprintf_dev_num_path(t, "block", st.st_dev);
+ errno = 0;
+ b = blkid_new_probe_from_filename(t);
+ if (!b)
+ return log_error_errno(errno ?: ENOMEM, "Failed to open file system \"%s\": %m", p);
+
+ blkid_probe_enable_superblocks(b, 1);
+ blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
+ blkid_probe_enable_partitions(b, 1);
+ blkid_probe_set_partitions_flags(b, BLKID_PARTS_ENTRY_DETAILS);
+
+ errno = 0;
+ r = blkid_do_safeprobe(b);
+ if (r == -2) {
+ log_error("File system \"%s\" is ambiguous.", p);
+ return -ENODEV;
+ } else if (r == 1) {
+ log_error("File system \"%s\" does not contain a label.", p);
+ return -ENODEV;
+ } else if (r != 0)
+ return log_error_errno(errno ?: EIO, "Failed to probe file system \"%s\": %m", p);
+
+ errno = 0;
+ r = blkid_probe_lookup_value(b, "TYPE", &v, NULL);
+ if (r != 0)
+ return log_error_errno(errno ?: EIO, "Failed to probe file system type \"%s\": %m", p);
+ if (!streq(v, "vfat")) {
+ log_error("File system \"%s\" is not FAT.", p);
+ return -ENODEV;
+ }
+
+ errno = 0;
+ r = blkid_probe_lookup_value(b, "PART_ENTRY_SCHEME", &v, NULL);
+ if (r != 0)
+ return log_error_errno(errno ?: EIO, "Failed to probe partition scheme \"%s\": %m", p);
+ if (!streq(v, "gpt")) {
+ log_error("File system \"%s\" is not on a GPT partition table.", p);
+ return -ENODEV;
+ }
+
+ errno = 0;
+ r = blkid_probe_lookup_value(b, "PART_ENTRY_TYPE", &v, NULL);
+ if (r != 0)
+ return log_error_errno(errno ?: EIO, "Failed to probe partition type UUID \"%s\": %m", p);
+ if (!streq(v, "c12a7328-f81f-11d2-ba4b-00a0c93ec93b")) {
+ log_error("File system \"%s\" has wrong type for an EFI System Partition (ESP).", p);
+ return -ENODEV;
+ }
+
+ errno = 0;
+ r = blkid_probe_lookup_value(b, "PART_ENTRY_UUID", &v, NULL);
+ if (r != 0)
+ return log_error_errno(errno ?: EIO, "Failed to probe partition entry UUID \"%s\": %m", p);
+ r = sd_id128_from_string(v, &uuid);
+ if (r < 0) {
+ log_error("Partition \"%s\" has invalid UUID \"%s\".", p, v);
+ return -EIO;
+ }
+
+ errno = 0;
+ r = blkid_probe_lookup_value(b, "PART_ENTRY_NUMBER", &v, NULL);
+ if (r != 0)
+ return log_error_errno(errno ?: EIO, "Failed to probe partition number \"%s\": m", p);
+ r = safe_atou32(v, &part);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse PART_ENTRY_NUMBER field.");
+
+ errno = 0;
+ r = blkid_probe_lookup_value(b, "PART_ENTRY_OFFSET", &v, NULL);
+ if (r != 0)
+ return log_error_errno(errno ?: EIO, "Failed to probe partition offset \"%s\": %m", p);
+ r = safe_atou64(v, &pstart);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse PART_ENTRY_OFFSET field.");
+
+ errno = 0;
+ r = blkid_probe_lookup_value(b, "PART_ENTRY_SIZE", &v, NULL);
+ if (r != 0)
+ return log_error_errno(errno ?: EIO, "Failed to probe partition size \"%s\": %m", p);
+ r = safe_atou64(v, &psize);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse PART_ENTRY_SIZE field.");
+#endif
+
+finish:
+ if (ret_part)
+ *ret_part = part;
+ if (ret_pstart)
+ *ret_pstart = pstart;
+ if (ret_psize)
+ *ret_psize = psize;
+ if (ret_uuid)
+ *ret_uuid = uuid;
+
+ return 0;
+}
+
+int find_esp_and_warn(
+ const char *path,
+ bool unprivileged_mode,
+ char **ret_path,
+ uint32_t *ret_part,
+ uint64_t *ret_pstart,
+ uint64_t *ret_psize,
+ sd_id128_t *ret_uuid) {
+
+ int r;
+
+ /* This logs about all errors except:
+ *
+ * -ENOKEY → when we can't find the partition
+ * -EACCESS → when unprivileged_mode is true, and we can't access something
+ */
+
+ if (path) {
+ r = verify_esp(path, false, unprivileged_mode, ret_part, ret_pstart, ret_psize, ret_uuid);
+ if (r < 0)
+ return r;
+
+ goto found;
+ }
+
+ FOREACH_STRING(path, "/efi", "/boot", "/boot/efi") {
+
+ r = verify_esp(path, true, unprivileged_mode, ret_part, ret_pstart, ret_psize, ret_uuid);
+ if (r >= 0)
+ goto found;
+ if (!IN_SET(r, -ENOENT, -EADDRNOTAVAIL)) /* This one is not it */
+ return r;
+ }
+
+ /* No logging here */
+ return -ENOKEY;
+
+found:
+ if (ret_path) {
+ char *c;
+
+ c = strdup(path);
+ if (!c)
+ return log_oom();
+
+ *ret_path = c;
+ }
+
+ return 0;
+}
diff --git a/src/shared/bootspec.h b/src/shared/bootspec.h
new file mode 100644
index 0000000000..d9c641bf08
--- /dev/null
+++ b/src/shared/bootspec.h
@@ -0,0 +1,64 @@
+/***
+ This file is part of systemd.
+
+ Copyright 2017 Zbigniew Jędrzejewski-Szmek
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#pragma once
+
+#include <stdlib.h>
+
+typedef struct BootEntry {
+ char *filename;
+
+ char *title;
+ char *show_title;
+ char *version;
+ char *machine_id;
+ char *architecture;
+ char **options;
+ char *kernel; /* linux is #defined to 1, yikes! */
+ char *efi;
+ char **initrd;
+ char *device_tree;
+} BootEntry;
+
+typedef struct BootConfig {
+ char *default_pattern;
+ char *timeout;
+ char *editor;
+
+ char *entry_oneshot;
+ char *entry_default;
+
+ BootEntry *entries;
+ size_t n_entries;
+ ssize_t default_entry;
+} BootConfig;
+
+void boot_entry_free(BootEntry *entry);
+int boot_entry_load(const char *path, BootEntry *entry);
+int boot_entries_find(const char *dir, BootEntry **entries, size_t *n_entries);
+
+int boot_loader_read_conf(const char *path, BootConfig *config);
+void boot_config_free(BootConfig *config);
+int boot_entries_load_config(const char *esp_path, BootConfig *config);
+
+static inline const char* boot_entry_title(const BootEntry *entry) {
+ return entry->show_title ?: entry->title ?: entry->filename;
+}
+
+int find_esp_and_warn(const char *path, bool unprivileged_mode, char **ret_path, uint32_t *ret_part, uint64_t *ret_pstart, uint64_t *ret_psize, sd_id128_t *ret_uuid);
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index e191f8c93e..b58abed2b5 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -28,6 +29,7 @@
#include "errno-list.h"
#include "escape.h"
#include "hashmap.h"
+#include "hexdecoct.h"
#include "hostname-util.h"
#include "in-addr-util.h"
#include "list.h"
@@ -132,9 +134,12 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
} else if (streq(field, "EnvironmentFile")) {
- r = sd_bus_message_append(m, "sv", "EnvironmentFiles", "a(sb)", 1,
- eq[0] == '-' ? eq + 1 : eq,
- eq[0] == '-');
+ if (isempty(eq))
+ r = sd_bus_message_append(m, "sv", "EnvironmentFiles", "a(sb)", 0);
+ else
+ r = sd_bus_message_append(m, "sv", "EnvironmentFiles", "a(sb)", 1,
+ eq[0] == '-' ? eq + 1 : eq,
+ eq[0] == '-');
goto finish;
} else if (STR_IN_SET(field, "AccuracySec", "RandomizedDelaySec", "RuntimeMaxSec")) {
@@ -156,7 +161,32 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
r = sd_bus_message_append(m, "sv", n, "t", t);
goto finish;
- } else if (STR_IN_SET(field, "MemoryLow", "MemoryHigh", "MemoryMax", "MemoryLimit")) {
+ } else if (streq(field, "LogExtraFields")) {
+
+ r = sd_bus_message_append(m, "s", "LogExtraFields");
+ if (r < 0)
+ goto finish;
+
+ r = sd_bus_message_open_container(m, 'v', "aay");
+ if (r < 0)
+ goto finish;
+
+ r = sd_bus_message_open_container(m, 'a', "ay");
+ if (r < 0)
+ goto finish;
+
+ r = sd_bus_message_append_array(m, 'y', eq, strlen(eq));
+ if (r < 0)
+ goto finish;
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ goto finish;
+
+ r = sd_bus_message_close_container(m);
+ goto finish;
+
+ } else if (STR_IN_SET(field, "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit")) {
uint64_t bytes;
if (isempty(eq) || streq(eq, "infinity"))
@@ -183,6 +213,51 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
r = sd_bus_message_append(m, "sv", field, "t", bytes);
goto finish;
+
+ } else if (streq(field, "Delegate")) {
+
+ r = parse_boolean(eq);
+ if (r < 0) {
+ const char *p = eq;
+
+ r = sd_bus_message_append(m, "s", "DelegateControllers");
+ if (r < 0)
+ goto finish;
+
+ r = sd_bus_message_open_container(m, 'v', "as");
+ if (r < 0)
+ goto finish;
+
+ r = sd_bus_message_open_container(m, 'a', "s");
+ if (r < 0)
+ goto finish;
+
+ for (;;) {
+ _cleanup_free_ char *word = NULL;
+
+ r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
+ if (r == 0)
+ break;
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0)
+ return log_error_errno(r, "Invalid syntax: %s", eq);
+
+ r = sd_bus_message_append(m, "s", word);
+ if (r < 0)
+ goto finish;
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ goto finish;
+
+ r = sd_bus_message_close_container(m);
+ } else
+ r = sd_bus_message_append(m, "sv", "Delegate", "b", r);
+
+ goto finish;
+
} else if (streq(field, "TasksMax")) {
uint64_t t;
@@ -203,6 +278,50 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
r = sd_bus_message_append(m, "sv", "TasksMax", "t", t);
goto finish;
+
+ } else if (STR_IN_SET(field, "StandardInput", "StandardOutput", "StandardError")) {
+ const char *n, *appended;
+
+ n = startswith(eq, "fd:");
+ if (n) {
+ appended = strjoina(field, "FileDescriptorName");
+ r = sd_bus_message_append(m, "sv", appended, "s", n);
+
+ } else if ((n = startswith(eq, "file:"))) {
+ appended = strjoina(field, "File");
+ r = sd_bus_message_append(m, "sv", appended, "s", n);
+ } else
+ r = sd_bus_message_append(m, "sv", field, "s", eq);
+
+ goto finish;
+
+ } else if (streq(field, "StandardInputText")) {
+ _cleanup_free_ char *unescaped = NULL;
+
+ r = cunescape(eq, 0, &unescaped);
+ if (r < 0)
+ return log_error_errno(r, "Failed to unescape text '%s': %m", eq);
+
+ if (!strextend(&unescaped, "\n", NULL))
+ return log_oom();
+
+ /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic
+ * interface anyway */
+
+ r = sd_bus_message_append(m, "s", "StandardInputData");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'v', "ay");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_array(m, 'y', unescaped, strlen(unescaped));
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+ goto finish;
}
r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
@@ -238,7 +357,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
"TasksAccounting", "IPAccounting", "SendSIGHUP", "SendSIGKILL", "WakeSystem",
"DefaultDependencies", "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate",
"RemainAfterExit", "PrivateTmp", "PrivateDevices", "PrivateNetwork", "PrivateUsers",
- "NoNewPrivileges", "SyslogLevelPrefix", "Delegate", "RemainAfterElapse",
+ "NoNewPrivileges", "SyslogLevelPrefix", "RemainAfterElapse", "Persistent",
"MemoryDenyWriteExecute", "RestrictRealtime", "DynamicUser", "RemoveIPC",
"ProtectKernelTunables", "ProtectKernelModules", "ProtectControlGroups", "MountAPIVFS",
"CPUSchedulingResetOnFork", "LockPersonality")) {
@@ -253,10 +372,8 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
uint64_t u;
r = cg_weight_parse(eq, &u);
- if (r < 0) {
- log_error("Failed to parse %s value %s.", field, eq);
- return -EINVAL;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
r = sd_bus_message_append(m, "v", "t", u);
@@ -264,10 +381,8 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
uint64_t u;
r = cg_cpu_shares_parse(eq, &u);
- if (r < 0) {
- log_error("Failed to parse %s value %s.", field, eq);
- return -EINVAL;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
r = sd_bus_message_append(m, "v", "t", u);
@@ -275,10 +390,8 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
uint64_t u;
r = cg_weight_parse(eq, &u);
- if (r < 0) {
- log_error("Failed to parse %s value %s.", field, eq);
- return -EINVAL;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
r = sd_bus_message_append(m, "v", "t", u);
@@ -286,25 +399,42 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
uint64_t u;
r = cg_blkio_weight_parse(eq, &u);
- if (r < 0) {
- log_error("Failed to parse %s value %s.", field, eq);
- return -EINVAL;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
r = sd_bus_message_append(m, "v", "t", u);
} else if (STR_IN_SET(field,
"User", "Group", "DevicePolicy", "KillMode",
"UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
- "StandardInput", "StandardOutput", "StandardError",
"Description", "Slice", "Type", "WorkingDirectory",
"RootDirectory", "SyslogIdentifier", "ProtectSystem",
"ProtectHome", "SELinuxContext", "Restart", "RootImage",
"NotifyAccess", "RuntimeDirectoryPreserve", "Personality",
- "KeyringMode"))
+ "KeyringMode", "CollectMode", "FailureAction", "SuccessAction",
+ "OnCalendar"))
+
r = sd_bus_message_append(m, "v", "s", eq);
- else if (STR_IN_SET(field, "AppArmorProfile", "SmackProcessLabel")) {
+ else if (streq(field, "StandardInputData")) {
+ _cleanup_free_ void *decoded = NULL;
+ size_t sz;
+
+ r = unbase64mem(eq, (size_t) -1, &decoded, &sz);
+ if (r < 0)
+ return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq);
+
+ r = sd_bus_message_open_container(m, 'v', "ay");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_array(m, 'y', decoded, sz);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_close_container(m);
+
+ } else if (STR_IN_SET(field, "AppArmorProfile", "SmackProcessLabel")) {
bool ignore;
const char *s;
@@ -318,7 +448,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
r = sd_bus_message_append(m, "v", "(bs)", ignore, s);
- } else if (streq(field, "SyslogLevel")) {
+ } else if (STR_IN_SET(field, "SyslogLevel", "LogLevelMax")) {
int level;
level = log_level_from_string(eq);
@@ -343,10 +473,8 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
} else if (streq(field, "SecureBits")) {
r = secure_bits_from_string(eq);
- if (r < 0) {
- log_error("Failed to parse %s value %s.", field, eq);
- return -EINVAL;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
r = sd_bus_message_append(m, "v", "i", r);
@@ -362,10 +490,8 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
}
r = capability_set_from_string(p, &sum);
- if (r < 0) {
- log_error("Failed to parse %s value %s.", field, eq);
- return -EINVAL;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
sum = invert ? ~sum : sum;
@@ -421,10 +547,8 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
bytes = CGROUP_LIMIT_MAX;
} else {
r = parse_size(bandwidth, 1000, &bytes);
- if (r < 0) {
- log_error("Failed to parse byte value %s.", bandwidth);
- return -EINVAL;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse byte value %s: %m", bandwidth);
}
r = sd_bus_message_append(m, "v", "a(st)", 1, path, bytes);
@@ -453,10 +577,9 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
}
r = safe_atou64(weight, &u);
- if (r < 0) {
- log_error("Failed to parse %s value %s.", field, weight);
- return -EINVAL;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value %s: %m", field, weight);
+
r = sd_bus_message_append(m, "v", "a(st)", 1, path, u);
}
@@ -511,7 +634,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
return bus_log_create_error(r);
prefix.in6 = (struct in6_addr) {
- .__in6_u.__u6_addr32[0] = htobe32(0xfe800000)
+ .s6_addr32[0] = htobe32(0xfe800000)
};
r = bus_append_ip_address_access(m, AF_INET6, &prefix, 64);
if (r < 0)
@@ -527,7 +650,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
return bus_log_create_error(r);
prefix.in6 = (struct in6_addr) {
- .__in6_u.__u6_addr32[0] = htobe32(0xff000000)
+ .s6_addr32[0] = htobe32(0xff000000)
};
r = bus_append_ip_address_access(m, AF_INET6, &prefix, 8);
if (r < 0)
@@ -584,8 +707,9 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
if (r < 0)
return bus_log_create_error(r);
- if (cpuset)
- sd_bus_message_append_array(m, 'y', cpuset, CPU_ALLOC_SIZE(ncpus));
+ r = sd_bus_message_append_array(m, 'y', cpuset, CPU_ALLOC_SIZE(ncpus));
+ if (r < 0)
+ return bus_log_create_error(r);
r = sd_bus_message_close_container(m);
@@ -598,16 +722,11 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
r = sd_bus_message_append(m, "v", "i", (int32_t) n);
-#if HAVE_SECCOMP
-
} else if (streq(field, "SystemCallFilter")) {
int whitelist;
+ _cleanup_strv_free_ char **l = NULL;
const char *p;
- r = sd_bus_message_open_container(m, 'v', "bas");
- if (r < 0)
- return bus_log_create_error(r);
-
p = eq;
if (*p == '~') {
whitelist = 0;
@@ -615,18 +734,10 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
} else
whitelist = 1;
- r = sd_bus_message_append_basic(m, 'b', &whitelist);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'a', "s");
- if (r < 0)
- return bus_log_create_error(r);
-
if (whitelist != 0) {
- r = sd_bus_message_append_basic(m, 's', "@default");
+ r = strv_extend(&l, "@default");
if (r < 0)
- return bus_log_create_error(r);
+ return log_oom();
}
for (;;) {
@@ -638,16 +749,34 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
if (r == 0)
break;
- r = sd_bus_message_append_basic(m, 's', word);
+ r = strv_extend(&l, word);
if (r < 0)
- return bus_log_create_error(r);
+ return log_oom();
}
+ r = sd_bus_message_open_container(m, 'v', "(bas)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'r', "bas");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_basic(m, 'b', &whitelist);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_strv(m, l);
+ if (r < 0)
+ return bus_log_create_error(r);
+
r = sd_bus_message_close_container(m);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
} else if (streq(field, "SystemCallArchitectures")) {
const char *p;
@@ -683,35 +812,23 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
} else if (streq(field, "SystemCallErrorNumber")) {
int n;
- n = errno_from_name(eq);
- if (n < 0)
+ n = parse_errno(eq);
+ if (n <= 0)
return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
r = sd_bus_message_append(m, "v", "i", (int32_t) n);
} else if (streq(field, "RestrictAddressFamilies")) {
int whitelist;
- const char *p;
-
- r = sd_bus_message_open_container(m, 'v', "bas");
- if (r < 0)
- return bus_log_create_error(r);
+ _cleanup_strv_free_ char **l = NULL;
+ const char *p = eq;
- p = eq;
if (*p == '~') {
whitelist = 0;
p++;
} else
whitelist = 1;
- r = sd_bus_message_append_basic(m, 'b', &whitelist);
- if (r < 0)
- return bus_log_create_error(r);
-
- r = sd_bus_message_open_container(m, 'a', "s");
- if (r < 0)
- return bus_log_create_error(r);
-
for (;;) {
_cleanup_free_ char *word = NULL;
@@ -721,18 +838,34 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
if (r == 0)
break;
- r = sd_bus_message_append_basic(m, 's', word);
+ r = strv_extend(&l, word);
if (r < 0)
- return bus_log_create_error(r);
+ return log_oom();
}
- r = sd_bus_message_close_container(m);
+ r = sd_bus_message_open_container(m, 'v', "(bas)");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_open_container(m, 'r', "bas");
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_basic(m, 'b', &whitelist);
+ if (r < 0)
+ return bus_log_create_error(r);
+
+ r = sd_bus_message_append_strv(m, l);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
-#endif
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return bus_log_create_error(r);
} else if (streq(field, "FileDescriptorStoreMax")) {
unsigned u;
@@ -776,10 +909,8 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
_cleanup_free_ char *word = NULL;
r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE);
- if (r < 0) {
- log_error("Failed to parse Environment value %s", eq);
- return -EINVAL;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse Environment value %s: %m", eq);
if (r == 0)
break;
@@ -826,20 +957,16 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
nsec_t n;
r = parse_nsec(eq, &n);
- if (r < 0) {
- log_error("Failed to parse %s value %s", field, eq);
- return -EINVAL;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
r = sd_bus_message_append(m, "v", "t", n);
} else if (streq(field, "OOMScoreAdjust")) {
int oa;
r = safe_atoi(eq, &oa);
- if (r < 0) {
- log_error("Failed to parse %s value %s", field, eq);
- return -EINVAL;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
if (!oom_score_adjust_is_valid(oa)) {
log_error("OOM score adjust value out of range");
@@ -864,10 +991,8 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
size_t offset;
r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
- if (r < 0) {
- log_error("Failed to parse %s value %s", field, eq);
- return -EINVAL;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
if (r == 0)
break;
@@ -912,10 +1037,8 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
_cleanup_free_ char *word = NULL;
r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
- if (r < 0) {
- log_error("Failed to parse %s value %s", field, eq);
- return -EINVAL;
- }
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
if (r == 0)
break;
@@ -1081,8 +1204,107 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
return r;
r = sd_bus_message_close_container(m);
+
+ } else if (STR_IN_SET(field, "ExecStartPre", "ExecStart", "ExecStartPost",
+ "ExecReload", "ExecStop", "ExecStopPost")) {
+
+ bool ignore_failure = false, explicit_path = false, done = false;
+ _cleanup_strv_free_ char **l = NULL;
+ _cleanup_free_ char *path = NULL;
+
+ do {
+ switch (*eq) {
+
+ case '-':
+ if (ignore_failure)
+ done = true;
+ else {
+ ignore_failure = true;
+ eq++;
+ }
+ break;
+
+ case '@':
+ if (explicit_path)
+ done = true;
+ else {
+ explicit_path = true;
+ eq++;
+ }
+ break;
+
+ case '+':
+ case '!':
+ /* The bus API doesn't support +, ! and !! currently, unfortunately. :-( */
+ log_error("Sorry, but +, ! and !! are currently not supported for transient services.");
+ return -EOPNOTSUPP;
+
+ default:
+ done = true;
+ break;
+ }
+ } while (!done);
+
+ if (explicit_path) {
+ r = extract_first_word(&eq, &path, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse path: %m");
+ }
+
+ r = strv_split_extract(&l, eq, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse command line: %m");
+
+ r = sd_bus_message_open_container(m, 'v', "a(sasb)");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_open_container(m, 'a', "(sasb)");
+ if (r < 0)
+ return r;
+
+ if (strv_length(l) > 0) {
+
+ r = sd_bus_message_open_container(m, 'r', "sasb");
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(m, "s", path ?: l[0]);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append_strv(m, l);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_append(m, "b", ignore_failure);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return r;
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ return r;
+
+ r = sd_bus_message_close_container(m);
+
+ } else if (STR_IN_SET(field,
+ "OnActiveSec", "OnBootSec", "OnStartupSec",
+ "OnUnitActiveSec","OnUnitInactiveSec")) {
+ usec_t t;
+
+ r = parse_sec(eq, &t);
+ if (r < 0)
+ return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
+
+ r = sd_bus_message_append(m, "v", "t", t);
+
} else {
- log_error("Unknown assignment %s.", assignment);
+ log_error("Unknown assignment: %s", assignment);
return -EINVAL;
}
@@ -1290,7 +1512,7 @@ static void log_job_error_with_service_result(const char* service, const char *r
service_shell_quoted = shell_maybe_quote(service, ESCAPE_BACKSLASH);
- if (extra_args) {
+ if (!strv_isempty((char**) extra_args)) {
_cleanup_free_ char *t;
t = strv_join((char**) extra_args, " ");
@@ -1471,7 +1693,7 @@ int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, Un
if (r < 0)
return bus_log_parse_error(r);
- unit_file_dump_changes(0, NULL, *changes, *n_changes, false);
+ unit_file_dump_changes(0, NULL, *changes, *n_changes, quiet);
return 0;
}
diff --git a/src/shared/bus-unit-util.h b/src/shared/bus-unit-util.h
index d102ea180e..1a137e8b84 100644
--- a/src/shared/bus-unit-util.h
+++ b/src/shared/bus-unit-util.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c
index 7609d9c522..7a185461a3 100644
--- a/src/shared/bus-util.c
+++ b/src/shared/bus-util.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -553,12 +554,7 @@ int bus_verify_polkit_async(
void bus_verify_polkit_async_registry_free(Hashmap *registry) {
#if ENABLE_POLKIT
- AsyncPolkitQuery *q;
-
- while ((q = hashmap_steal_first(registry)))
- async_polkit_query_free(q);
-
- hashmap_free(registry);
+ hashmap_free_with_destructor(registry, async_polkit_query_free);
#endif
}
@@ -664,7 +660,7 @@ int bus_connect_user_systemd(sd_bus **_bus) {
printf(fmt "\n", __VA_ARGS__); \
else \
printf("%s=" fmt "\n", name, __VA_ARGS__); \
- } while(0)
+ } while (0)
int bus_print_property(const char *name, sd_bus_message *property, bool value, bool all) {
char type;
diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h
index d9ce4263bb..a9f4969d7d 100644
--- a/src/shared/bus-util.h
+++ b/src/shared/bus-util.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c
index 436130edea..0ddae95434 100644
--- a/src/shared/cgroup-show.c
+++ b/src/shared/cgroup-show.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
diff --git a/src/shared/cgroup-show.h b/src/shared/cgroup-show.h
index 1764f76744..efa597aad0 100644
--- a/src/shared/cgroup-show.h
+++ b/src/shared/cgroup-show.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/clean-ipc.c b/src/shared/clean-ipc.c
index 64f81bb5d3..7e2ef4a8eb 100644
--- a/src/shared/clean-ipc.c
+++ b/src/shared/clean-ipc.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
diff --git a/src/shared/clean-ipc.h b/src/shared/clean-ipc.h
index c04ed3596b..0ade561b3f 100644
--- a/src/shared/clean-ipc.h
+++ b/src/shared/clean-ipc.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/condition.c b/src/shared/condition.c
index 74d5e854e1..3f32dfb7b6 100644
--- a/src/shared/condition.c
+++ b/src/shared/condition.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -54,6 +55,7 @@
#include "stat-util.h"
#include "string-table.h"
#include "string-util.h"
+#include "tomoyo-util.h"
#include "user-util.h"
#include "util.h"
#include "virt.h"
@@ -76,8 +78,7 @@ Condition* condition_new(ConditionType type, const char *parameter, bool trigger
r = free_and_strdup(&c->parameter, parameter);
if (r < 0) {
- free(c);
- return NULL;
+ return mfree(c);
}
return c;
@@ -156,7 +157,7 @@ static int condition_test_user(Condition *c) {
return id == getuid() || id == geteuid();
if (streq("@system", c->parameter))
- return getuid() <= SYSTEM_UID_MAX || geteuid() <= SYSTEM_UID_MAX;
+ return uid_is_system(getuid()) || uid_is_system(geteuid());
username = getusername_malloc();
if (!username)
@@ -301,6 +302,8 @@ static int condition_test_security(Condition *c) {
return use_audit();
if (streq(c->parameter, "ima"))
return use_ima();
+ if (streq(c->parameter, "tomoyo"))
+ return mac_tomoyo_use();
return false;
}
diff --git a/src/shared/condition.h b/src/shared/condition.h
index d0b592bc43..534906b6d6 100644
--- a/src/shared/condition.h
+++ b/src/shared/condition.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c
index c304ae3334..daddb7cf20 100644
--- a/src/shared/conf-parser.c
+++ b/src/shared/conf-parser.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -121,17 +122,18 @@ int config_item_perf_lookup(
}
/* Run the user supplied parser for an assignment */
-static int next_assignment(const char *unit,
- const char *filename,
- unsigned line,
- ConfigItemLookup lookup,
- const void *table,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- const char *rvalue,
- bool relaxed,
- void *userdata) {
+static int next_assignment(
+ const char *unit,
+ const char *filename,
+ unsigned line,
+ ConfigItemLookup lookup,
+ const void *table,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ const char *rvalue,
+ ConfigParseFlags flags,
+ void *userdata) {
ConfigParserCallback func = NULL;
int ltype = 0;
@@ -157,26 +159,26 @@ static int next_assignment(const char *unit,
}
/* Warn about unknown non-extension fields. */
- if (!relaxed && !startswith(lvalue, "X-"))
+ if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(lvalue, "X-"))
log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown lvalue '%s' in section '%s'", lvalue, section);
return 0;
}
/* Parse a variable assignment line */
-static int parse_line(const char* unit,
- const char *filename,
- unsigned line,
- const char *sections,
- ConfigItemLookup lookup,
- const void *table,
- bool relaxed,
- bool allow_include,
- char **section,
- unsigned *section_line,
- bool *section_ignored,
- char *l,
- void *userdata) {
+static int parse_line(
+ const char* unit,
+ const char *filename,
+ unsigned line,
+ const char *sections,
+ ConfigItemLookup lookup,
+ const void *table,
+ ConfigParseFlags flags,
+ char **section,
+ unsigned *section_line,
+ bool *section_ignored,
+ char *l,
+ void *userdata) {
char *e;
@@ -186,7 +188,6 @@ static int parse_line(const char* unit,
assert(l);
l = strstrip(l);
-
if (!*l)
return 0;
@@ -205,7 +206,7 @@ static int parse_line(const char* unit,
*
* Support for them should be eventually removed. */
- if (!allow_include) {
+ if (!(flags & CONFIG_PARSE_ALLOW_INCLUDE)) {
log_syntax(unit, LOG_ERR, filename, line, 0, ".include not allowed here. Ignoring.");
return 0;
}
@@ -214,7 +215,7 @@ static int parse_line(const char* unit,
if (!fn)
return -ENOMEM;
- return config_parse(unit, fn, NULL, sections, lookup, table, relaxed, false, false, userdata);
+ return config_parse(unit, fn, NULL, sections, lookup, table, flags, userdata);
}
if (*l == '[') {
@@ -235,7 +236,7 @@ static int parse_line(const char* unit,
if (sections && !nulstr_contains(sections, n)) {
- if (!relaxed && !startswith(n, "X-"))
+ if (!(flags & CONFIG_PARSE_RELAXED) && !startswith(n, "X-"))
log_syntax(unit, LOG_WARNING, filename, line, 0, "Unknown section '%s'. Ignoring.", n);
free(n);
@@ -254,7 +255,7 @@ static int parse_line(const char* unit,
if (sections && !*section) {
- if (!relaxed && !*section_ignored)
+ if (!(flags & CONFIG_PARSE_RELAXED) && !*section_ignored)
log_syntax(unit, LOG_WARNING, filename, line, 0, "Assignment outside of section. Ignoring.");
return 0;
@@ -278,7 +279,7 @@ static int parse_line(const char* unit,
*section_line,
strstrip(l),
strstrip(e),
- relaxed,
+ flags,
userdata);
}
@@ -289,15 +290,13 @@ int config_parse(const char *unit,
const char *sections,
ConfigItemLookup lookup,
const void *table,
- bool relaxed,
- bool allow_include,
- bool warn,
+ ConfigParseFlags flags,
void *userdata) {
_cleanup_free_ char *section = NULL, *continuation = NULL;
_cleanup_fclose_ FILE *ours = NULL;
unsigned line = 0, section_line = 0;
- bool section_ignored = false, allow_bom = true;
+ bool section_ignored = false;
int r;
assert(filename);
@@ -308,7 +307,7 @@ int config_parse(const char *unit,
if (!f) {
/* Only log on request, except for ENOENT,
* since we return 0 to the caller. */
- if (warn || errno == ENOENT)
+ if ((flags & CONFIG_PARSE_WARN) || errno == ENOENT)
log_full(errno == ENOENT ? LOG_DEBUG : LOG_ERR,
"Failed to open configuration file '%s': %m", filename);
return errno == ENOENT ? 0 : -errno;
@@ -319,52 +318,50 @@ int config_parse(const char *unit,
for (;;) {
_cleanup_free_ char *buf = NULL;
- char *l, *p, *c = NULL, *e;
bool escaped = false;
+ char *l, *p, *e;
r = read_line(f, LONG_LINE_MAX, &buf);
if (r == 0)
break;
if (r == -ENOBUFS) {
- if (warn)
+ if (flags & CONFIG_PARSE_WARN)
log_error_errno(r, "%s:%u: Line too long", filename, line);
return r;
}
if (r < 0) {
- if (warn)
+ if (CONFIG_PARSE_WARN)
log_error_errno(r, "%s:%u: Error while reading configuration file: %m", filename, line);
return r;
}
l = buf;
- if (allow_bom) {
+ if (!(flags & CONFIG_PARSE_REFUSE_BOM)) {
char *q;
q = startswith(buf, UTF8_BYTE_ORDER_MARK);
if (q) {
l = q;
- allow_bom = false;
+ flags |= CONFIG_PARSE_REFUSE_BOM;
}
}
if (continuation) {
if (strlen(continuation) + strlen(l) > LONG_LINE_MAX) {
- if (warn)
+ if (flags & CONFIG_PARSE_WARN)
log_error("%s:%u: Continuation line too long", filename, line);
return -ENOBUFS;
}
- c = strappend(continuation, l);
- if (!c) {
- if (warn)
+ if (!strextend(&continuation, l, NULL)) {
+ if (flags & CONFIG_PARSE_WARN)
log_oom();
return -ENOMEM;
}
- continuation = mfree(continuation);
- p = c;
+ p = continuation;
} else
p = l;
@@ -378,12 +375,10 @@ int config_parse(const char *unit,
if (escaped) {
*(e-1) = ' ';
- if (c)
- continuation = c;
- else {
+ if (!continuation) {
continuation = strdup(l);
if (!continuation) {
- if (warn)
+ if (flags & CONFIG_PARSE_WARN)
log_oom();
return -ENOMEM;
}
@@ -398,20 +393,20 @@ int config_parse(const char *unit,
sections,
lookup,
table,
- relaxed,
- allow_include,
+ flags,
&section,
&section_line,
&section_ignored,
p,
userdata);
- free(c);
-
if (r < 0) {
- if (warn)
+ if (flags & CONFIG_PARSE_WARN)
log_warning_errno(r, "%s:%u: Failed to parse file: %m", filename, line);
return r;
+
}
+
+ continuation = mfree(continuation);
}
return 0;
@@ -423,20 +418,20 @@ static int config_parse_many_files(
const char *sections,
ConfigItemLookup lookup,
const void *table,
- bool relaxed,
+ ConfigParseFlags flags,
void *userdata) {
char **fn;
int r;
if (conf_file) {
- r = config_parse(NULL, conf_file, NULL, sections, lookup, table, relaxed, false, true, userdata);
+ r = config_parse(NULL, conf_file, NULL, sections, lookup, table, flags, userdata);
if (r < 0)
return r;
}
STRV_FOREACH(fn, files) {
- r = config_parse(NULL, *fn, NULL, sections, lookup, table, relaxed, false, true, userdata);
+ r = config_parse(NULL, *fn, NULL, sections, lookup, table, flags, userdata);
if (r < 0)
return r;
}
@@ -451,7 +446,7 @@ int config_parse_many_nulstr(
const char *sections,
ConfigItemLookup lookup,
const void *table,
- bool relaxed,
+ ConfigParseFlags flags,
void *userdata) {
_cleanup_strv_free_ char **files = NULL;
@@ -461,8 +456,7 @@ int config_parse_many_nulstr(
if (r < 0)
return r;
- return config_parse_many_files(conf_file, files,
- sections, lookup, table, relaxed, userdata);
+ return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata);
}
/* Parse each config file in the directories specified as strv. */
@@ -473,7 +467,7 @@ int config_parse_many(
const char *sections,
ConfigItemLookup lookup,
const void *table,
- bool relaxed,
+ ConfigParseFlags flags,
void *userdata) {
_cleanup_strv_free_ char **dropin_dirs = NULL;
@@ -490,8 +484,7 @@ int config_parse_many(
if (r < 0)
return r;
- return config_parse_many_files(conf_file, files,
- sections, lookup, table, relaxed, userdata);
+ return config_parse_many_files(conf_file, files, sections, lookup, table, flags, userdata);
}
#define DEFINE_PARSER(type, vartype, conv_func) \
@@ -567,16 +560,17 @@ int config_parse_iec_size(const char* unit,
return 0;
}
-int config_parse_si_size(const char* unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_si_size(
+ const char* unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
size_t *sz = data;
uint64_t v;
@@ -597,16 +591,17 @@ int config_parse_si_size(const char* unit,
return 0;
}
-int config_parse_iec_uint64(const char* unit,
- const char *filename,
- unsigned line,
- const char *section,
- unsigned section_line,
- const char *lvalue,
- int ltype,
- const char *rvalue,
- void *data,
- void *userdata) {
+int config_parse_iec_uint64(
+ const char* unit,
+ const char *filename,
+ unsigned line,
+ const char *section,
+ unsigned section_line,
+ const char *lvalue,
+ int ltype,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
uint64_t *bytes = data;
int r;
@@ -840,7 +835,6 @@ int config_parse_log_facility(
void *data,
void *userdata) {
-
int *o = data, x;
assert(filename);
@@ -871,7 +865,6 @@ int config_parse_log_level(
void *data,
void *userdata) {
-
int *o = data, x;
assert(filename);
@@ -885,7 +878,11 @@ int config_parse_log_level(
return 0;
}
- *o = (*o & LOG_FACMASK) | x;
+ if (*o < 0) /* if it wasn't initialized so far, assume zero facility */
+ *o = x;
+ else
+ *o = (*o & LOG_FACMASK) | x;
+
return 0;
}
diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h
index ce1113485d..2fd135baa0 100644
--- a/src/shared/conf-parser.h
+++ b/src/shared/conf-parser.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
@@ -29,8 +30,14 @@
#include "log.h"
#include "macro.h"
-/* An abstract parser for simple, line based, shallow configuration
- * files consisting of variable assignments only. */
+/* An abstract parser for simple, line based, shallow configuration files consisting of variable assignments only. */
+
+typedef enum ConfigParseFlags {
+ CONFIG_PARSE_RELAXED = 1U << 0,
+ CONFIG_PARSE_ALLOW_INCLUDE = 1U << 1,
+ CONFIG_PARSE_WARN = 1U << 2,
+ CONFIG_PARSE_REFUSE_BOM = 1U << 3,
+} ConfigParseFlags;
/* Prototype for a parser for a specific configuration setting */
typedef int (*ConfigParserCallback)(const char *unit,
@@ -91,9 +98,7 @@ int config_parse(
const char *sections, /* nulstr */
ConfigItemLookup lookup,
const void *table,
- bool relaxed,
- bool allow_include,
- bool warn,
+ ConfigParseFlags flags,
void *userdata);
int config_parse_many_nulstr(
@@ -102,7 +107,7 @@ int config_parse_many_nulstr(
const char *sections, /* nulstr */
ConfigItemLookup lookup,
const void *table,
- bool relaxed,
+ ConfigParseFlags flags,
void *userdata);
int config_parse_many(
@@ -112,7 +117,7 @@ int config_parse_many(
const char *sections, /* nulstr */
ConfigItemLookup lookup,
const void *table,
- bool relaxed,
+ ConfigParseFlags flags,
void *userdata);
/* Generic parsers */
diff --git a/src/shared/dev-setup.c b/src/shared/dev-setup.c
index b2d464c117..6d2cc685fa 100644
--- a/src/shared/dev-setup.c
+++ b/src/shared/dev-setup.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
diff --git a/src/shared/dev-setup.h b/src/shared/dev-setup.h
index 5766a62060..4dd591de0a 100644
--- a/src/shared/dev-setup.h
+++ b/src/shared/dev-setup.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c
index 4b59f2ca7d..e8d7db8f0c 100644
--- a/src/shared/dissect-image.c
+++ b/src/shared/dissect-image.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -17,50 +18,68 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
-#if HAVE_LIBCRYPTSETUP
-#include <libcryptsetup.h>
-#endif
#include <sys/mount.h>
+#include <sys/prctl.h>
+#include <sys/wait.h>
#include "architecture.h"
#include "ask-password-api.h"
#include "blkid-util.h"
+#include "copy.h"
+#include "crypt-util.h"
+#include "def.h"
+#include "device-nodes.h"
#include "dissect-image.h"
#include "fd-util.h"
#include "fileio.h"
#include "fs-util.h"
#include "gpt.h"
#include "hexdecoct.h"
+#include "hostname-util.h"
+#include "id128-util.h"
#include "linux-3.13/dm-ioctl.h"
#include "mount-util.h"
#include "path-util.h"
+#include "process-util.h"
+#include "raw-clone.h"
+#include "signal-util.h"
#include "stat-util.h"
#include "stdio-util.h"
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
#include "udev-util.h"
+#include "user-util.h"
#include "xattr-util.h"
-_unused_ static int probe_filesystem(const char *node, char **ret_fstype) {
+int probe_filesystem(const char *node, char **ret_fstype) {
+ /* Try to find device content type and return it in *ret_fstype. If nothing is found,
+ * 0/NULL will be returned. -EUCLEAN will be returned for ambigous results, and an
+ * different error otherwise. */
+
#if HAVE_BLKID
_cleanup_blkid_free_probe_ blkid_probe b = NULL;
const char *fstype;
int r;
+ errno = 0;
b = blkid_new_probe_from_filename(node);
if (!b)
- return -ENOMEM;
+ return -errno ?: -ENOMEM;
blkid_probe_enable_superblocks(b, 1);
blkid_probe_set_superblocks_flags(b, BLKID_SUBLKS_TYPE);
errno = 0;
r = blkid_do_safeprobe(b);
- if (IN_SET(r, -2, 1)) {
- log_debug("Failed to identify any partition type on partition %s", node);
+ if (r == 1) {
+ log_debug("No type detected on partition %s", node);
goto not_found;
}
+ if (r == -2) {
+ log_debug("Results ambiguous for partition %s", node);
+ return -EUCLEAN;
+ }
if (r != 0)
return -errno ?: -EIO;
@@ -266,18 +285,34 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectI
return -EIO;
}
if (n < z + 1) {
- unsigned j;
+ unsigned j = 0;
/* The kernel has probed fewer partitions than blkid? Maybe the kernel prober is still running
* or it got EBUSY because udev already opened the device. Let's reprobe the device, which is a
* synchronous call that waits until probing is complete. */
- for (j = 0; j < 20; j++) {
+ for (;;) {
+ if (j++ > 20)
+ return -EBUSY;
- r = ioctl(fd, BLKRRPART, 0);
- if (r < 0)
+ if (ioctl(fd, BLKRRPART, 0) < 0) {
r = -errno;
- if (r >= 0 || r != -EBUSY)
+
+ if (r == -EINVAL) {
+ struct loop_info64 info;
+
+ /* If we are running on a loop device that has partition scanning off,
+ * return an explicit recognizable error about this, so that callers
+ * can generate a proper message explaining the situation. */
+
+ if (ioctl(fd, LOOP_GET_STATUS64, &info) >= 0 && (info.lo_flags & LO_FLAGS_PARTSCAN) == 0) {
+ log_debug("Device is loop device and partition scanning is off!");
+ return -EPROTONOSUPPORT;
+ }
+ }
+ if (r != -EBUSY)
+ return r;
+ } else
break;
/* If something else has the device open, such as an udev rule, the ioctl will return
@@ -286,11 +321,8 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectI
*
* This is really something they should fix in the kernel! */
- usleep(50 * USEC_PER_MSEC);
+ (void) usleep(50 * USEC_PER_MSEC);
}
-
- if (r < 0)
- return r;
}
e = udev_enumerate_unref(e);
@@ -585,7 +617,7 @@ int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectI
if (!p->fstype && p->node) {
r = probe_filesystem(p->node, &p->fstype);
- if (r < 0)
+ if (r < 0 && r != -EUCLEAN)
return r;
}
@@ -618,12 +650,15 @@ DissectedImage* dissected_image_unref(DissectedImage *m) {
free(m->partitions[i].decrypted_node);
}
- free(m);
- return NULL;
+ free(m->hostname);
+ strv_free(m->machine_info);
+ strv_free(m->os_release);
+
+ return mfree(m);
}
static int is_loop_device(const char *path) {
- char s[strlen("/sys/dev/block/") + DECIMAL_STR_MAX(dev_t) + 1 + DECIMAL_STR_MAX(dev_t) + strlen("/../loop/")];
+ char s[SYS_BLOCK_PATH_MAX("/../loop/")];
struct stat st;
assert(path);
@@ -634,13 +669,13 @@ static int is_loop_device(const char *path) {
if (!S_ISBLK(st.st_mode))
return -ENOTBLK;
- xsprintf(s, "/sys/dev/block/%u:%u/loop/", major(st.st_rdev), minor(st.st_rdev));
+ xsprintf_sys_block_path(s, "/loop/", st.st_dev);
if (access(s, F_OK) < 0) {
if (errno != ENOENT)
return -errno;
/* The device itself isn't a loop device, but maybe it's a partition and its parent is? */
- xsprintf(s, "/sys/dev/block/%u:%u/../loop/", major(st.st_rdev), minor(st.st_rdev));
+ xsprintf_sys_block_path(s, "/../loop/", st.st_dev);
if (access(s, F_OK) < 0)
return errno == ENOENT ? false : -errno;
}
@@ -652,10 +687,11 @@ static int mount_partition(
DissectedPartition *m,
const char *where,
const char *directory,
+ uid_t uid_shift,
DissectImageFlags flags) {
- const char *p, *options = NULL, *node, *fstype;
- _cleanup_free_ char *chased = NULL;
+ _cleanup_free_ char *chased = NULL, *options = NULL;
+ const char *p, *node, *fstype;
bool rw;
int r;
@@ -686,13 +722,26 @@ static int mount_partition(
/* If requested, turn on discard support. */
if (fstype_can_discard(fstype) &&
((flags & DISSECT_IMAGE_DISCARD) ||
- ((flags & DISSECT_IMAGE_DISCARD_ON_LOOP) && is_loop_device(m->node))))
- options = "discard";
+ ((flags & DISSECT_IMAGE_DISCARD_ON_LOOP) && is_loop_device(m->node)))) {
+ options = strdup("discard");
+ if (!options)
+ return -ENOMEM;
+ }
+
+ if (uid_is_valid(uid_shift) && uid_shift != 0 && fstype_can_uid_gid(fstype)) {
+ _cleanup_free_ char *uid_option = NULL;
+
+ if (asprintf(&uid_option, "uid=" UID_FMT ",gid=" GID_FMT, uid_shift, (gid_t) uid_shift) < 0)
+ return -ENOMEM;
+
+ if (!strextend_with_separator(&options, ",", uid_option, NULL))
+ return -ENOMEM;
+ }
return mount_verbose(LOG_DEBUG, node, p, fstype, MS_NODEV|(rw ? 0 : MS_RDONLY), options);
}
-int dissected_image_mount(DissectedImage *m, const char *where, DissectImageFlags flags) {
+int dissected_image_mount(DissectedImage *m, const char *where, uid_t uid_shift, DissectImageFlags flags) {
int r;
assert(m);
@@ -701,15 +750,20 @@ int dissected_image_mount(DissectedImage *m, const char *where, DissectImageFlag
if (!m->partitions[PARTITION_ROOT].found)
return -ENXIO;
- r = mount_partition(m->partitions + PARTITION_ROOT, where, NULL, flags);
- if (r < 0)
- return r;
+ if ((flags & DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY) == 0) {
+ r = mount_partition(m->partitions + PARTITION_ROOT, where, NULL, uid_shift, flags);
+ if (r < 0)
+ return r;
+ }
+
+ if ((flags & DISSECT_IMAGE_MOUNT_ROOT_ONLY))
+ return 0;
- r = mount_partition(m->partitions + PARTITION_HOME, where, "/home", flags);
+ r = mount_partition(m->partitions + PARTITION_HOME, where, "/home", uid_shift, flags);
if (r < 0)
return r;
- r = mount_partition(m->partitions + PARTITION_SRV, where, "/srv", flags);
+ r = mount_partition(m->partitions + PARTITION_SRV, where, "/srv", uid_shift, flags);
if (r < 0)
return r;
@@ -727,7 +781,7 @@ int dissected_image_mount(DissectedImage *m, const char *where, DissectImageFlag
r = dir_is_empty(p);
if (r > 0) {
- r = mount_partition(m->partitions + PARTITION_ESP, where, mp, flags);
+ r = mount_partition(m->partitions + PARTITION_ESP, where, mp, uid_shift, flags);
if (r < 0)
return r;
}
@@ -820,7 +874,7 @@ static int decrypt_partition(
DecryptedImage *d) {
_cleanup_free_ char *node = NULL, *name = NULL;
- struct crypt_device *cd;
+ _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
int r;
assert(m);
@@ -832,6 +886,9 @@ static int decrypt_partition(
if (!streq(m->fstype, "crypto_LUKS"))
return 0;
+ if (!passphrase)
+ return -ENOKEY;
+
r = make_dm_name_and_node(m->node, "-decrypted", &name, &node);
if (r < 0)
return r;
@@ -843,38 +900,29 @@ static int decrypt_partition(
if (r < 0)
return log_debug_errno(r, "Failed to initialize dm-crypt: %m");
- r = crypt_load(cd, CRYPT_LUKS1, NULL);
- if (r < 0) {
- log_debug_errno(r, "Failed to load LUKS metadata: %m");
- goto fail;
- }
+ r = crypt_load(cd, CRYPT_LUKS, NULL);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to load LUKS metadata: %m");
r = crypt_activate_by_passphrase(cd, name, CRYPT_ANY_SLOT, passphrase, strlen(passphrase),
((flags & DISSECT_IMAGE_READ_ONLY) ? CRYPT_ACTIVATE_READONLY : 0) |
((flags & DISSECT_IMAGE_DISCARD_ON_CRYPTO) ? CRYPT_ACTIVATE_ALLOW_DISCARDS : 0));
- if (r < 0)
+ if (r < 0) {
log_debug_errno(r, "Failed to activate LUKS device: %m");
- if (r == -EPERM) {
- r = -EKEYREJECTED;
- goto fail;
+ return r == -EPERM ? -EKEYREJECTED : r;
}
- if (r < 0)
- goto fail;
d->decrypted[d->n_decrypted].name = name;
name = NULL;
d->decrypted[d->n_decrypted].device = cd;
+ cd = NULL;
d->n_decrypted++;
m->decrypted_node = node;
node = NULL;
return 0;
-
-fail:
- crypt_free(cd);
- return r;
}
static int verity_partition(
@@ -886,7 +934,7 @@ static int verity_partition(
DecryptedImage *d) {
_cleanup_free_ char *node = NULL, *name = NULL;
- struct crypt_device *cd;
+ _cleanup_(crypt_freep) struct crypt_device *cd = NULL;
int r;
assert(m);
@@ -916,30 +964,27 @@ static int verity_partition(
r = crypt_load(cd, CRYPT_VERITY, NULL);
if (r < 0)
- goto fail;
+ return r;
r = crypt_set_data_device(cd, m->node);
if (r < 0)
- goto fail;
+ return r;
r = crypt_activate_by_volume_key(cd, name, root_hash, root_hash_size, CRYPT_ACTIVATE_READONLY);
if (r < 0)
- goto fail;
+ return r;
d->decrypted[d->n_decrypted].name = name;
name = NULL;
d->decrypted[d->n_decrypted].device = cd;
+ cd = NULL;
d->n_decrypted++;
m->decrypted_node = node;
node = NULL;
return 0;
-
-fail:
- crypt_free(cd);
- return r;
}
#endif
@@ -951,8 +996,8 @@ int dissected_image_decrypt(
DissectImageFlags flags,
DecryptedImage **ret) {
- _cleanup_(decrypted_image_unrefp) DecryptedImage *d = NULL;
#if HAVE_LIBCRYPTSETUP
+ _cleanup_(decrypted_image_unrefp) DecryptedImage *d = NULL;
unsigned i;
int r;
#endif
@@ -977,9 +1022,6 @@ int dissected_image_decrypt(
}
#if HAVE_LIBCRYPTSETUP
- if (m->encrypted && !passphrase)
- return -ENOKEY;
-
d = new0(DecryptedImage, 1);
if (!d)
return -ENOMEM;
@@ -1004,7 +1046,7 @@ int dissected_image_decrypt(
if (!p->decrypted_fstype && p->decrypted_node) {
r = probe_filesystem(p->decrypted_node, &p->decrypted_fstype);
- if (r < 0)
+ if (r < 0 && r != -EUCLEAN)
return r;
}
}
@@ -1144,7 +1186,7 @@ int root_hash_load(const char *image, void **ret, size_t *ret_size) {
if (!IN_SET(r, -ENODATA, -EOPNOTSUPP, -ENOENT))
return r;
- fn = newa(char, strlen(image) + strlen(".roothash") + 1);
+ fn = newa(char, strlen(image) + STRLEN(".roothash") + 1);
n = stpcpy(fn, image);
e = endswith(fn, ".raw");
if (e)
@@ -1176,6 +1218,174 @@ int root_hash_load(const char *image, void **ret, size_t *ret_size) {
return 1;
}
+int dissected_image_acquire_metadata(DissectedImage *m) {
+
+ enum {
+ META_HOSTNAME,
+ META_MACHINE_ID,
+ META_MACHINE_INFO,
+ META_OS_RELEASE,
+ _META_MAX,
+ };
+
+ static const char *const paths[_META_MAX] = {
+ [META_HOSTNAME] = "/etc/hostname\0",
+ [META_MACHINE_ID] = "/etc/machine-id\0",
+ [META_MACHINE_INFO] = "/etc/machine-info\0",
+ [META_OS_RELEASE] = "/etc/os-release\0/usr/lib/os-release\0",
+ };
+
+ _cleanup_strv_free_ char **machine_info = NULL, **os_release = NULL;
+ _cleanup_(rmdir_and_freep) char *t = NULL;
+ _cleanup_(sigkill_waitp) pid_t child = 0;
+ sd_id128_t machine_id = SD_ID128_NULL;
+ _cleanup_free_ char *hostname = NULL;
+ unsigned n_meta_initialized = 0, k;
+ int fds[2 * _META_MAX], r;
+ siginfo_t si;
+
+ BLOCK_SIGNALS(SIGCHLD);
+
+ assert(m);
+
+ for (; n_meta_initialized < _META_MAX; n_meta_initialized ++)
+ if (pipe2(fds + 2*n_meta_initialized, O_CLOEXEC) < 0) {
+ r = -errno;
+ goto finish;
+ }
+
+ r = mkdtemp_malloc("/tmp/dissect-XXXXXX", &t);
+ if (r < 0)
+ goto finish;
+
+ child = raw_clone(SIGCHLD|CLONE_NEWNS);
+ if (child < 0) {
+ r = -errno;
+ goto finish;
+ }
+
+ if (child == 0) {
+
+ (void) reset_all_signal_handlers();
+ (void) reset_signal_mask();
+ assert_se(prctl(PR_SET_PDEATHSIG, SIGTERM) == 0);
+
+ /* Make sure we never propagate to the host */
+ if (mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL) < 0)
+ _exit(EXIT_FAILURE);
+
+ r = dissected_image_mount(m, t, UID_INVALID, DISSECT_IMAGE_READ_ONLY);
+ if (r < 0)
+ _exit(EXIT_FAILURE);
+
+ for (k = 0; k < _META_MAX; k++) {
+ _cleanup_close_ int fd = -1;
+ const char *p;
+
+ fds[2*k] = safe_close(fds[2*k]);
+
+ NULSTR_FOREACH(p, paths[k]) {
+ _cleanup_free_ char *q = NULL;
+
+ r = chase_symlinks(p, t, CHASE_PREFIX_ROOT, &q);
+ if (r < 0)
+ continue;
+
+ fd = open(q, O_RDONLY|O_CLOEXEC|O_NOCTTY);
+ if (fd >= 0)
+ break;
+ }
+ if (fd < 0)
+ continue;
+
+ r = copy_bytes(fd, fds[2*k+1], (uint64_t) -1, 0);
+ if (r < 0)
+ _exit(EXIT_FAILURE);
+
+ fds[2*k+1] = safe_close(fds[2*k+1]);
+ }
+
+ _exit(EXIT_SUCCESS);
+ }
+
+ for (k = 0; k < _META_MAX; k++) {
+ _cleanup_fclose_ FILE *f = NULL;
+
+ fds[2*k+1] = safe_close(fds[2*k+1]);
+
+ f = fdopen(fds[2*k], "re");
+ if (!f) {
+ r = -errno;
+ goto finish;
+ }
+
+ fds[2*k] = -1;
+
+ switch (k) {
+
+ case META_HOSTNAME:
+ r = read_etc_hostname_stream(f, &hostname);
+ if (r < 0)
+ log_debug_errno(r, "Failed to read /etc/hostname: %m");
+
+ break;
+
+ case META_MACHINE_ID: {
+ _cleanup_free_ char *line = NULL;
+
+ r = read_line(f, LONG_LINE_MAX, &line);
+ if (r < 0)
+ log_debug_errno(r, "Failed to read /etc/machine-id: %m");
+ else if (r == 33) {
+ r = sd_id128_from_string(line, &machine_id);
+ if (r < 0)
+ log_debug_errno(r, "Image contains invalid /etc/machine-id: %s", line);
+ } else if (r == 0)
+ log_debug("/etc/machine-id file is empty.");
+ else
+ log_debug("/etc/machine-id has unexpected length %i.", r);
+
+ break;
+ }
+
+ case META_MACHINE_INFO:
+ r = load_env_file_pairs(f, "machine-info", NULL, &machine_info);
+ if (r < 0)
+ log_debug_errno(r, "Failed to read /etc/machine-info: %m");
+
+ break;
+
+ case META_OS_RELEASE:
+ r = load_env_file_pairs(f, "os-release", NULL, &os_release);
+ if (r < 0)
+ log_debug_errno(r, "Failed to read OS release file: %m");
+
+ break;
+ }
+ }
+
+ r = wait_for_terminate(child, &si);
+ if (r < 0)
+ goto finish;
+ child = 0;
+
+ if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS) {
+ r = -EPROTO;
+ goto finish;
+ }
+
+ free_and_replace(m->hostname, hostname);
+ m->machine_id = machine_id;
+ strv_free_and_replace(m->machine_info, machine_info);
+ strv_free_and_replace(m->os_release, os_release);
+
+finish:
+ for (k = 0; k < n_meta_initialized; k++)
+ safe_close_pair(fds + 2*k);
+
+ return r;
+}
+
static const char *const partition_designator_table[] = {
[PARTITION_ROOT] = "root",
[PARTITION_ROOT_SECONDARY] = "root-secondary",
diff --git a/src/shared/dissect-image.h b/src/shared/dissect-image.h
index cdb083be6f..53a1554a28 100644
--- a/src/shared/dissect-image.h
+++ b/src/shared/dissect-image.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
@@ -61,24 +62,33 @@ static inline int PARTITION_VERITY_OF(int p) {
}
typedef enum DissectImageFlags {
- DISSECT_IMAGE_READ_ONLY = 1,
- DISSECT_IMAGE_DISCARD_ON_LOOP = 2, /* Turn on "discard" if on a loop device and file system supports it */
- DISSECT_IMAGE_DISCARD = 4, /* Turn on "discard" if file system supports it, on all block devices */
- DISSECT_IMAGE_DISCARD_ON_CRYPTO = 8, /* Turn on "discard" also on crypto devices */
+ DISSECT_IMAGE_READ_ONLY = 1 << 0,
+ DISSECT_IMAGE_DISCARD_ON_LOOP = 1 << 1, /* Turn on "discard" if on a loop device and file system supports it */
+ DISSECT_IMAGE_DISCARD = 1 << 2, /* Turn on "discard" if file system supports it, on all block devices */
+ DISSECT_IMAGE_DISCARD_ON_CRYPTO = 1 << 3, /* Turn on "discard" also on crypto devices */
DISSECT_IMAGE_DISCARD_ANY = DISSECT_IMAGE_DISCARD_ON_LOOP |
DISSECT_IMAGE_DISCARD |
DISSECT_IMAGE_DISCARD_ON_CRYPTO,
- DISSECT_IMAGE_GPT_ONLY = 16, /* Only recognize images with GPT partition tables */
- DISSECT_IMAGE_REQUIRE_ROOT = 32, /* Don't accept disks without root partition */
+ DISSECT_IMAGE_GPT_ONLY = 1 << 4, /* Only recognize images with GPT partition tables */
+ DISSECT_IMAGE_REQUIRE_ROOT = 1 << 5, /* Don't accept disks without root partition */
+ DISSECT_IMAGE_MOUNT_ROOT_ONLY = 1 << 6, /* Mount only the root partition */
+ DISSECT_IMAGE_MOUNT_NON_ROOT_ONLY = 1 << 7, /* Mount only non-root partitions */
} DissectImageFlags;
struct DissectedImage {
bool encrypted:1;
bool verity:1; /* verity available and usable */
bool can_verity:1; /* verity available, but not necessarily used */
+
DissectedPartition partitions[_PARTITION_DESIGNATOR_MAX];
+
+ char *hostname;
+ sd_id128_t machine_id;
+ char **machine_info;
+ char **os_release;
};
+int probe_filesystem(const char *node, char **ret_fstype);
int dissect_image(int fd, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DissectedImage **ret);
DissectedImage* dissected_image_unref(DissectedImage *m);
@@ -86,7 +96,9 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(DissectedImage*, dissected_image_unref);
int dissected_image_decrypt(DissectedImage *m, const char *passphrase, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DecryptedImage **ret);
int dissected_image_decrypt_interactively(DissectedImage *m, const char *passphrase, const void *root_hash, size_t root_hash_size, DissectImageFlags flags, DecryptedImage **ret);
-int dissected_image_mount(DissectedImage *m, const char *dest, DissectImageFlags flags);
+int dissected_image_mount(DissectedImage *m, const char *dest, uid_t uid_shift, DissectImageFlags flags);
+
+int dissected_image_acquire_metadata(DissectedImage *m);
DecryptedImage* decrypted_image_unref(DecryptedImage *p);
DEFINE_TRIVIAL_CLEANUP_FUNC(DecryptedImage*, decrypted_image_unref);
diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c
index 4739cc880b..8c807e0e23 100644
--- a/src/shared/dns-domain.c
+++ b/src/shared/dns-domain.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -692,23 +693,26 @@ int dns_name_change_suffix(const char *name, const char *old_suffix, const char
}
int dns_name_between(const char *a, const char *b, const char *c) {
- int n;
-
/* Determine if b is strictly greater than a and strictly smaller than c.
We consider the order of names to be circular, so that if a is
strictly greater than c, we consider b to be between them if it is
either greater than a or smaller than c. This is how the canonical
DNS name order used in NSEC records work. */
- n = dns_name_compare_func(a, c);
- if (n == 0)
- return -EINVAL;
- else if (n < 0)
- /* a<---b--->c */
+ if (dns_name_compare_func(a, c) < 0)
+ /*
+ a and c are properly ordered:
+ a<---b--->c
+ */
return dns_name_compare_func(a, b) < 0 &&
dns_name_compare_func(b, c) < 0;
else
- /* <--b--c a--b--> */
+ /*
+ a and c are equal or 'reversed':
+ <--b--c a----->
+ or:
+ <-----c a--b-->
+ */
return dns_name_compare_func(b, c) < 0 ||
dns_name_compare_func(a, b) < 0;
}
@@ -958,6 +962,12 @@ bool dns_srv_type_is_valid(const char *name) {
return c == 2; /* exactly two labels */
}
+bool dnssd_srv_type_is_valid(const char *name) {
+ return dns_srv_type_is_valid(name) &&
+ ((dns_name_endswith(name, "_tcp") > 0) ||
+ (dns_name_endswith(name, "_udp") > 0)); /* Specific to DNS-SD. RFC 6763, Section 7 */
+}
+
bool dns_service_name_is_valid(const char *name) {
size_t l;
diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h
index a44d9d48d4..cd3dbb7a89 100644
--- a/src/shared/dns-domain.h
+++ b/src/shared/dns-domain.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
@@ -95,6 +96,7 @@ bool dns_name_is_single_label(const char *name);
int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len, bool canonical);
bool dns_srv_type_is_valid(const char *name);
+bool dnssd_srv_type_is_valid(const char *name);
bool dns_service_name_is_valid(const char *name);
int dns_service_join(const char *name, const char *type, const char *domain, char **ret);
diff --git a/src/shared/dropin.c b/src/shared/dropin.c
index 059b50dbd0..f0966874ee 100644
--- a/src/shared/dropin.c
+++ b/src/shared/dropin.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -127,7 +128,11 @@ static int unit_file_find_dir(
assert(path);
r = chase_symlinks(path, original_root, 0, &chased);
- if (r == -ENOENT) /* Ignore -ENOENT, after all most units won't have a drop-in dir */
+ /* Ignore -ENOENT, after all most units won't have a drop-in dir.
+ * Also ignore -ENAMETOOLONG, users are not even able to create
+ * the drop-in dir in such case. This mostly happens for device units with long /sys path.
+ * */
+ if (IN_SET(r, -ENOENT, -ENAMETOOLONG))
return 0;
if (r < 0)
return log_full_errno(LOG_WARNING, r, "Failed to canonicalize path %s: %m", path);
diff --git a/src/shared/dropin.h b/src/shared/dropin.h
index a2b8cdce61..102fc9403c 100644
--- a/src/shared/dropin.h
+++ b/src/shared/dropin.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/efivars.c b/src/shared/efivars.c
index a3850bede2..9ca51cf750 100644
--- a/src/shared/efivars.c
+++ b/src/shared/efivars.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -84,10 +85,10 @@ bool is_efi_boot(void) {
}
static int read_flag(const char *varname) {
- int r;
_cleanup_free_ void *v = NULL;
- size_t s;
uint8_t b;
+ size_t s;
+ int r;
r = efi_get_variable(EFI_VENDOR_GLOBAL, varname, NULL, &v, &s);
if (r < 0)
@@ -97,8 +98,7 @@ static int read_flag(const char *varname) {
return -EINVAL;
b = *(uint8_t *)v;
- r = b > 0;
- return r;
+ return b > 0;
}
bool is_efi_secure_boot(void) {
@@ -110,29 +110,33 @@ bool is_efi_secure_boot_setup_mode(void) {
}
int efi_reboot_to_firmware_supported(void) {
- int r;
- size_t s;
- uint64_t b;
_cleanup_free_ void *v = NULL;
+ uint64_t b;
+ size_t s;
+ int r;
if (!is_efi_boot() || detect_container() > 0)
return -EOPNOTSUPP;
r = efi_get_variable(EFI_VENDOR_GLOBAL, "OsIndicationsSupported", NULL, &v, &s);
+ if (r == -ENOENT) /* variable doesn't exist? it's not supported then */
+ return -EOPNOTSUPP;
if (r < 0)
return r;
- else if (s != sizeof(uint64_t))
+ if (s != sizeof(uint64_t))
return -EINVAL;
- b = *(uint64_t *)v;
- b &= EFI_OS_INDICATIONS_BOOT_TO_FW_UI;
- return b > 0 ? 0 : -EOPNOTSUPP;
+ b = *(uint64_t*) v;
+ if (!(b & EFI_OS_INDICATIONS_BOOT_TO_FW_UI))
+ return -EOPNOTSUPP; /* bit unset? it's not supported then */
+
+ return 0;
}
static int get_os_indications(uint64_t *os_indication) {
- int r;
- size_t s;
_cleanup_free_ void *v = NULL;
+ size_t s;
+ int r;
r = efi_reboot_to_firmware_supported();
if (r < 0)
diff --git a/src/shared/efivars.h b/src/shared/efivars.h
index 72bace0d07..9a4880de7d 100644
--- a/src/shared/efivars.h
+++ b/src/shared/efivars.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/fdset.c b/src/shared/fdset.c
index 090f3fdcdd..9ce1295223 100644
--- a/src/shared/fdset.c
+++ b/src/shared/fdset.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
diff --git a/src/shared/fdset.h b/src/shared/fdset.h
index 16efe5bdf2..864ab676f7 100644
--- a/src/shared/fdset.h
+++ b/src/shared/fdset.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/firewall-util.c b/src/shared/firewall-util.c
index 6d295ea65b..a6859462ac 100644
--- a/src/shared/firewall-util.c
+++ b/src/shared/firewall-util.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -77,7 +78,8 @@ static int entry_fill_basics(
if (out_interface) {
size_t l = strlen(out_interface);
- assert(l < sizeof entry->ip.outiface && l < sizeof entry->ip.outiface_mask);
+ assert(l < sizeof entry->ip.outiface);
+ assert(l < sizeof entry->ip.outiface_mask);
strcpy(entry->ip.outiface, out_interface);
memset(entry->ip.outiface_mask, 0xFF, l + 1);
diff --git a/src/shared/firewall-util.h b/src/shared/firewall-util.h
index 5915266b4b..fd7e3b456e 100644
--- a/src/shared/firewall-util.h
+++ b/src/shared/firewall-util.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c
index ec2e868ca8..bcd7b43084 100644
--- a/src/shared/fstab-util.c
+++ b/src/shared/fstab-util.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
diff --git a/src/shared/fstab-util.h b/src/shared/fstab-util.h
index bbf0441351..87f82dcfb4 100644
--- a/src/shared/fstab-util.h
+++ b/src/shared/fstab-util.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/gcrypt-util.c b/src/shared/gcrypt-util.c
index e10a38dcfc..1bfb776725 100644
--- a/src/shared/gcrypt-util.c
+++ b/src/shared/gcrypt-util.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
diff --git a/src/shared/gcrypt-util.h b/src/shared/gcrypt-util.h
index f08ed6052c..69faf08e56 100644
--- a/src/shared/gcrypt-util.h
+++ b/src/shared/gcrypt-util.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
diff --git a/src/shared/generator.c b/src/shared/generator.c
index 18fc469098..3495a7ef7d 100644
--- a/src/shared/generator.c
+++ b/src/shared/generator.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -32,6 +33,7 @@
#include "mkdir.h"
#include "path-util.h"
#include "special.h"
+#include "specifier.h"
#include "string-util.h"
#include "time-util.h"
#include "unit-name.h"
@@ -54,15 +56,19 @@ int generator_add_symlink(const char *root, const char *dst, const char *dep_typ
}
static int write_fsck_sysroot_service(const char *dir, const char *what) {
- _cleanup_free_ char *device = NULL, *escaped = NULL;
+ _cleanup_free_ char *device = NULL, *escaped = NULL, *escaped2 = NULL;
_cleanup_fclose_ FILE *f = NULL;
const char *unit;
int r;
- escaped = cescape(what);
+ escaped = specifier_escape(what);
if (!escaped)
return log_oom();
+ escaped2 = cescape(escaped);
+ if (!escaped2)
+ return log_oom();
+
unit = strjoina(dir, "/systemd-fsck-root.service");
log_debug("Creating %s", unit);
@@ -77,8 +83,8 @@ static int write_fsck_sysroot_service(const char *dir, const char *what) {
fprintf(f,
"# Automatically generated by %1$s\n\n"
"[Unit]\n"
- "Documentation=man:systemd-fsck-root.service(8)\n"
"Description=File System Check on %2$s\n"
+ "Documentation=man:systemd-fsck-root.service(8)\n"
"DefaultDependencies=no\n"
"BindsTo=%3$s\n"
"After=initrd-root-device.target local-fs-pre.target %3$s\n"
@@ -90,9 +96,9 @@ static int write_fsck_sysroot_service(const char *dir, const char *what) {
"ExecStart=" SYSTEMD_FSCK_PATH " %4$s\n"
"TimeoutSec=0\n",
program_invocation_short_name,
- what,
+ escaped,
device,
- escaped);
+ escaped2);
r = fflush_and_check(f);
if (r < 0)
@@ -242,7 +248,8 @@ int generator_write_device_deps(
r = unit_name_from_path(node, ".device", &unit);
if (r < 0)
- return log_error_errno(r, "Failed to make unit name from path: %m");
+ return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
+ node);
/* See mount_add_default_dependencies for explanation why we create such
* dependencies. */
@@ -260,7 +267,8 @@ int generator_write_initrd_root_device_deps(const char *dir, const char *what) {
r = unit_name_from_path(what, ".device", &unit);
if (r < 0)
- return log_error_errno(r, "Failed to make unit name from path: %m");
+ return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
+ what);
return write_drop_in_format(dir, SPECIAL_INITRD_ROOT_DEVICE_TARGET, 50, "root-device",
"# Automatically generated by %s\n\n"
@@ -271,3 +279,206 @@ int generator_write_initrd_root_device_deps(const char *dir, const char *what) {
unit,
unit);
}
+
+int generator_hook_up_mkswap(
+ const char *dir,
+ const char *what) {
+
+ _cleanup_free_ char *node = NULL, *unit = NULL, *escaped = NULL, *where_unit = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ const char *unit_file;
+ int r;
+
+ node = fstab_node_to_udev_node(what);
+ if (!node)
+ return log_oom();
+
+ /* Nothing to work on. */
+ if (!is_device_path(node)) {
+ log_error("Cannot format something that is not a device node: %s", node);
+ return -EINVAL;
+ }
+
+ r = unit_name_from_path_instance("systemd-mkswap", node, ".service", &unit);
+ if (r < 0)
+ return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
+ node);
+
+ unit_file = strjoina(dir, "/", unit);
+ log_debug("Creating %s", unit_file);
+
+ escaped = cescape(node);
+ if (!escaped)
+ return log_oom();
+
+ r = unit_name_from_path(what, ".swap", &where_unit);
+ if (r < 0)
+ return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
+ what);
+
+ f = fopen(unit_file, "wxe");
+ if (!f)
+ return log_error_errno(errno, "Failed to create unit file %s: %m",
+ unit_file);
+
+ fprintf(f,
+ "# Automatically generated by %s\n\n"
+ "[Unit]\n"
+ "Description=Make Swap on %%f\n"
+ "Documentation=man:systemd-mkswap@.service(8)\n"
+ "DefaultDependencies=no\n"
+ "BindsTo=%%i.device\n"
+ "After=%%i.device\n"
+ "Before=%s\n"
+ "Before=shutdown.target\n"
+ "\n"
+ "[Service]\n"
+ "Type=oneshot\n"
+ "RemainAfterExit=yes\n"
+ "ExecStart="SYSTEMD_MAKEFS_PATH " swap %s\n"
+ "TimeoutSec=0\n",
+ program_invocation_short_name,
+ where_unit,
+ escaped);
+
+ r = fflush_and_check(f);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write unit file %s: %m", unit_file);
+
+ return generator_add_symlink(dir, where_unit, "requires", unit);
+}
+
+int generator_hook_up_mkfs(
+ const char *dir,
+ const char *what,
+ const char *where,
+ const char *type) {
+
+ _cleanup_free_ char *node = NULL, *unit = NULL, *escaped = NULL, *where_unit = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ const char *unit_file;
+ int r;
+
+ node = fstab_node_to_udev_node(what);
+ if (!node)
+ return log_oom();
+
+ /* Nothing to work on. */
+ if (!is_device_path(node)) {
+ log_error("Cannot format something that is not a device node: %s", node);
+ return -EINVAL;
+ }
+
+ if (!type || streq(type, "auto")) {
+ log_error("Cannot format partition %s, filesystem type is not specified", node);
+ return -EINVAL;
+ }
+
+ r = unit_name_from_path_instance("systemd-mkfs", node, ".service", &unit);
+ if (r < 0)
+ return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
+ node);
+
+ unit_file = strjoina(dir, "/", unit);
+ log_debug("Creating %s", unit_file);
+
+ escaped = cescape(node);
+ if (!escaped)
+ return log_oom();
+
+ r = unit_name_from_path(where, ".mount", &where_unit);
+ if (r < 0)
+ return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
+ where);
+
+ f = fopen(unit_file, "wxe");
+ if (!f)
+ return log_error_errno(errno, "Failed to create unit file %s: %m",
+ unit_file);
+
+ fprintf(f,
+ "# Automatically generated by %s\n\n"
+ "[Unit]\n"
+ "Description=Make File System on %%f\n"
+ "Documentation=man:systemd-mkfs@.service(8)\n"
+ "DefaultDependencies=no\n"
+ "BindsTo=%%i.device\n"
+ "After=%%i.device\n"
+ /* fsck might or might not be used, so let's be safe and order
+ * ourselves before both systemd-fsck@.service and the mount unit. */
+ "Before=systemd-fsck@%%i.service\n"
+ "Before=%s\n"
+ "Before=shutdown.target\n"
+ "\n"
+ "[Service]\n"
+ "Type=oneshot\n"
+ "RemainAfterExit=yes\n"
+ "ExecStart="SYSTEMD_MAKEFS_PATH " %s %s\n"
+ "TimeoutSec=0\n",
+ program_invocation_short_name,
+ where_unit,
+ type,
+ escaped);
+ // XXX: what about local-fs-pre.target?
+
+ r = fflush_and_check(f);
+ if (r < 0)
+ return log_error_errno(r, "Failed to write unit file %s: %m", unit_file);
+
+ return generator_add_symlink(dir, where_unit, "requires", unit);
+}
+
+int generator_hook_up_growfs(
+ const char *dir,
+ const char *where,
+ const char *target) {
+
+ _cleanup_free_ char *unit = NULL, *escaped = NULL, *where_unit = NULL;
+ _cleanup_fclose_ FILE *f = NULL;
+ const char *unit_file;
+ int r;
+
+ escaped = cescape(where);
+ if (!escaped)
+ return log_oom();
+
+ r = unit_name_from_path_instance("systemd-growfs", where, ".service", &unit);
+ if (r < 0)
+ return log_error_errno(r, "Failed to make unit instance name from path \"%s\": %m",
+ where);
+
+ r = unit_name_from_path(where, ".mount", &where_unit);
+ if (r < 0)
+ return log_error_errno(r, "Failed to make unit name from path \"%s\": %m",
+ where);
+
+ unit_file = strjoina(dir, "/", unit);
+ log_debug("Creating %s", unit_file);
+
+ f = fopen(unit_file, "wxe");
+ if (!f)
+ return log_error_errno(errno, "Failed to create unit file %s: %m",
+ unit_file);
+
+ fprintf(f,
+ "# Automatically generated by %s\n\n"
+ "[Unit]\n"
+ "Description=Grow File System on %%f\n"
+ "Documentation=man:systemd-growfs@.service(8)\n"
+ "DefaultDependencies=no\n"
+ "BindsTo=%%i.mount\n"
+ "After=%%i.mount\n"
+ "Before=shutdown.target\n"
+ "Before=%s\n"
+ "\n"
+ "[Service]\n"
+ "Type=oneshot\n"
+ "RemainAfterExit=yes\n"
+ "ExecStart="SYSTEMD_GROWFS_PATH " %s\n"
+ "TimeoutSec=0\n",
+ program_invocation_short_name,
+ target,
+ escaped);
+
+ return generator_add_symlink(dir, where_unit, "wants", unit);
+}
diff --git a/src/shared/generator.h b/src/shared/generator.h
index e70016839f..32d1ad021c 100644
--- a/src/shared/generator.h
+++ b/src/shared/generator.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
@@ -38,11 +39,24 @@ int generator_write_timeouts(
char **filtered);
int generator_write_device_deps(
- const char *dir,
- const char *what,
- const char *where,
- const char *opts);
+ const char *dir,
+ const char *what,
+ const char *where,
+ const char *opts);
int generator_write_initrd_root_device_deps(
const char *dir,
const char *what);
+
+int generator_hook_up_mkswap(
+ const char *dir,
+ const char *what);
+int generator_hook_up_mkfs(
+ const char *dir,
+ const char *what,
+ const char *where,
+ const char *type);
+int generator_hook_up_growfs(
+ const char *dir,
+ const char *where,
+ const char *target);
diff --git a/src/shared/gpt.h b/src/shared/gpt.h
index cc752006fa..7589f6fb7a 100644
--- a/src/shared/gpt.h
+++ b/src/shared/gpt.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/ima-util.c b/src/shared/ima-util.c
index 789064d653..064f38be6f 100644
--- a/src/shared/ima-util.c
+++ b/src/shared/ima-util.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
diff --git a/src/shared/ima-util.h b/src/shared/ima-util.h
index 5be94761fd..5633c78be9 100644
--- a/src/shared/ima-util.h
+++ b/src/shared/ima-util.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/import-util.c b/src/shared/import-util.c
index ab701ad8b2..07ba216e93 100644
--- a/src/shared/import-util.c
+++ b/src/shared/import-util.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
diff --git a/src/shared/import-util.h b/src/shared/import-util.h
index 77b17d91f3..583845b1a4 100644
--- a/src/shared/import-util.h
+++ b/src/shared/import-util.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/install-printf.c b/src/shared/install-printf.c
index c10ed3d311..aaab2e6665 100644
--- a/src/shared/install-printf.c
+++ b/src/shared/install-printf.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -93,7 +94,7 @@ static int specifier_instance(char specifier, void *data, void *userdata, char *
return r;
if (isempty(instance)) {
- r = free_and_strdup(&instance, i->default_instance ?: "");
+ r = free_and_strdup(&instance, strempty(i->default_instance));
if (r < 0)
return r;
}
@@ -102,34 +103,6 @@ static int specifier_instance(char specifier, void *data, void *userdata, char *
return 0;
}
-static int specifier_user_name(char specifier, void *data, void *userdata, char **ret) {
- char *t;
-
- /* If we are UID 0 (root), this will not result in NSS,
- * otherwise it might. This is good, as we want to be able to
- * run this in PID 1, where our user ID is 0, but where NSS
- * lookups are not allowed.
-
- * We don't user getusername_malloc() here, because we don't want to look
- * at $USER, to remain consistent with specifer_user_id() below.
- */
-
- t = uid_to_name(getuid());
- if (!t)
- return -ENOMEM;
-
- *ret = t;
- return 0;
-}
-
-static int specifier_user_id(char specifier, void *data, void *userdata, char **ret) {
-
- if (asprintf(ret, UID_FMT, getuid()) < 0)
- return -ENOMEM;
-
- return 0;
-}
-
int install_full_printf(UnitFileInstallInfo *i, const char *format, char **ret) {
/* This is similar to unit_full_printf() but does not support
diff --git a/src/shared/install-printf.h b/src/shared/install-printf.h
index 8a570fc265..d868f65cfa 100644
--- a/src/shared/install-printf.h
+++ b/src/shared/install-printf.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/install.c b/src/shared/install.c
index 7598bf6a23..05ccc586a9 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -991,23 +992,11 @@ static void install_info_free(UnitFileInstallInfo *i) {
free(i);
}
-static OrderedHashmap* install_info_hashmap_free(OrderedHashmap *m) {
- UnitFileInstallInfo *i;
-
- if (!m)
- return NULL;
-
- while ((i = ordered_hashmap_steal_first(m)))
- install_info_free(i);
-
- return ordered_hashmap_free(m);
-}
-
static void install_context_done(InstallContext *c) {
assert(c);
- c->will_process = install_info_hashmap_free(c->will_process);
- c->have_processed = install_info_hashmap_free(c->have_processed);
+ c->will_process = ordered_hashmap_free_with_destructor(c->will_process, install_info_free);
+ c->have_processed = ordered_hashmap_free_with_destructor(c->have_processed, install_info_free);
}
static UnitFileInstallInfo *install_info_find(InstallContext *c, const char *name) {
@@ -1128,15 +1117,14 @@ static int config_parse_alias(
void *data,
void *userdata) {
- const char *name;
UnitType type;
+ assert(unit);
assert(filename);
assert(lvalue);
assert(rvalue);
- name = basename(filename);
- type = unit_name_to_type(name);
+ type = unit_name_to_type(unit);
if (!unit_type_may_alias(type))
return log_syntax(unit, LOG_WARNING, filename, line, 0,
"Alias= is not allowed for %s units, ignoring.",
@@ -1162,6 +1150,7 @@ static int config_parse_also(
InstallContext *c = data;
int r;
+ assert(unit);
assert(filename);
assert(lvalue);
assert(rvalue);
@@ -1209,20 +1198,19 @@ static int config_parse_default_instance(
void *userdata) {
UnitFileInstallInfo *i = data;
- const char *name;
_cleanup_free_ char *printed = NULL;
int r;
+ assert(unit);
assert(filename);
assert(lvalue);
assert(rvalue);
- name = basename(filename);
- if (unit_name_is_valid(name, UNIT_NAME_INSTANCE))
+ if (unit_name_is_valid(unit, UNIT_NAME_INSTANCE))
/* When enabling an instance, we might be using a template unit file,
* but we should ignore DefaultInstance silently. */
return 0;
- if (!unit_name_is_valid(name, UNIT_NAME_TEMPLATE))
+ if (!unit_name_is_valid(unit, UNIT_NAME_TEMPLATE))
return log_syntax(unit, LOG_WARNING, filename, line, 0,
"DefaultInstance= only makes sense for template units, ignoring.");
@@ -1251,7 +1239,6 @@ static int unit_file_load(
{}
};
- const char *name;
UnitType type;
_cleanup_fclose_ FILE *f = NULL;
_cleanup_close_ int fd = -1;
@@ -1261,9 +1248,8 @@ static int unit_file_load(
assert(info);
assert(path);
- name = basename(path);
- type = unit_name_to_type(name);
- if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE|UNIT_NAME_INSTANCE) &&
+ type = unit_name_to_type(info->name);
+ if (unit_name_is_valid(info->name, UNIT_NAME_TEMPLATE|UNIT_NAME_INSTANCE) &&
!unit_type_may_template(type))
return log_error_errno(EINVAL, "Unit type %s cannot be templated.", unit_type_to_string(type));
@@ -1308,10 +1294,10 @@ static int unit_file_load(
return -errno;
fd = -1;
- r = config_parse(NULL, path, f,
+ r = config_parse(info->name, path, f,
NULL,
config_item_table_lookup, items,
- true, true, false, info);
+ CONFIG_PARSE_RELAXED|CONFIG_PARSE_ALLOW_INCLUDE, info);
if (r < 0)
return log_debug_errno(r, "Failed to parse %s: %m", info->name);
@@ -1398,8 +1384,15 @@ static int unit_file_search(
SearchFlags flags) {
_cleanup_free_ char *template = NULL;
+ _cleanup_strv_free_ char **dirs = NULL;
+ _cleanup_strv_free_ char **files = NULL;
+ const char *dropin_dir_name = NULL;
+ const char *dropin_template_dir_name = NULL;
+
char **p;
int r;
+ int result;
+ bool found_unit = false;
assert(info);
assert(paths);
@@ -1413,6 +1406,12 @@ static int unit_file_search(
assert(info->name);
+ if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
+ r = unit_name_template(info->name, &template);
+ if (r < 0)
+ return r;
+ }
+
STRV_FOREACH(p, paths->search_path) {
_cleanup_free_ char *path = NULL;
@@ -1421,23 +1420,23 @@ static int unit_file_search(
return -ENOMEM;
r = unit_file_load_or_readlink(c, info, path, paths->root_dir, flags);
+
if (r >= 0) {
info->path = path;
path = NULL;
- return r;
+ result = r;
+ found_unit = true;
+ break;
} else if (!IN_SET(r, -ENOENT, -ENOTDIR, -EACCES))
return r;
}
- if (unit_name_is_valid(info->name, UNIT_NAME_INSTANCE)) {
+ if (!found_unit && template) {
+
/* Unit file doesn't exist, however instance
* enablement was requested. We will check if it is
* possible to load template unit file. */
- r = unit_name_template(info->name, &template);
- if (r < 0)
- return r;
-
STRV_FOREACH(p, paths->search_path) {
_cleanup_free_ char *path = NULL;
@@ -1449,14 +1448,62 @@ static int unit_file_search(
if (r >= 0) {
info->path = path;
path = NULL;
- return r;
+ result = r;
+ found_unit = true;
+ break;
} else if (!IN_SET(r, -ENOENT, -ENOTDIR, -EACCES))
return r;
}
}
- log_debug("Cannot find unit %s%s%s.", info->name, template ? " or " : "", strempty(template));
- return -ENOENT;
+ if (!found_unit) {
+ log_debug("Cannot find unit %s%s%s.", info->name, template ? " or " : "", strempty(template));
+ return -ENOENT;
+ }
+
+ /* Search for drop-in directories */
+
+ dropin_dir_name = strjoina(info->name, ".d");
+ STRV_FOREACH(p, paths->search_path) {
+ char *path;
+
+ path = path_join(NULL, *p, dropin_dir_name);
+ if (!path)
+ return -ENOMEM;
+
+ r = strv_consume(&dirs, path);
+ if (r < 0)
+ return r;
+ }
+
+ if (template) {
+ dropin_template_dir_name = strjoina(template, ".d");
+ STRV_FOREACH(p, paths->search_path) {
+ char *path;
+
+ path = path_join(NULL, *p, dropin_template_dir_name);
+ if (!path)
+ return -ENOMEM;
+
+ r = strv_consume(&dirs, path);
+ if (r < 0)
+ return r;
+ }
+ }
+
+ /* Load drop-in conf files */
+
+ r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char**) dirs);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to get list of conf files: %m");
+
+ STRV_FOREACH(p, files) {
+ r = unit_file_load_or_readlink(c, info, *p, paths->root_dir, flags);
+ if (r < 0)
+ return log_debug_errno(r, "Failed to load conf file %s: %m", *p);
+ }
+
+ return result;
}
static int install_info_follow(
@@ -2937,7 +2984,7 @@ static int preset_prepare_one(
if (r < 0)
return r;
if (!streq(name, i->name)) {
- log_debug("Skipping %s because is an alias for %s", name, i->name);
+ log_debug("Skipping %s because it is an alias for %s.", name, i->name);
return 0;
}
@@ -3063,6 +3110,8 @@ int unit_file_preset_all(
else if (r == -ENOLINK)
r = unit_file_changes_add(changes, n_changes,
UNIT_FILE_IS_DANGLING, de->d_name, NULL);
+ else if (r == -EADDRNOTAVAIL) /* Ignore generated/transient units when applying preset */
+ continue;
if (r < 0)
return r;
}
@@ -3080,12 +3129,7 @@ static void unit_file_list_free_one(UnitFileList *f) {
}
Hashmap* unit_file_list_free(Hashmap *h) {
- UnitFileList *i;
-
- while ((i = hashmap_steal_first(h)))
- unit_file_list_free_one(i);
-
- return hashmap_free(h);
+ return hashmap_free_with_destructor(h, unit_file_list_free_one);
}
DEFINE_TRIVIAL_CLEANUP_FUNC(UnitFileList*, unit_file_list_free_one);
diff --git a/src/shared/install.h b/src/shared/install.h
index c1fcbe96ed..6d7518d72a 100644
--- a/src/shared/install.h
+++ b/src/shared/install.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/journal-util.c b/src/shared/journal-util.c
index fff3dfc9d1..eb7a75295f 100644
--- a/src/shared/journal-util.c
+++ b/src/shared/journal-util.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -149,3 +150,41 @@ int journal_access_check_and_warn(sd_journal *j, bool quiet) {
return r;
}
+
+bool journal_field_valid(const char *p, size_t l, bool allow_protected) {
+ const char *a;
+
+ /* We kinda enforce POSIX syntax recommendations for
+ environment variables here, but make a couple of additional
+ requirements.
+
+ http://pubs.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html */
+
+ if (l == (size_t) -1)
+ l = strlen(p);
+
+ /* No empty field names */
+ if (l <= 0)
+ return false;
+
+ /* Don't allow names longer than 64 chars */
+ if (l > 64)
+ return false;
+
+ /* Variables starting with an underscore are protected */
+ if (!allow_protected && p[0] == '_')
+ return false;
+
+ /* Don't allow digits as first character */
+ if (p[0] >= '0' && p[0] <= '9')
+ return false;
+
+ /* Only allow A-Z0-9 and '_' */
+ for (a = p; a < p + l; a++)
+ if ((*a < 'A' || *a > 'Z') &&
+ (*a < '0' || *a > '9') &&
+ *a != '_')
+ return false;
+
+ return true;
+}
diff --git a/src/shared/journal-util.h b/src/shared/journal-util.h
index 499e6c62ec..ef5e314d37 100644
--- a/src/shared/journal-util.h
+++ b/src/shared/journal-util.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -19,7 +20,10 @@
***/
#include <stdbool.h>
+#include <sys/types.h>
#include "sd-journal.h"
+bool journal_field_valid(const char *p, size_t l, bool allow_protected);
+
int journal_access_check_and_warn(sd_journal *j, bool quiet);
diff --git a/src/shared/linux/auto_dev-ioctl.h b/src/shared/linux/auto_dev-ioctl.h
index aeaeb3ea7a..b3555fb2c8 100644
--- a/src/shared/linux/auto_dev-ioctl.h
+++ b/src/shared/linux/auto_dev-ioctl.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
/*
* Copyright 2008 Red Hat, Inc. All rights reserved.
* Copyright 2008 Ian Kent <raven@themaw.net>
diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c
index 0626d80b19..afc3dcd219 100644
--- a/src/shared/logs-show.c
+++ b/src/shared/logs-show.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -48,6 +49,7 @@
#include "stdio-util.h"
#include "string-table.h"
#include "string-util.h"
+#include "strv.h"
#include "terminal-util.h"
#include "time-util.h"
#include "utf8.h"
@@ -79,37 +81,76 @@ static int print_catalog(FILE *f, sd_journal *j) {
return 0;
}
-static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) {
- size_t fl, nl;
+static int parse_field(const void *data, size_t length, const char *field, size_t field_len, char **target, size_t *target_len) {
+ size_t nl;
char *buf;
assert(data);
assert(field);
assert(target);
- fl = strlen(field);
- if (length < fl)
+ if (length < field_len)
return 0;
- if (memcmp(data, field, fl))
+ if (memcmp(data, field, field_len))
return 0;
- nl = length - fl;
+ nl = length - field_len;
- buf = newdup_suffix0(char, (const char*) data + fl, nl);
+ buf = newdup_suffix0(char, (const char*) data + field_len, nl);
if (!buf)
return log_oom();
free(*target);
*target = buf;
- if (target_size)
- *target_size = nl;
+ if (target_len)
+ *target_len = nl;
return 1;
}
+typedef struct ParseFieldVec {
+ const char *field;
+ size_t field_len;
+ char **target;
+ size_t *target_len;
+} ParseFieldVec;
+
+#define PARSE_FIELD_VEC_ENTRY(_field, _target, _target_len) \
+ { .field = _field, .field_len = strlen(_field), .target = _target, .target_len = _target_len }
+
+static int parse_fieldv(const void *data, size_t length, const ParseFieldVec *fields, unsigned n_fields) {
+ unsigned i;
+
+ for (i = 0; i < n_fields; i++) {
+ const ParseFieldVec *f = &fields[i];
+ int r;
+
+ r = parse_field(data, length, f->field, f->field_len, f->target, f->target_len);
+ if (r < 0)
+ return r;
+ else if (r > 0)
+ break;
+ }
+
+ return 0;
+}
+
+static int field_set_test(Set *fields, const char *name, size_t n) {
+ char *s = NULL;
+
+ if (!fields)
+ return 1;
+
+ s = strndupa(name, n);
+ if (!s)
+ return log_oom();
+
+ return set_get(fields, s) ? 1 : 0;
+}
+
static bool shall_print(const char *p, size_t l, OutputFlags flags) {
assert(p);
@@ -327,7 +368,8 @@ static int output_short(
sd_journal *j,
OutputMode mode,
unsigned n_columns,
- OutputFlags flags) {
+ OutputFlags flags,
+ Set *output_fields) {
int r;
const void *data;
@@ -337,6 +379,17 @@ static int output_short(
size_t hostname_len = 0, identifier_len = 0, comm_len = 0, pid_len = 0, fake_pid_len = 0, message_len = 0, realtime_len = 0, monotonic_len = 0, priority_len = 0;
int p = LOG_INFO;
bool ellipsized = false;
+ const ParseFieldVec fields[] = {
+ PARSE_FIELD_VEC_ENTRY("_PID=", &pid, &pid_len),
+ PARSE_FIELD_VEC_ENTRY("_COMM=", &comm, &comm_len),
+ PARSE_FIELD_VEC_ENTRY("MESSAGE=", &message, &message_len),
+ PARSE_FIELD_VEC_ENTRY("PRIORITY=", &priority, &priority_len),
+ PARSE_FIELD_VEC_ENTRY("_HOSTNAME=", &hostname, &hostname_len),
+ PARSE_FIELD_VEC_ENTRY("SYSLOG_PID=", &fake_pid, &fake_pid_len),
+ PARSE_FIELD_VEC_ENTRY("SYSLOG_IDENTIFIER=", &identifier, &identifier_len),
+ PARSE_FIELD_VEC_ENTRY("_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len),
+ PARSE_FIELD_VEC_ENTRY("_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len),
+ };
assert(f);
assert(j);
@@ -351,55 +404,7 @@ static int output_short(
JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
- r = parse_field(data, length, "PRIORITY=", &priority, &priority_len);
- if (r < 0)
- return r;
- else if (r > 0)
- continue;
-
- r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
- if (r < 0)
- return r;
- else if (r > 0)
- continue;
-
- r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
- if (r < 0)
- return r;
- else if (r > 0)
- continue;
-
- r = parse_field(data, length, "_COMM=", &comm, &comm_len);
- if (r < 0)
- return r;
- else if (r > 0)
- continue;
-
- r = parse_field(data, length, "_PID=", &pid, &pid_len);
- if (r < 0)
- return r;
- else if (r > 0)
- continue;
-
- r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
- if (r < 0)
- return r;
- else if (r > 0)
- continue;
-
- r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
- if (r < 0)
- return r;
- else if (r > 0)
- continue;
-
- r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
- if (r < 0)
- return r;
- else if (r > 0)
- continue;
-
- r = parse_field(data, length, "MESSAGE=", &message, &message_len);
+ r = parse_fieldv(data, length, fields, ELEMENTSOF(fields));
if (r < 0)
return r;
}
@@ -477,7 +482,8 @@ static int output_verbose(
sd_journal *j,
OutputMode mode,
unsigned n_columns,
- OutputFlags flags) {
+ OutputFlags flags,
+ Set *output_fields) {
const void *data;
size_t length;
@@ -500,7 +506,9 @@ static int output_verbose(
else {
_cleanup_free_ char *value = NULL;
- r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &value, NULL);
+ r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=",
+ STRLEN("_SOURCE_REALTIME_TIMESTAMP="), &value,
+ NULL);
if (r < 0)
return r;
assert(r > 0);
@@ -538,6 +546,12 @@ static int output_verbose(
}
fieldlen = c - (const char*) data;
+ r = field_set_test(output_fields, data, fieldlen);
+ if (r < 0)
+ return r;
+ if (!r)
+ continue;
+
if (flags & OUTPUT_COLOR && startswith(data, "MESSAGE=")) {
on = ANSI_HIGHLIGHT;
off = ANSI_NORMAL;
@@ -575,7 +589,8 @@ static int output_export(
sd_journal *j,
OutputMode mode,
unsigned n_columns,
- OutputFlags flags) {
+ OutputFlags flags,
+ Set *output_fields) {
sd_id128_t boot_id;
char sid[33];
@@ -612,6 +627,7 @@ static int output_export(
sd_id128_to_string(boot_id, sid));
JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
+ const char *c;
/* We already printed the boot id, from the data in
* the header, hence let's suppress it here */
@@ -619,18 +635,23 @@ static int output_export(
startswith(data, "_BOOT_ID="))
continue;
+ c = memchr(data, '=', length);
+ if (!c) {
+ log_error("Invalid field.");
+ return -EINVAL;
+ }
+
+ r = field_set_test(output_fields, data, c - (const char *) data);
+ if (r < 0)
+ return r;
+ if (!r)
+ continue;
+
if (utf8_is_printable_newline(data, length, false))
fwrite(data, length, 1, f);
else {
- const char *c;
uint64_t le64;
- c = memchr(data, '=', length);
- if (!c) {
- log_error("Invalid field.");
- return -EINVAL;
- }
-
fwrite(data, c - (const char*) data, 1, f);
fputc('\n', f);
le64 = htole64(length - (c - (const char*) data) - 1);
@@ -706,7 +727,8 @@ static int output_json(
sd_journal *j,
OutputMode mode,
unsigned n_columns,
- OutputFlags flags) {
+ OutputFlags flags,
+ Set *output_fields) {
uint64_t realtime, monotonic;
_cleanup_free_ char *cursor = NULL;
@@ -825,13 +847,6 @@ static int output_json(
if (!eq)
continue;
- if (separator) {
- if (mode == OUTPUT_JSON_PRETTY)
- fputs(",\n\t", f);
- else
- fputs(", ", f);
- }
-
m = eq - (const char*) data;
n = strndup(data, m);
@@ -840,6 +855,18 @@ static int output_json(
goto finish;
}
+ if (output_fields && !set_get(output_fields, n)) {
+ free(n);
+ continue;
+ }
+
+ if (separator) {
+ if (mode == OUTPUT_JSON_PRETTY)
+ fputs(",\n\t", f);
+ else
+ fputs(", ", f);
+ }
+
u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
if (u == 0) {
/* We already printed this, let's jump to the next */
@@ -924,7 +951,8 @@ static int output_cat(
sd_journal *j,
OutputMode mode,
unsigned n_columns,
- OutputFlags flags) {
+ OutputFlags flags,
+ Set *output_fields) {
const void *data;
size_t l;
@@ -957,7 +985,8 @@ static int (*output_funcs[_OUTPUT_MODE_MAX])(
sd_journal*j,
OutputMode mode,
unsigned n_columns,
- OutputFlags flags) = {
+ OutputFlags flags,
+ Set *output_fields) = {
[OUTPUT_SHORT] = output_short,
[OUTPUT_SHORT_ISO] = output_short,
@@ -980,16 +1009,28 @@ int output_journal(
OutputMode mode,
unsigned n_columns,
OutputFlags flags,
+ char **output_fields,
bool *ellipsized) {
int ret;
+ _cleanup_set_free_free_ Set *fields = NULL;
assert(mode >= 0);
assert(mode < _OUTPUT_MODE_MAX);
if (n_columns <= 0)
n_columns = columns();
- ret = output_funcs[mode](f, j, mode, n_columns, flags);
+ if (output_fields) {
+ fields = set_new(&string_hash_ops);
+ if (!fields)
+ return log_oom();
+
+ ret = set_put_strdupv(fields, output_fields);
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = output_funcs[mode](f, j, mode, n_columns, flags, fields);
if (ellipsized && ret > 0)
*ellipsized = true;
@@ -1071,7 +1112,7 @@ static int show_journal(FILE *f,
line++;
maybe_print_begin_newline(f, &flags);
- r = output_journal(f, j, mode, n_columns, flags, ellipsized);
+ r = output_journal(f, j, mode, n_columns, flags, NULL, ellipsized);
if (r < 0)
return r;
}
diff --git a/src/shared/logs-show.h b/src/shared/logs-show.h
index 6643440881..eaa69b6e90 100644
--- a/src/shared/logs-show.h
+++ b/src/shared/logs-show.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
@@ -37,6 +38,7 @@ int output_journal(
OutputMode mode,
unsigned n_columns,
OutputFlags flags,
+ char **output_fields,
bool *ellipsized);
int add_match_this_boot(sd_journal *j, const char *machine);
diff --git a/src/shared/loop-util.c b/src/shared/loop-util.c
index 047e213634..097de690e5 100644
--- a/src/shared/loop-util.c
+++ b/src/shared/loop-util.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -151,9 +152,7 @@ LoopDevice* loop_device_unref(LoopDevice *d) {
}
free(d->node);
- free(d);
-
- return NULL;
+ return mfree(d);
}
void loop_device_relinquish(LoopDevice *d) {
diff --git a/src/shared/loop-util.h b/src/shared/loop-util.h
index 45fead5f18..7e18e5779d 100644
--- a/src/shared/loop-util.h
+++ b/src/shared/loop-util.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c
index 859e5ffc1a..66eefb3036 100644
--- a/src/shared/machine-image.c
+++ b/src/shared/machine-image.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -33,12 +34,17 @@
#include "chattr-util.h"
#include "copy.h"
#include "dirent-util.h"
+#include "dissect-image.h"
#include "env-util.h"
#include "fd-util.h"
+#include "fileio.h"
#include "fs-util.h"
#include "hashmap.h"
+#include "hostname-util.h"
+#include "id128-util.h"
#include "lockfile-util.h"
#include "log.h"
+#include "loop-util.h"
#include "machine-image.h"
#include "macro.h"
#include "mkdir.h"
@@ -64,6 +70,11 @@ Image *image_unref(Image *i) {
free(i->name);
free(i->path);
+
+ free(i->hostname);
+ strv_free(i->machine_info);
+ strv_free(i->os_release);
+
return mfree(i);
}
@@ -171,9 +182,8 @@ static int image_make(
assert(filename);
- /* We explicitly *do* follow symlinks here, since we want to
- * allow symlinking trees into /var/lib/machines/, and treat
- * them normally. */
+ /* We explicitly *do* follow symlinks here, since we want to allow symlinking trees, raw files and block
+ * devices into /var/lib/machines/, and treat them normally. */
if (fstatat(dfd, filename, &st, 0) < 0)
return -errno;
@@ -286,6 +296,58 @@ static int image_make(
(*ret)->limit = (*ret)->limit_exclusive = st.st_size;
return 1;
+
+ } else if (S_ISBLK(st.st_mode)) {
+ _cleanup_close_ int block_fd = -1;
+ uint64_t size = UINT64_MAX;
+
+ /* A block device */
+
+ if (!ret)
+ return 1;
+
+ if (!pretty)
+ pretty = filename;
+
+ block_fd = openat(dfd, filename, O_RDONLY|O_NONBLOCK|O_CLOEXEC|O_NOCTTY);
+ if (block_fd < 0)
+ log_debug_errno(errno, "Failed to open block device %s/%s, ignoring: %m", path, filename);
+ else {
+ if (fstat(block_fd, &st) < 0)
+ return -errno;
+ if (!S_ISBLK(st.st_mode)) /* Verify that what we opened is actually what we think it is */
+ return -ENOTTY;
+
+ if (!read_only) {
+ int state = 0;
+
+ if (ioctl(block_fd, BLKROGET, &state) < 0)
+ log_debug_errno(errno, "Failed to issue BLKROGET on device %s/%s, ignoring: %m", path, filename);
+ else if (state)
+ read_only = true;
+ }
+
+ if (ioctl(block_fd, BLKGETSIZE64, &size) < 0)
+ log_debug_errno(errno, "Failed to issue BLKFLSBUF on device %s/%s, ignoring: %m", path, filename);
+
+ block_fd = safe_close(block_fd);
+ }
+
+ r = image_new(IMAGE_BLOCK,
+ pretty,
+ path,
+ filename,
+ !(st.st_mode & 0222) || read_only,
+ 0,
+ 0,
+ ret);
+ if (r < 0)
+ return r;
+
+ if (size != 0 && size != UINT64_MAX)
+ (*ret)->usage = (*ret)->usage_exclusive = (*ret)->limit = (*ret)->limit_exclusive = size;
+
+ return 1;
}
return 0;
@@ -395,15 +457,6 @@ int image_discover(Hashmap *h) {
return 0;
}
-void image_hashmap_free(Hashmap *map) {
- Image *i;
-
- while ((i = hashmap_steal_first(map)))
- image_unref(i);
-
- hashmap_free(map);
-}
-
int image_remove(Image *i) {
_cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
_cleanup_strv_free_ char **settings = NULL;
@@ -432,9 +485,15 @@ int image_remove(Image *i) {
switch (i->type) {
case IMAGE_SUBVOLUME:
- r = btrfs_subvol_remove(i->path, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
- if (r < 0)
- return r;
+
+ /* Let's unlink first, maybe it is a symlink? If that works we are happy. Otherwise, let's get out the
+ * big guns */
+ if (unlink(i->path) < 0) {
+ r = btrfs_subvol_remove(i->path, BTRFS_REMOVE_RECURSIVE|BTRFS_REMOVE_QUOTA);
+ if (r < 0)
+ return r;
+ }
+
break;
case IMAGE_DIRECTORY:
@@ -446,6 +505,16 @@ int image_remove(Image *i) {
break;
+ case IMAGE_BLOCK:
+
+ /* If this is inside of /dev, then it's a real block device, hence let's not touch the device node
+ * itself (but let's remove the stuff stored alongside it). If it's anywhere else, let's try to unlink
+ * the thing (it's most likely a symlink after all). */
+
+ if (path_startswith(i->path, "/dev"))
+ break;
+
+ _fallthrough_;
case IMAGE_RAW:
if (unlink(i->path) < 0)
return -errno;
@@ -530,12 +599,20 @@ int image_rename(Image *i, const char *new_name) {
if (file_attr & FS_IMMUTABLE_FL)
(void) chattr_path(i->path, 0, FS_IMMUTABLE_FL);
- /* fall through */
-
+ _fallthrough_;
case IMAGE_SUBVOLUME:
new_path = file_in_same_dir(i->path, new_name);
break;
+ case IMAGE_BLOCK:
+
+ /* Refuse renaming raw block devices in /dev, the names are picked by udev after all. */
+ if (path_startswith(i->path, "/dev"))
+ return -EROFS;
+
+ new_path = file_in_same_dir(i->path, new_name);
+ break;
+
case IMAGE_RAW: {
const char *fn;
@@ -563,13 +640,8 @@ int image_rename(Image *i, const char *new_name) {
if (file_attr & FS_IMMUTABLE_FL)
(void) chattr_path(new_path, FS_IMMUTABLE_FL, FS_IMMUTABLE_FL);
- free(i->path);
- i->path = new_path;
- new_path = NULL;
-
- free(i->name);
- i->name = nn;
- nn = NULL;
+ free_and_replace(i->path, new_path);
+ free_and_replace(i->name, nn);
STRV_FOREACH(j, settings) {
r = rename_auxiliary_file(*j, new_name, ".nspawn");
@@ -659,6 +731,7 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
r = copy_file_atomic(i->path, new_path, read_only ? 0444 : 0644, FS_NOCOW_FL, COPY_REFLINK);
break;
+ case IMAGE_BLOCK:
default:
return -EOPNOTSUPP;
}
@@ -682,6 +755,7 @@ int image_clone(Image *i, const char *new_name, bool read_only) {
int image_read_only(Image *i, bool b) {
_cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
int r;
+
assert(i);
if (IMAGE_IS_VENDOR(i) || IMAGE_IS_HOST(i))
@@ -737,6 +811,26 @@ int image_read_only(Image *i, bool b) {
break;
}
+ case IMAGE_BLOCK: {
+ _cleanup_close_ int fd = -1;
+ struct stat st;
+ int state = b;
+
+ fd = open(i->path, O_CLOEXEC|O_RDONLY|O_NONBLOCK|O_NOCTTY);
+ if (fd < 0)
+ return -errno;
+
+ if (fstat(fd, &st) < 0)
+ return -errno;
+ if (!S_ISBLK(st.st_mode))
+ return -ENOTTY;
+
+ if (ioctl(fd, BLKROSET, &state) < 0)
+ return -errno;
+
+ break;
+ }
+
default:
return -EOPNOTSUPP;
}
@@ -772,13 +866,24 @@ int image_path_lock(const char *path, int operation, LockFile *global, LockFile
return -EBUSY;
if (stat(path, &st) >= 0) {
- if (asprintf(&p, "/run/systemd/nspawn/locks/inode-%lu:%lu", (unsigned long) st.st_dev, (unsigned long) st.st_ino) < 0)
+ if (S_ISBLK(st.st_mode))
+ r = asprintf(&p, "/run/systemd/nspawn/locks/block-%u:%u", major(st.st_rdev), minor(st.st_rdev));
+ else if (S_ISDIR(st.st_mode) || S_ISREG(st.st_mode))
+ r = asprintf(&p, "/run/systemd/nspawn/locks/inode-%lu:%lu", (unsigned long) st.st_dev, (unsigned long) st.st_ino);
+ else
+ return -ENOTTY;
+
+ if (r < 0)
return -ENOMEM;
}
- r = make_lock_file_for(path, operation, &t);
- if (r < 0)
- return r;
+ /* For block devices we don't need the "local" lock, as the major/minor lock above should be sufficient, since
+ * block devices are device local anyway. */
+ if (!path_startswith(path, "/dev")) {
+ r = make_lock_file_for(path, operation, &t);
+ if (r < 0)
+ return r;
+ }
if (p) {
mkdir_p("/run/systemd/nspawn/locks", 0700);
@@ -814,6 +919,118 @@ int image_set_limit(Image *i, uint64_t referenced_max) {
return btrfs_subvol_set_subtree_quota_limit(i->path, 0, referenced_max);
}
+int image_read_metadata(Image *i) {
+ _cleanup_release_lock_file_ LockFile global_lock = LOCK_FILE_INIT, local_lock = LOCK_FILE_INIT;
+ int r;
+
+ assert(i);
+
+ r = image_path_lock(i->path, LOCK_SH|LOCK_NB, &global_lock, &local_lock);
+ if (r < 0)
+ return r;
+
+ switch (i->type) {
+
+ case IMAGE_SUBVOLUME:
+ case IMAGE_DIRECTORY: {
+ _cleanup_strv_free_ char **machine_info = NULL, **os_release = NULL;
+ sd_id128_t machine_id = SD_ID128_NULL;
+ _cleanup_free_ char *hostname = NULL;
+ _cleanup_free_ char *path = NULL;
+
+ r = chase_symlinks("/etc/hostname", i->path, CHASE_PREFIX_ROOT, &path);
+ if (r < 0 && r != -ENOENT)
+ log_debug_errno(r, "Failed to chase /etc/hostname in image %s: %m", i->name);
+ else if (r >= 0) {
+ r = read_etc_hostname(path, &hostname);
+ if (r < 0)
+ log_debug_errno(errno, "Failed to read /etc/hostname of image %s: %m", i->name);
+ }
+
+ path = mfree(path);
+
+ r = chase_symlinks("/etc/machine-id", i->path, CHASE_PREFIX_ROOT, &path);
+ if (r < 0 && r != -ENOENT)
+ log_debug_errno(r, "Failed to chase /etc/machine-id in image %s: %m", i->name);
+ else if (r >= 0) {
+ _cleanup_close_ int fd = -1;
+
+ fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
+ if (fd < 0)
+ log_debug_errno(errno, "Failed to open %s: %m", path);
+ else {
+ r = id128_read_fd(fd, ID128_PLAIN, &machine_id);
+ if (r < 0)
+ log_debug_errno(r, "Image %s contains invalid machine ID.", i->name);
+ }
+ }
+
+ path = mfree(path);
+
+ r = chase_symlinks("/etc/machine-info", i->path, CHASE_PREFIX_ROOT, &path);
+ if (r < 0 && r != -ENOENT)
+ log_debug_errno(r, "Failed to chase /etc/machine-info in image %s: %m", i->name);
+ else if (r >= 0) {
+ r = load_env_file_pairs(NULL, path, NULL, &machine_info);
+ if (r < 0)
+ log_debug_errno(r, "Failed to parse machine-info data of %s: %m", i->name);
+ }
+
+ path = mfree(path);
+
+ r = chase_symlinks("/etc/os-release", i->path, CHASE_PREFIX_ROOT, &path);
+ if (r == -ENOENT)
+ r = chase_symlinks("/usr/lib/os-release", i->path, CHASE_PREFIX_ROOT, &path);
+ if (r < 0 && r != -ENOENT)
+ log_debug_errno(r, "Failed to chase os-release in image: %m");
+ else if (r >= 0) {
+ r = load_env_file_pairs(NULL, path, NULL, &os_release);
+ if (r < 0)
+ log_debug_errno(r, "Failed to parse os-release data of %s: %m", i->name);
+ }
+
+ free_and_replace(i->hostname, hostname);
+ i->machine_id = machine_id;
+ strv_free_and_replace(i->machine_info, machine_info);
+ strv_free_and_replace(i->os_release, os_release);
+
+ break;
+ }
+
+ case IMAGE_RAW:
+ case IMAGE_BLOCK: {
+ _cleanup_(loop_device_unrefp) LoopDevice *d = NULL;
+ _cleanup_(dissected_image_unrefp) DissectedImage *m = NULL;
+
+ r = loop_device_make_by_path(i->path, O_RDONLY, &d);
+ if (r < 0)
+ return r;
+
+ r = dissect_image(d->fd, NULL, 0, DISSECT_IMAGE_REQUIRE_ROOT, &m);
+ if (r < 0)
+ return r;
+
+ r = dissected_image_acquire_metadata(m);
+ if (r < 0)
+ return r;
+
+ free_and_replace(i->hostname, m->hostname);
+ i->machine_id = m->machine_id;
+ strv_free_and_replace(i->machine_info, m->machine_info);
+ strv_free_and_replace(i->os_release, m->os_release);
+
+ break;
+ }
+
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ i->metadata_valid = true;
+
+ return 0;
+}
+
int image_name_lock(const char *name, int operation, LockFile *ret) {
const char *p;
@@ -860,6 +1077,7 @@ static const char* const image_type_table[_IMAGE_TYPE_MAX] = {
[IMAGE_DIRECTORY] = "directory",
[IMAGE_SUBVOLUME] = "subvolume",
[IMAGE_RAW] = "raw",
+ [IMAGE_BLOCK] = "block",
};
DEFINE_STRING_TABLE_LOOKUP(image_type, ImageType);
diff --git a/src/shared/machine-image.h b/src/shared/machine-image.h
index 7410168c4f..3df9a29a24 100644
--- a/src/shared/machine-image.h
+++ b/src/shared/machine-image.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
@@ -33,6 +34,7 @@ typedef enum ImageType {
IMAGE_DIRECTORY,
IMAGE_SUBVOLUME,
IMAGE_RAW,
+ IMAGE_BLOCK,
_IMAGE_TYPE_MAX,
_IMAGE_TYPE_INVALID = -1
} ImageType;
@@ -51,11 +53,20 @@ typedef struct Image {
uint64_t limit;
uint64_t limit_exclusive;
+ char *hostname;
+ sd_id128_t machine_id;
+ char **machine_info;
+ char **os_release;
+
+ bool metadata_valid;
+
void *userdata;
} Image;
Image *image_unref(Image *i);
-void image_hashmap_free(Hashmap *map);
+static inline Hashmap* image_hashmap_free(Hashmap *map) {
+ return hashmap_free_with_destructor(map, image_unref);
+}
DEFINE_TRIVIAL_CLEANUP_FUNC(Image*, image_unref);
DEFINE_TRIVIAL_CLEANUP_FUNC(Hashmap*, image_hashmap_free);
@@ -78,6 +89,8 @@ int image_name_lock(const char *name, int operation, LockFile *ret);
int image_set_limit(Image *i, uint64_t referenced_max);
+int image_read_metadata(Image *i);
+
static inline bool IMAGE_IS_HIDDEN(const struct Image *i) {
assert(i);
diff --git a/src/shared/machine-pool.c b/src/shared/machine-pool.c
index c581bdeb79..167bcfad36 100644
--- a/src/shared/machine-pool.c
+++ b/src/shared/machine-pool.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
diff --git a/src/shared/machine-pool.h b/src/shared/machine-pool.h
index 40fe5ecb3a..6e390521e8 100644
--- a/src/shared/machine-pool.h
+++ b/src/shared/machine-pool.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/meson.build b/src/shared/meson.build
index 883821352e..06a944c49d 100644
--- a/src/shared/meson.build
+++ b/src/shared/meson.build
@@ -1,3 +1,20 @@
+# SPDX-License-Identifier: LGPL-2.1+
+#
+# Copyright 2017 Zbigniew Jędrzejewski-Szmek
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# systemd is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with systemd; If not, see <http://www.gnu.org/licenses/>.
+
shared_sources = '''
acl-util.h
acpi-fpdt.c
@@ -10,6 +27,8 @@ shared_sources = '''
base-filesystem.h
boot-timestamps.c
boot-timestamps.h
+ bootspec.c
+ bootspec.h
bus-unit-util.c
bus-unit-util.h
bus-util.c
@@ -88,6 +107,8 @@ shared_sources = '''
sysctl-util.h
tests.c
tests.h
+ tomoyo-util.c
+ tomoyo-util.h
udev-util.h
udev-util.c
uid-range.c
diff --git a/src/shared/nsflags.c b/src/shared/nsflags.c
index aeb79b131e..05ec9feb8d 100644
--- a/src/shared/nsflags.c
+++ b/src/shared/nsflags.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
diff --git a/src/shared/nsflags.h b/src/shared/nsflags.h
index 152ab8b936..dcac6cd0b2 100644
--- a/src/shared/nsflags.h
+++ b/src/shared/nsflags.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/output-mode.c b/src/shared/output-mode.c
index 29dcba9f6b..5256e917a3 100644
--- a/src/shared/output-mode.c
+++ b/src/shared/output-mode.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
diff --git a/src/shared/output-mode.h b/src/shared/output-mode.h
index 2a1bfd98d0..747f7eb1b9 100644
--- a/src/shared/output-mode.h
+++ b/src/shared/output-mode.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/pager.c b/src/shared/pager.c
index 0661ff0bb9..39997278f1 100644
--- a/src/shared/pager.c
+++ b/src/shared/pager.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -80,9 +81,10 @@ int pager_open(bool no_pager, bool jump_to_end) {
if (pager && STR_IN_SET(pager, "", "cat"))
return 0;
- /* Determine and cache number of columns before we spawn the
- * pager so that we get the value from the actual tty */
+ /* Determine and cache number of columns/lines before we spawn the pager so that we get the value from the
+ * actual tty */
(void) columns();
+ (void) lines();
if (pipe2(fd, O_CLOEXEC) < 0)
return log_error_errno(errno, "Failed to create pager pipe: %m");
diff --git a/src/shared/pager.h b/src/shared/pager.h
index 893e1d2bb6..99716f8747 100644
--- a/src/shared/pager.h
+++ b/src/shared/pager.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c
index 802e4b9c8d..d57c78a8b1 100644
--- a/src/shared/path-lookup.c
+++ b/src/shared/path-lookup.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -38,7 +39,7 @@
#include "user-util.h"
#include "util.h"
-static int user_runtime_dir(char **ret, const char *suffix) {
+int xdg_user_runtime_dir(char **ret, const char *suffix) {
const char *e;
char *j;
@@ -57,7 +58,7 @@ static int user_runtime_dir(char **ret, const char *suffix) {
return 0;
}
-static int user_config_dir(char **ret, const char *suffix) {
+int xdg_user_config_dir(char **ret, const char *suffix) {
const char *e;
char *j;
int r;
@@ -84,7 +85,7 @@ static int user_config_dir(char **ret, const char *suffix) {
return 0;
}
-static int user_data_dir(char **ret, const char *suffix) {
+int xdg_user_data_dir(char **ret, const char *suffix) {
const char *e;
char *j;
int r;
@@ -130,23 +131,7 @@ static const char* const user_config_unit_paths[] = {
NULL
};
-static char** user_dirs(
- const char *persistent_config,
- const char *runtime_config,
- const char *generator,
- const char *generator_early,
- const char *generator_late,
- const char *transient,
- const char *persistent_control,
- const char *runtime_control) {
-
- _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
- _cleanup_free_ char *data_home = NULL;
- _cleanup_strv_free_ char **res = NULL;
- const char *e;
- char **tmp;
- int r;
-
+int xdg_user_dirs(char ***ret_config_dirs, char ***ret_data_dirs) {
/* Implement the mechanisms defined in
*
* http://standards.freedesktop.org/basedir-spec/basedir-spec-0.6.html
@@ -155,18 +140,16 @@ static char** user_dirs(
* want to encourage that distributors ship their unit files
* as data, and allow overriding as configuration.
*/
+ const char *e;
+ _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
e = getenv("XDG_CONFIG_DIRS");
if (e) {
config_dirs = strv_split(e, ":");
if (!config_dirs)
- return NULL;
+ return -ENOMEM;
}
- r = user_data_dir(&data_home, "/systemd/user");
- if (r < 0 && r != -ENXIO)
- return NULL;
-
e = getenv("XDG_DATA_DIRS");
if (e)
data_dirs = strv_split(e, ":");
@@ -175,6 +158,36 @@ static char** user_dirs(
"/usr/share",
NULL);
if (!data_dirs)
+ return -ENOMEM;
+
+ *ret_config_dirs = config_dirs;
+ *ret_data_dirs = data_dirs;
+ config_dirs = data_dirs = NULL;
+ return 0;
+}
+
+static char** user_dirs(
+ const char *persistent_config,
+ const char *runtime_config,
+ const char *generator,
+ const char *generator_early,
+ const char *generator_late,
+ const char *transient,
+ const char *persistent_control,
+ const char *runtime_control) {
+
+ _cleanup_strv_free_ char **config_dirs = NULL, **data_dirs = NULL;
+ _cleanup_free_ char *data_home = NULL;
+ _cleanup_strv_free_ char **res = NULL;
+ char **tmp;
+ int r;
+
+ r = xdg_user_dirs(&config_dirs, &data_dirs);
+ if (r < 0)
+ return NULL;
+
+ r = xdg_user_data_dir(&data_home, "/systemd/user");
+ if (r < 0 && r != -ENXIO)
return NULL;
/* Now merge everything we found. */
@@ -245,7 +258,6 @@ static int acquire_generator_dirs(
char **generator_early,
char **generator_late) {
- _cleanup_(rmdir_and_freep) char *t = NULL;
_cleanup_free_ char *x = NULL, *y = NULL, *z = NULL;
const char *prefix;
@@ -311,7 +323,7 @@ static int acquire_transient_dir(
else if (scope == UNIT_FILE_SYSTEM)
transient = strdup("/run/systemd/transient");
else
- return user_runtime_dir(ret, "/systemd/transient");
+ return xdg_user_runtime_dir(ret, "/systemd/transient");
if (!transient)
return -ENOMEM;
@@ -339,11 +351,11 @@ static int acquire_config_dirs(UnitFileScope scope, char **persistent, char **ru
break;
case UNIT_FILE_USER:
- r = user_config_dir(&a, "/systemd/user");
+ r = xdg_user_config_dir(&a, "/systemd/user");
if (r < 0 && r != -ENXIO)
return r;
- r = user_runtime_dir(runtime, "/systemd/user");
+ r = xdg_user_runtime_dir(runtime, "/systemd/user");
if (r < 0) {
if (r != -ENXIO)
return r;
@@ -399,11 +411,11 @@ static int acquire_control_dirs(UnitFileScope scope, char **persistent, char **r
}
case UNIT_FILE_USER:
- r = user_config_dir(&a, "/systemd/system.control");
+ r = xdg_user_config_dir(&a, "/systemd/system.control");
if (r < 0 && r != -ENXIO)
return r;
- r = user_runtime_dir(runtime, "/systemd/system.control");
+ r = xdg_user_runtime_dir(runtime, "/systemd/system.control");
if (r < 0) {
if (r != -ENXIO)
return r;
@@ -736,6 +748,14 @@ int lookup_paths_reduce(LookupPaths *p) {
struct stat st;
unsigned k;
+ /* Never strip the transient and control directories from the path */
+ if (path_equal_ptr(p->search_path[c], p->transient) ||
+ path_equal_ptr(p->search_path[c], p->persistent_control) ||
+ path_equal_ptr(p->search_path[c], p->runtime_control)) {
+ c++;
+ continue;
+ }
+
if (p->root_dir)
r = lstat(p->search_path[c], &st);
else
diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h
index fc8b8ed8c7..42a870aa3e 100644
--- a/src/shared/path-lookup.h
+++ b/src/shared/path-lookup.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
@@ -27,8 +28,8 @@ typedef struct LookupPaths LookupPaths;
#include "macro.h"
typedef enum LookupPathsFlags {
- LOOKUP_PATHS_EXCLUDE_GENERATED = 1,
- LOOKUP_PATHS_TEMPORARY_GENERATED,
+ LOOKUP_PATHS_EXCLUDE_GENERATED = 1 << 0,
+ LOOKUP_PATHS_TEMPORARY_GENERATED = 1 << 1,
} LookupPathsFlags;
struct LookupPaths {
@@ -67,6 +68,10 @@ struct LookupPaths {
};
int lookup_paths_init(LookupPaths *p, UnitFileScope scope, LookupPathsFlags flags, const char *root_dir);
+int xdg_user_dirs(char ***ret_config_dirs, char ***ret_data_dirs);
+int xdg_user_runtime_dir(char **ret, const char *suffix);
+int xdg_user_config_dir(char **ret, const char *suffix);
+int xdg_user_data_dir(char **ret, const char *suffix);
bool path_is_user_data_dir(const char *path);
bool path_is_user_config_dir(const char *path);
diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c
index 0c92184ba5..94a4dd513f 100644
--- a/src/shared/ptyfwd.c
+++ b/src/shared/ptyfwd.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -170,6 +171,30 @@ static bool ignore_vhangup(PTYForward *f) {
return false;
}
+static bool drained(PTYForward *f) {
+ int q = 0;
+
+ assert(f);
+
+ if (f->out_buffer_full > 0)
+ return false;
+
+ if (f->master_readable)
+ return false;
+
+ if (ioctl(f->master, TIOCINQ, &q) < 0)
+ log_debug_errno(errno, "TIOCINQ failed on master: %m");
+ else if (q > 0)
+ return false;
+
+ if (ioctl(f->master, TIOCOUTQ, &q) < 0)
+ log_debug_errno(errno, "TIOCOUTQ failed on master: %m");
+ else if (q > 0)
+ return false;
+
+ return true;
+}
+
static int shovel(PTYForward *f) {
ssize_t k;
@@ -305,7 +330,7 @@ static int shovel(PTYForward *f) {
/* If we were asked to drain, and there's nothing more to handle from the master, then call the callback
* too. */
- if (f->drain && f->out_buffer_full == 0 && !f->master_readable)
+ if (f->drain && drained(f))
return pty_forward_done(f, 0);
return 0;
@@ -546,6 +571,28 @@ bool pty_forward_drain(PTYForward *f) {
*/
f->drain = true;
+ return drained(f);
+}
+
+int pty_forward_set_priority(PTYForward *f, int64_t priority) {
+ int r;
+ assert(f);
- return f->out_buffer_full == 0 && !f->master_readable;
+ r = sd_event_source_set_priority(f->stdin_event_source, priority);
+ if (r < 0)
+ return r;
+
+ r = sd_event_source_set_priority(f->stdout_event_source, priority);
+ if (r < 0)
+ return r;
+
+ r = sd_event_source_set_priority(f->master_event_source, priority);
+ if (r < 0)
+ return r;
+
+ r = sd_event_source_set_priority(f->sigwinch_event_source, priority);
+ if (r < 0)
+ return r;
+
+ return 0;
}
diff --git a/src/shared/ptyfwd.h b/src/shared/ptyfwd.h
index 3fad1d3b26..6a0e0c6a2b 100644
--- a/src/shared/ptyfwd.h
+++ b/src/shared/ptyfwd.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
@@ -53,4 +54,6 @@ void pty_forward_set_handler(PTYForward *f, PTYForwardHandler handler, void *use
bool pty_forward_drain(PTYForward *f);
+int pty_forward_set_priority(PTYForward *f, int64_t priority);
+
DEFINE_TRIVIAL_CLEANUP_FUNC(PTYForward*, pty_forward_free);
diff --git a/src/shared/resolve-util.c b/src/shared/resolve-util.c
index e2da81bab7..edcb8e05e7 100644
--- a/src/shared/resolve-util.c
+++ b/src/shared/resolve-util.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
diff --git a/src/shared/resolve-util.h b/src/shared/resolve-util.h
index 8636a6c134..975156ca96 100644
--- a/src/shared/resolve-util.h
+++ b/src/shared/resolve-util.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c
index 14a75bfffe..62742858c7 100644
--- a/src/shared/seccomp-util.c
+++ b/src/shared/seccomp-util.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -313,6 +314,7 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
"set_robust_list\0"
"set_thread_area\0"
"set_tid_address\0"
+ "set_tls\0"
"sigreturn\0"
"time\0"
"ugetrlimit\0"
@@ -465,7 +467,7 @@ const SyscallFilterSet syscall_filter_sets[_SYSCALL_FILTER_SET_MAX] = {
"stat64\0"
"statfs\0"
"statfs64\0"
-#ifdef __PNR_statx
+#ifdef __NR_statx
"statx\0"
#endif
"symlink\0"
@@ -900,20 +902,20 @@ int seccomp_load_syscall_filter_set(uint32_t default_action, const SyscallFilter
return 0;
}
-int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Set* set, uint32_t action) {
+int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* set, uint32_t action) {
uint32_t arch;
int r;
/* Similar to seccomp_load_syscall_filter_set(), but takes a raw Set* of syscalls, instead of a
* SyscallFilterSet* table. */
- if (set_isempty(set) && default_action == SCMP_ACT_ALLOW)
+ if (hashmap_isempty(set) && default_action == SCMP_ACT_ALLOW)
return 0;
SECCOMP_FOREACH_LOCAL_ARCH(arch) {
_cleanup_(seccomp_releasep) scmp_filter_ctx seccomp = NULL;
Iterator i;
- void *id;
+ void *id, *val;
log_debug("Operating on architecture: %s", seccomp_arch_to_string(arch));
@@ -921,8 +923,14 @@ int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Set* set, uint3
if (r < 0)
return r;
- SET_FOREACH(id, set, i) {
- r = seccomp_rule_add_exact(seccomp, action, PTR_TO_INT(id) - 1, 0);
+ HASHMAP_FOREACH_KEY(val, id, set, i) {
+ uint32_t a = action;
+ int e = PTR_TO_INT(val);
+
+ if (action != SCMP_ACT_ALLOW && e >= 0)
+ a = SCMP_ACT_ERRNO(e);
+
+ r = seccomp_rule_add_exact(seccomp, a, PTR_TO_INT(id) - 1, 0);
if (r < 0) {
/* If the system call is not known on this architecture, then that's fine, let's ignore it */
_cleanup_free_ char *n = NULL;
@@ -1433,6 +1441,14 @@ int seccomp_memory_deny_write_execute(void) {
if (r < 0)
continue;
+#ifdef __NR_pkey_mprotect
+ r = add_seccomp_syscall_filter(seccomp, arch, SCMP_SYS(pkey_mprotect),
+ 1,
+ SCMP_A2(SCMP_CMP_MASKED_EQ, PROT_EXEC, PROT_EXEC));
+ if (r < 0)
+ continue;
+#endif
+
if (shmat_syscall != 0) {
r = add_seccomp_syscall_filter(seccomp, arch, SCMP_SYS(shmat),
1,
@@ -1515,7 +1531,7 @@ int parse_syscall_archs(char **l, Set **archs) {
return 0;
}
-int seccomp_filter_set_add(Set *filter, bool add, const SyscallFilterSet *set) {
+int seccomp_filter_set_add(Hashmap *filter, bool add, const SyscallFilterSet *set) {
const char *i;
int r;
@@ -1543,11 +1559,11 @@ int seccomp_filter_set_add(Set *filter, bool add, const SyscallFilterSet *set) {
}
if (add) {
- r = set_put(filter, INT_TO_PTR(id + 1));
+ r = hashmap_put(filter, INT_TO_PTR(id + 1), INT_TO_PTR(-1));
if (r < 0)
return r;
} else
- (void) set_remove(filter, INT_TO_PTR(id + 1));
+ (void) hashmap_remove(filter, INT_TO_PTR(id + 1));
}
}
diff --git a/src/shared/seccomp-util.h b/src/shared/seccomp-util.h
index 6dfa465ef3..ad2ab7f6b5 100644
--- a/src/shared/seccomp-util.h
+++ b/src/shared/seccomp-util.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
@@ -73,12 +74,12 @@ extern const SyscallFilterSet syscall_filter_sets[];
const SyscallFilterSet *syscall_filter_set_find(const char *name);
-int seccomp_filter_set_add(Set *s, bool b, const SyscallFilterSet *set);
+int seccomp_filter_set_add(Hashmap *s, bool b, const SyscallFilterSet *set);
int seccomp_add_syscall_filter_item(scmp_filter_ctx *ctx, const char *name, uint32_t action, char **exclude);
int seccomp_load_syscall_filter_set(uint32_t default_action, const SyscallFilterSet *set, uint32_t action);
-int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Set* set, uint32_t action);
+int seccomp_load_syscall_filter_set_raw(uint32_t default_action, Hashmap* set, uint32_t action);
int seccomp_restrict_archs(Set *archs);
int seccomp_restrict_namespaces(unsigned long retain);
diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c
index 8c1624ff46..ecac98e0ab 100644
--- a/src/shared/sleep-config.c
+++ b/src/shared/sleep-config.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -58,10 +59,10 @@ int parse_sleep_config(const char *verb, char ***_modes, char ***_states) {
{}
};
- config_parse_many_nulstr(PKGSYSCONFDIR "/sleep.conf",
- CONF_PATHS_NULSTR("systemd/sleep.conf.d"),
- "Sleep\0", config_item_table_lookup, items,
- false, NULL);
+ (void) config_parse_many_nulstr(PKGSYSCONFDIR "/sleep.conf",
+ CONF_PATHS_NULSTR("systemd/sleep.conf.d"),
+ "Sleep\0", config_item_table_lookup, items,
+ CONFIG_PARSE_WARN, NULL);
if (streq(verb, "suspend")) {
/* empty by default */
diff --git a/src/shared/sleep-config.h b/src/shared/sleep-config.h
index ad10039ff4..fc5a81d954 100644
--- a/src/shared/sleep-config.h
+++ b/src/shared/sleep-config.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/spawn-ask-password-agent.c b/src/shared/spawn-ask-password-agent.c
index a46b7525f0..9af5faa3dd 100644
--- a/src/shared/spawn-ask-password-agent.c
+++ b/src/shared/spawn-ask-password-agent.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
diff --git a/src/shared/spawn-ask-password-agent.h b/src/shared/spawn-ask-password-agent.h
index fb0749b13f..158f8839ab 100644
--- a/src/shared/spawn-ask-password-agent.h
+++ b/src/shared/spawn-ask-password-agent.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/spawn-polkit-agent.c b/src/shared/spawn-polkit-agent.c
index 9a40147662..423069fb0e 100644
--- a/src/shared/spawn-polkit-agent.c
+++ b/src/shared/spawn-polkit-agent.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
diff --git a/src/shared/spawn-polkit-agent.h b/src/shared/spawn-polkit-agent.h
index 42b2989ded..9f26fa10a7 100644
--- a/src/shared/spawn-polkit-agent.h
+++ b/src/shared/spawn-polkit-agent.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
@@ -19,5 +20,22 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "bus-util.h"
+
int polkit_agent_open(void);
void polkit_agent_close(void);
+
+static inline void polkit_agent_open_if_enabled(
+ BusTransport transport,
+ bool ask_password) {
+
+ /* Open the polkit agent as a child process if necessary */
+
+ if (transport != BUS_TRANSPORT_LOCAL)
+ return;
+
+ if (!ask_password)
+ return;
+
+ polkit_agent_open();
+}
diff --git a/src/shared/specifier.c b/src/shared/specifier.c
index 81379041cc..23aaa88c4b 100644
--- a/src/shared/specifier.c
+++ b/src/shared/specifier.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -31,6 +32,8 @@
#include "macro.h"
#include "specifier.h"
#include "string-util.h"
+#include "strv.h"
+#include "user-util.h"
/*
* Generic infrastructure for replacing %x style specifiers in
@@ -38,11 +41,16 @@
*
*/
+/* Any ASCII character or digit: our pool of potential specifiers,
+ * and "%" used for escaping. */
+#define POSSIBLE_SPECIFIERS ALPHANUMERICAL "%"
+
int specifier_printf(const char *text, const Specifier table[], void *userdata, char **_ret) {
- char *ret, *t;
+ size_t l;
+ _cleanup_free_ char *ret = NULL;
+ char *t;
const char *f;
bool percent = false;
- size_t l;
int r;
assert(text);
@@ -73,28 +81,25 @@ int specifier_printf(const char *text, const Specifier table[], void *userdata,
size_t k, j;
r = i->lookup(i->specifier, i->data, userdata, &w);
- if (r < 0) {
- free(ret);
+ if (r < 0)
return r;
- }
j = t - ret;
k = strlen(w);
n = new(char, j + k + l + 1);
- if (!n) {
- free(ret);
+ if (!n)
return -ENOMEM;
- }
memcpy(n, ret, j);
memcpy(n + j, w, k);
- free(ret);
-
- ret = n;
- t = n + j + k;
- } else {
+ free_and_replace(ret, n);
+ t = ret + j + k;
+ } else if (strchr(POSSIBLE_SPECIFIERS, *f))
+ /* Oops, an unknown specifier. */
+ return -EBADSLT;
+ else {
*(t++) = '%';
*(t++) = *f;
}
@@ -113,6 +118,7 @@ int specifier_printf(const char *text, const Specifier table[], void *userdata,
*t = 0;
*_ret = ret;
+ ret = NULL;
return 0;
}
@@ -190,3 +196,74 @@ int specifier_kernel_release(char specifier, void *data, void *userdata, char **
*ret = n;
return 0;
}
+
+int specifier_user_name(char specifier, void *data, void *userdata, char **ret) {
+ char *t;
+
+ /* If we are UID 0 (root), this will not result in NSS, otherwise it might. This is good, as we want to be able
+ * to run this in PID 1, where our user ID is 0, but where NSS lookups are not allowed.
+
+ * We don't use getusername_malloc() here, because we don't want to look at $USER, to remain consistent with
+ * specifer_user_id() below.
+ */
+
+ t = uid_to_name(getuid());
+ if (!t)
+ return -ENOMEM;
+
+ *ret = t;
+ return 0;
+}
+
+int specifier_user_id(char specifier, void *data, void *userdata, char **ret) {
+
+ if (asprintf(ret, UID_FMT, getuid()) < 0)
+ return -ENOMEM;
+
+ return 0;
+}
+
+int specifier_user_home(char specifier, void *data, void *userdata, char **ret) {
+
+ /* On PID 1 (which runs as root) this will not result in NSS,
+ * which is good. See above */
+
+ return get_home_dir(ret);
+}
+
+int specifier_user_shell(char specifier, void *data, void *userdata, char **ret) {
+
+ /* On PID 1 (which runs as root) this will not result in NSS,
+ * which is good. See above */
+
+ return get_shell(ret);
+}
+
+int specifier_escape_strv(char **l, char ***ret) {
+ char **z, **p, **q;
+
+ assert(ret);
+
+ if (strv_isempty(l)) {
+ *ret = NULL;
+ return 0;
+ }
+
+ z = new(char*, strv_length(l)+1);
+ if (!z)
+ return -ENOMEM;
+
+ for (p = l, q = z; *p; p++, q++) {
+
+ *q = specifier_escape(*p);
+ if (!*q) {
+ strv_free(z);
+ return -ENOMEM;
+ }
+ }
+
+ *q = NULL;
+ *ret = z;
+
+ return 0;
+}
diff --git a/src/shared/specifier.h b/src/shared/specifier.h
index 6b1623ee61..bd6bc55577 100644
--- a/src/shared/specifier.h
+++ b/src/shared/specifier.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
@@ -19,6 +20,8 @@
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
+#include "string-util.h"
+
typedef int (*SpecifierCallback)(char specifier, void *data, void *userdata, char **ret);
typedef struct Specifier {
@@ -35,3 +38,14 @@ int specifier_machine_id(char specifier, void *data, void *userdata, char **ret)
int specifier_boot_id(char specifier, void *data, void *userdata, char **ret);
int specifier_host_name(char specifier, void *data, void *userdata, char **ret);
int specifier_kernel_release(char specifier, void *data, void *userdata, char **ret);
+
+int specifier_user_name(char specifier, void *data, void *userdata, char **ret);
+int specifier_user_id(char specifier, void *data, void *userdata, char **ret);
+int specifier_user_home(char specifier, void *data, void *userdata, char **ret);
+int specifier_user_shell(char specifier, void *data, void *userdata, char **ret);
+
+static inline char* specifier_escape(const char *string) {
+ return strreplace(string, "%", "%%");
+}
+
+int specifier_escape_strv(char **l, char ***ret);
diff --git a/src/shared/switch-root.c b/src/shared/switch-root.c
index afdf1ab5ad..3c51fa36f3 100644
--- a/src/shared/switch-root.c
+++ b/src/shared/switch-root.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
diff --git a/src/shared/switch-root.h b/src/shared/switch-root.h
index a7a080b3e8..abcdc1c65f 100644
--- a/src/shared/switch-root.h
+++ b/src/shared/switch-root.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
#include <stdbool.h>
diff --git a/src/shared/sysctl-util.c b/src/shared/sysctl-util.c
index e1ccb3294c..189580e3ed 100644
--- a/src/shared/sysctl-util.c
+++ b/src/shared/sysctl-util.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -59,7 +60,7 @@ int sysctl_write(const char *property, const char *value) {
log_debug("Setting '%s' to '%s'", property, value);
p = strjoina("/proc/sys/", property);
- return write_string_file(p, value, 0);
+ return write_string_file(p, value, WRITE_STRING_FILE_DISABLE_BUFFER);
}
int sysctl_read(const char *property, char **content) {
diff --git a/src/shared/sysctl-util.h b/src/shared/sysctl-util.h
index 2decb39f58..446aa6f384 100644
--- a/src/shared/sysctl-util.h
+++ b/src/shared/sysctl-util.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/test-tables.h b/src/shared/test-tables.h
index 228e510104..6b223b1ee5 100644
--- a/src/shared/test-tables.h
+++ b/src/shared/test-tables.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd
diff --git a/src/shared/tests.c b/src/shared/tests.c
index f300bbc66f..d78ab7b069 100644
--- a/src/shared/tests.c
+++ b/src/shared/tests.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
diff --git a/src/shared/tests.h b/src/shared/tests.h
index 7055124990..b070f386e3 100644
--- a/src/shared/tests.h
+++ b/src/shared/tests.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/tomoyo-util.c b/src/shared/tomoyo-util.c
new file mode 100644
index 0000000000..390fff6152
--- /dev/null
+++ b/src/shared/tomoyo-util.c
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+/***
+ This file is part of systemd.
+
+ Copyright 2017 Shawn Landden
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <unistd.h>
+
+#include "tomoyo-util.h"
+
+bool mac_tomoyo_use(void) {
+ static int cached_use = -1;
+
+ if (cached_use < 0)
+ cached_use = (access("/sys/kernel/security/tomoyo/version",
+ F_OK) == 0);
+
+ return cached_use;
+}
diff --git a/src/shared/tomoyo-util.h b/src/shared/tomoyo-util.h
new file mode 100644
index 0000000000..4fb309fd54
--- /dev/null
+++ b/src/shared/tomoyo-util.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+/***
+ This file is part of systemd.
+
+ Copyright 2017 Shawn Landden
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdbool.h>
+
+bool mac_tomoyo_use(void);
diff --git a/src/shared/udev-util.c b/src/shared/udev-util.c
index f708dcfa14..65a09e9c2e 100644
--- a/src/shared/udev-util.c
+++ b/src/shared/udev-util.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
diff --git a/src/shared/udev-util.h b/src/shared/udev-util.h
index a415be249e..c5e4197dff 100644
--- a/src/shared/udev-util.h
+++ b/src/shared/udev-util.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/uid-range.c b/src/shared/uid-range.c
index b6ec474390..c38b7cc984 100644
--- a/src/shared/uid-range.c
+++ b/src/shared/uid-range.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
diff --git a/src/shared/uid-range.h b/src/shared/uid-range.h
index 4044eb4c9c..882f6624cd 100644
--- a/src/shared/uid-range.h
+++ b/src/shared/uid-range.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/utmp-wtmp.c b/src/shared/utmp-wtmp.c
index fc8548c5b3..1715c0fb24 100644
--- a/src/shared/utmp-wtmp.c
+++ b/src/shared/utmp-wtmp.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -424,7 +425,7 @@ int utmp_wall(
if (u->ut_type != USER_PROCESS || u->ut_user[0] == 0)
continue;
- /* this access is fine, because strlen("/dev/") << 32 (UT_LINESIZE) */
+ /* this access is fine, because STRLEN("/dev/") << 32 (UT_LINESIZE) */
if (path_startswith(u->ut_line, "/dev/"))
path = u->ut_line;
else {
diff --git a/src/shared/utmp-wtmp.h b/src/shared/utmp-wtmp.h
index 8f4fbcdeff..2c75d4097e 100644
--- a/src/shared/utmp-wtmp.h
+++ b/src/shared/utmp-wtmp.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/vlan-util.c b/src/shared/vlan-util.c
index 1edd96fbe7..fa270164bb 100644
--- a/src/shared/vlan-util.c
+++ b/src/shared/vlan-util.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
diff --git a/src/shared/vlan-util.h b/src/shared/vlan-util.h
index 365ed14d88..6d287fd32a 100644
--- a/src/shared/vlan-util.h
+++ b/src/shared/vlan-util.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/volatile-util.c b/src/shared/volatile-util.c
index e7e9721411..85512d00af 100644
--- a/src/shared/volatile-util.c
+++ b/src/shared/volatile-util.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
diff --git a/src/shared/volatile-util.h b/src/shared/volatile-util.h
index 17930ba6ae..3ad037af8b 100644
--- a/src/shared/volatile-util.h
+++ b/src/shared/volatile-util.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
diff --git a/src/shared/watchdog.c b/src/shared/watchdog.c
index 4f3e0125f3..b0a422da84 100644
--- a/src/shared/watchdog.c
+++ b/src/shared/watchdog.c
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
/***
This file is part of systemd.
@@ -26,10 +27,12 @@
#include "fd-util.h"
#include "log.h"
+#include "string-util.h"
#include "time-util.h"
#include "watchdog.h"
static int watchdog_fd = -1;
+static char *watchdog_device = NULL;
static usec_t watchdog_timeout = USEC_INFINITY;
static int update_timeout(void) {
@@ -83,7 +86,8 @@ static int open_watchdog(void) {
if (watchdog_fd >= 0)
return 0;
- watchdog_fd = open("/dev/watchdog", O_WRONLY|O_CLOEXEC);
+ watchdog_fd = open(watchdog_device ?: "/dev/watchdog",
+ O_WRONLY|O_CLOEXEC);
if (watchdog_fd < 0)
return -errno;
@@ -95,6 +99,10 @@ static int open_watchdog(void) {
return update_timeout();
}
+int watchdog_set_device(char *path) {
+ return free_and_strdup(&watchdog_device, path);
+}
+
int watchdog_set_timeout(usec_t *usec) {
int r;
diff --git a/src/shared/watchdog.h b/src/shared/watchdog.h
index f6ec178ea1..5694338db3 100644
--- a/src/shared/watchdog.h
+++ b/src/shared/watchdog.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
#pragma once
/***
@@ -24,6 +25,11 @@
#include "time-util.h"
#include "util.h"
+int watchdog_set_device(char *path);
int watchdog_set_timeout(usec_t *usec);
int watchdog_ping(void);
void watchdog_close(bool disarm);
+
+static inline void watchdog_free_device(void) {
+ (void) watchdog_set_device(NULL);
+}