Compare commits
13 Commits
c18cd302fd
...
546827f67c
Author | SHA1 | Date |
---|---|---|
Daan De Meyer | 546827f67c | |
Daan De Meyer | 81af8f998e | |
chenjiayi | 4fc8a63f9e | |
Jason Yundt | dfb3155419 | |
Daan De Meyer | fc5037e7d7 | |
Yu Watanabe | 13f6ec7ce7 | |
Yu Watanabe | 6e1816ef16 | |
Yu Watanabe | 7ac1ad90d0 | |
Yu Watanabe | d265b8afb7 | |
Yu Watanabe | 1aab0a5b10 | |
Daan De Meyer | 8c934d1c4a | |
Daan De Meyer | cce9bb7f25 | |
Daan De Meyer | e0c207b085 |
|
@ -593,8 +593,6 @@ node /org/freedesktop/systemd1 {
|
||||||
|
|
||||||
<!--method GetJobBefore is not documented!-->
|
<!--method GetJobBefore is not documented!-->
|
||||||
|
|
||||||
<!--method SetShowStatus is not documented!-->
|
|
||||||
|
|
||||||
<!--method ListUnitsFiltered is not documented!-->
|
<!--method ListUnitsFiltered is not documented!-->
|
||||||
|
|
||||||
<!--method ListUnitsByPatterns is not documented!-->
|
<!--method ListUnitsByPatterns is not documented!-->
|
||||||
|
@ -673,8 +671,6 @@ node /org/freedesktop/systemd1 {
|
||||||
|
|
||||||
<!--property ConfirmSpawn is not documented!-->
|
<!--property ConfirmSpawn is not documented!-->
|
||||||
|
|
||||||
<!--property ShowStatus is not documented!-->
|
|
||||||
|
|
||||||
<!--property DefaultStandardOutput is not documented!-->
|
<!--property DefaultStandardOutput is not documented!-->
|
||||||
|
|
||||||
<!--property DefaultStandardError is not documented!-->
|
<!--property DefaultStandardError is not documented!-->
|
||||||
|
@ -1362,6 +1358,24 @@ node /org/freedesktop/systemd1 {
|
||||||
|
|
||||||
<para><function>ResetFailedUnit()</function> resets the "failed" state of a specific unit.</para>
|
<para><function>ResetFailedUnit()</function> resets the "failed" state of a specific unit.</para>
|
||||||
|
|
||||||
|
<para><function>SetShowStatus()</function> configures the display of status messages during bootup and
|
||||||
|
shutdown. The <varname>mode</varname> parameter can be set to any value that's valid for the
|
||||||
|
<varname>systemd.show_status</varname> kernel parameter. For more information about
|
||||||
|
<varname>systemd.show_status</varname>, see
|
||||||
|
<citerefentry project="man-pages"><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>.
|
||||||
|
The <varname>mode</varname> parameter can also be set to an empty string. When <varname>mode</varname>
|
||||||
|
is set to an empty string, <function>SetShowStatus()</function> will reset
|
||||||
|
<varname>ShowStatus</varname> back to its original value. You can use
|
||||||
|
<function>SetShowStatus()</function> create a service that does something like this:
|
||||||
|
<orderedlist>
|
||||||
|
<listitem><para>Send a D-Bus message that will turn off status messages.</para></listitem>
|
||||||
|
<listitem><para>Block until a reply to that message is received.</para></listitem>
|
||||||
|
<listitem><para>Print multiples lines without being interrupted by status messages.</para></listitem>
|
||||||
|
<listitem><para>Send a D-Bus message that will reset <varname>ShowStatus</varname> back to its
|
||||||
|
original value.</para></listitem>
|
||||||
|
</orderedlist>
|
||||||
|
</para>
|
||||||
|
|
||||||
<para><function>ResetFailed()</function> resets the "failed" state of all units.</para>
|
<para><function>ResetFailed()</function> resets the "failed" state of all units.</para>
|
||||||
|
|
||||||
<para><function>ListUnits()</function> returns an array of all currently loaded units. Note that
|
<para><function>ListUnits()</function> returns an array of all currently loaded units. Note that
|
||||||
|
@ -1788,6 +1802,12 @@ node /org/freedesktop/systemd1 {
|
||||||
<para><varname>Environment</varname> encodes the environment block passed to all executed services. It
|
<para><varname>Environment</varname> encodes the environment block passed to all executed services. It
|
||||||
may be altered with bus calls such as <function>SetEnvironment()</function> (see above).</para>
|
may be altered with bus calls such as <function>SetEnvironment()</function> (see above).</para>
|
||||||
|
|
||||||
|
<para><varname>ShowStatus</varname> encodes systemd's current policy for displaying status messages
|
||||||
|
during bootup and shutdown. Its value can be any valid value for the
|
||||||
|
<varname>systemd.show_status</varname> kernel parameter (see
|
||||||
|
<citerefentry project="man-pages"><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>).
|
||||||
|
It may be altered using <function>SetShowStatus()</function> (see above).</para>
|
||||||
|
|
||||||
<para><varname>UnitPath</varname> encodes the currently active unit file search path. It is an array of
|
<para><varname>UnitPath</varname> encodes the currently active unit file search path. It is an array of
|
||||||
file system paths encoded as strings.</para>
|
file system paths encoded as strings.</para>
|
||||||
|
|
||||||
|
|
|
@ -483,18 +483,18 @@
|
||||||
<term><varname>ExcludeFiles=</varname></term>
|
<term><varname>ExcludeFiles=</varname></term>
|
||||||
<term><varname>ExcludeFilesTarget=</varname></term>
|
<term><varname>ExcludeFilesTarget=</varname></term>
|
||||||
|
|
||||||
<listitem><para>Takes an absolute file system path referring to a source file or directory on the
|
<listitem><para>Takes one or more absolute paths, separated by whitespace, each referring to a
|
||||||
host. This setting may be used to exclude files or directories from the host from being copied into
|
source file or directory on the host. This setting may be used to exclude files or directories from
|
||||||
the file system when <varname>CopyFiles=</varname> is used. This option may be used multiple times to
|
the host from being copied into the file system when <varname>CopyFiles=</varname> is used. This
|
||||||
exclude multiple files or directories from host from being copied into the newly formatted file
|
option may be used multiple times to exclude multiple files or directories from host from being
|
||||||
system.</para>
|
copied into the newly formatted file system.</para>
|
||||||
|
|
||||||
<para>If the path is a directory and ends with <literal>/</literal>, only the directory's
|
<para>If the path is a directory and ends with <literal>/</literal>, only the directory's
|
||||||
contents are excluded but not the directory itself. If the path is a directory and does not end with
|
contents are excluded but not the directory itself. If the path is a directory and does not end with
|
||||||
<literal>/</literal>, both the directory and its contents are excluded.</para>
|
<literal>/</literal>, both the directory and its contents are excluded.</para>
|
||||||
|
|
||||||
<para><varname>ExcludeFilesTarget=</varname> is like <varname>ExcludeFiles=</varname> except that
|
<para><varname>ExcludeFilesTarget=</varname> is like <varname>ExcludeFiles=</varname> except that
|
||||||
instead of excluding the path on the host from being copied into the partition, we exclude any files
|
instead of excluding the path on the host from being copied into the partition, it exclude any files
|
||||||
and directories from being copied into the given path in the partition.</para>
|
and directories from being copied into the given path in the partition.</para>
|
||||||
|
|
||||||
<para>When
|
<para>When
|
||||||
|
|
|
@ -3001,7 +3001,12 @@ SystemCallErrorNumber=EPERM</programlisting>
|
||||||
|
|
||||||
<para><option>tty</option> connects standard output to a tty (as configured via <varname>TTYPath=</varname>,
|
<para><option>tty</option> connects standard output to a tty (as configured via <varname>TTYPath=</varname>,
|
||||||
see below). If the TTY is used for output only, the executed process will not become the controlling process of
|
see below). If the TTY is used for output only, the executed process will not become the controlling process of
|
||||||
the terminal, and will not fail or wait for other processes to release the terminal.</para>
|
the terminal, and will not fail or wait for other processes to release the terminal. Note: if a unit
|
||||||
|
tries to print multiple lines to a TTY during bootup or shutdown, then there's a chance that those
|
||||||
|
lines will be broken up by status messages. <function>SetShowStatus()</function> can be used to
|
||||||
|
prevent this problem. See
|
||||||
|
<citerefentry project="man-pages"><refentrytitle>org.freedesktop.systemd1</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||||
|
for details.</para>
|
||||||
|
|
||||||
<para><option>journal</option> connects standard output with the journal, which is accessible via
|
<para><option>journal</option> connects standard output with the journal, which is accessible via
|
||||||
<citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>. Note
|
<citerefentry><refentrytitle>journalctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>. Note
|
||||||
|
|
|
@ -568,7 +568,11 @@
|
||||||
<listitem><para>Enables display of status messages on the
|
<listitem><para>Enables display of status messages on the
|
||||||
console, as controlled via
|
console, as controlled via
|
||||||
<varname>systemd.show_status=1</varname> on the kernel command
|
<varname>systemd.show_status=1</varname> on the kernel command
|
||||||
line.</para></listitem>
|
line.</para>
|
||||||
|
<para>You may want to use <function>SetShowStatus()</function> instead of
|
||||||
|
<constant>SIGRTMIN+20</constant> in order to prevent race conditions. See
|
||||||
|
<citerefentry project="man-pages"><refentrytitle>org.freedesktop.systemd1</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
|
||||||
|
</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
|
@ -579,7 +583,11 @@
|
||||||
controlled via
|
controlled via
|
||||||
<varname>systemd.show_status=0</varname>
|
<varname>systemd.show_status=0</varname>
|
||||||
on the kernel command
|
on the kernel command
|
||||||
line.</para></listitem>
|
line.</para>
|
||||||
|
<para>You may want to use <function>SetShowStatus()</function> instead of
|
||||||
|
<constant>SIGRTMIN+21</constant> in order to prevent race conditions. See
|
||||||
|
<citerefentry project="man-pages"><refentrytitle>org.freedesktop.systemd1</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
|
||||||
|
</para></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
|
|
|
@ -4169,7 +4169,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
|
||||||
* detect when the cgroup becomes empty. Note that the control process is always
|
* detect when the cgroup becomes empty. Note that the control process is always
|
||||||
* our child so it's pointless to watch all other processes. */
|
* our child so it's pointless to watch all other processes. */
|
||||||
if (!control_pid_good(s))
|
if (!control_pid_good(s))
|
||||||
if (!s->main_pid_known || s->main_pid_alien)
|
if (!s->main_pid_known || s->main_pid_alien || unit_cgroup_delegate(u))
|
||||||
(void) unit_enqueue_rewatch_pids(u);
|
(void) unit_enqueue_rewatch_pids(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -404,15 +404,16 @@ static int context_set_path_strv(Context *c, char* const* strv, const char *sour
|
||||||
|
|
||||||
static int context_set_plugins(Context *c, const char *s, const char *source) {
|
static int context_set_plugins(Context *c, const char *s, const char *source) {
|
||||||
_cleanup_strv_free_ char **v = NULL;
|
_cleanup_strv_free_ char **v = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
assert(c);
|
assert(c);
|
||||||
|
|
||||||
if (c->plugins || !s)
|
if (c->plugins || !s)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
v = strv_split(s, NULL);
|
r = strv_split_full(&v, s, NULL, EXTRACT_UNQUOTE);
|
||||||
if (!v)
|
if (r < 0)
|
||||||
return log_oom();
|
return log_error_errno(r, "Failed to parse plugin paths from %s: %m", source);
|
||||||
|
|
||||||
return context_set_path_strv(c, v, source, "plugins", &c->plugins);
|
return context_set_path_strv(c, v, source, "plugins", &c->plugins);
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,7 +46,13 @@ echo 'DTBDTBDTBDTB' >"$D/sources/subdir/whatever.dtb"
|
||||||
|
|
||||||
export KERNEL_INSTALL_CONF_ROOT="$D/sources"
|
export KERNEL_INSTALL_CONF_ROOT="$D/sources"
|
||||||
# We "install" multiple plugins, but control which ones will be active via install.conf.
|
# We "install" multiple plugins, but control which ones will be active via install.conf.
|
||||||
export KERNEL_INSTALL_PLUGINS="${ukify_install} ${loaderentry_install} ${uki_copy_install}"
|
KERNEL_INSTALL_PLUGINS="'${loaderentry_install}' '${uki_copy_install}'"
|
||||||
|
if [[ -n "$ukify_install" ]]; then
|
||||||
|
# shellcheck disable=SC2089
|
||||||
|
KERNEL_INSTALL_PLUGINS="'${ukify_install}' $KERNEL_INSTALL_PLUGINS"
|
||||||
|
fi
|
||||||
|
# shellcheck disable=SC2090
|
||||||
|
export KERNEL_INSTALL_PLUGINS
|
||||||
export BOOT_ROOT="$D/boot"
|
export BOOT_ROOT="$D/boot"
|
||||||
export BOOT_MNT="$D/boot"
|
export BOOT_MNT="$D/boot"
|
||||||
export MACHINE_ID='3e0484f3634a418b8e6a39e8828b03e3'
|
export MACHINE_ID='3e0484f3634a418b8e6a39e8828b03e3'
|
||||||
|
|
|
@ -1742,8 +1742,9 @@ static int config_parse_exclude_files(
|
||||||
const char *rvalue,
|
const char *rvalue,
|
||||||
void *data,
|
void *data,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
_cleanup_free_ char *resolved = NULL;
|
|
||||||
char ***exclude_files = ASSERT_PTR(data);
|
char ***exclude_files = ASSERT_PTR(data);
|
||||||
|
const char *p = ASSERT_PTR(rvalue);
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (isempty(rvalue)) {
|
if (isempty(rvalue)) {
|
||||||
|
@ -1751,20 +1752,34 @@ static int config_parse_exclude_files(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = specifier_printf(rvalue, PATH_MAX-1, system_and_tmp_specifier_table, arg_root, NULL, &resolved);
|
for (;;) {
|
||||||
if (r < 0) {
|
_cleanup_free_ char *word = NULL, *resolved = NULL;
|
||||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
|
||||||
"Failed to expand specifiers in ExcludeFiles= path, ignoring: %s", rvalue);
|
r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
|
||||||
return 0;
|
if (r == -ENOMEM)
|
||||||
|
return log_oom();
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_WARNING, filename, line, r, "Invalid syntax, ignoring: %s", p);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (r == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
r = specifier_printf(word, PATH_MAX-1, system_and_tmp_specifier_table, arg_root, NULL, &resolved);
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||||
|
"Failed to expand specifiers in %s path, ignoring: %s", lvalue, word);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE|PATH_KEEP_TRAILING_SLASH, unit, filename, line, lvalue);
|
||||||
|
if (r < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (strv_consume(exclude_files, TAKE_PTR(resolved)) < 0)
|
||||||
|
return log_oom();
|
||||||
}
|
}
|
||||||
|
|
||||||
r = path_simplify_and_warn(resolved, PATH_CHECK_ABSOLUTE|PATH_KEEP_TRAILING_SLASH, unit, filename, line, lvalue);
|
|
||||||
if (r < 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (strv_consume(exclude_files, TAKE_PTR(resolved)) < 0)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1462,11 +1462,6 @@ int remount_idmap(
|
||||||
return remount_idmap_fd(p, userns_fd);
|
return remount_idmap_fd(p, userns_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct SubMount {
|
|
||||||
char *path;
|
|
||||||
int mount_fd;
|
|
||||||
} SubMount;
|
|
||||||
|
|
||||||
static void sub_mount_clear(SubMount *s) {
|
static void sub_mount_clear(SubMount *s) {
|
||||||
assert(s);
|
assert(s);
|
||||||
|
|
||||||
|
@ -1474,7 +1469,7 @@ static void sub_mount_clear(SubMount *s) {
|
||||||
s->mount_fd = safe_close(s->mount_fd);
|
s->mount_fd = safe_close(s->mount_fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sub_mount_array_free(SubMount *s, size_t n) {
|
void sub_mount_array_free(SubMount *s, size_t n) {
|
||||||
assert(s || n == 0);
|
assert(s || n == 0);
|
||||||
|
|
||||||
for (size_t i = 0; i < n; i++)
|
for (size_t i = 0; i < n; i++)
|
||||||
|
@ -1503,10 +1498,7 @@ static void sub_mount_drop(SubMount *s, size_t n) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_sub_mounts(
|
int get_sub_mounts(const char *prefix, SubMount **ret_mounts, size_t *ret_n_mounts) {
|
||||||
const char *prefix,
|
|
||||||
SubMount **ret_mounts,
|
|
||||||
size_t *ret_n_mounts) {
|
|
||||||
|
|
||||||
_cleanup_(mnt_free_tablep) struct libmnt_table *table = NULL;
|
_cleanup_(mnt_free_tablep) struct libmnt_table *table = NULL;
|
||||||
_cleanup_(mnt_free_iterp) struct libmnt_iter *iter = NULL;
|
_cleanup_(mnt_free_iterp) struct libmnt_iter *iter = NULL;
|
||||||
|
|
|
@ -12,6 +12,15 @@
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
#include "pidref.h"
|
#include "pidref.h"
|
||||||
|
|
||||||
|
typedef struct SubMount {
|
||||||
|
char *path;
|
||||||
|
int mount_fd;
|
||||||
|
} SubMount;
|
||||||
|
|
||||||
|
void sub_mount_array_free(SubMount *s, size_t n);
|
||||||
|
|
||||||
|
int get_sub_mounts(const char *prefix, SubMount **ret_mounts, size_t *ret_n_mounts);
|
||||||
|
|
||||||
int repeat_unmount(const char *path, int flags);
|
int repeat_unmount(const char *path, int flags);
|
||||||
|
|
||||||
int umount_recursive_full(const char *target, int flags, char **keep);
|
int umount_recursive_full(const char *target, int flags, char **keep);
|
||||||
|
|
|
@ -273,6 +273,106 @@ static int need_reload(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int move_submounts(const char *src, const char *dst, const char *stack) {
|
||||||
|
SubMount *submounts = NULL;
|
||||||
|
size_t n_submounts = 0;
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
assert(src);
|
||||||
|
assert(dst);
|
||||||
|
assert(stack);
|
||||||
|
|
||||||
|
CLEANUP_ARRAY(submounts, n_submounts, sub_mount_array_free);
|
||||||
|
|
||||||
|
r = get_sub_mounts(src, &submounts, &n_submounts);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to get submounts for %s: %m", src);
|
||||||
|
|
||||||
|
if (n_submounts == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
_cleanup_free_ char *dir_stack = path_join(stack, "dir");
|
||||||
|
if (!dir_stack)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
r = mkdir_p(dir_stack, 0700);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to create directory %s: %m", dir_stack);
|
||||||
|
|
||||||
|
_cleanup_free_ char *file_stack = path_join(stack, "file");
|
||||||
|
if (!file_stack)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
r = mkdir_parents(file_stack, 0700);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to create parent directories of %s: %m", file_stack);
|
||||||
|
|
||||||
|
r = touch(file_stack);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to create %s: %m", file_stack);
|
||||||
|
|
||||||
|
FOREACH_ARRAY(m, submounts, n_submounts) {
|
||||||
|
_cleanup_free_ char *t = NULL;
|
||||||
|
const char *suffix;
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
assert_se(suffix = path_startswith(m->path, src));
|
||||||
|
|
||||||
|
t = path_join(dst, suffix);
|
||||||
|
if (!t)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
if (fstat(m->mount_fd, &st) < 0)
|
||||||
|
return log_error_errno(errno, "Failed to stat %s: %m", m->path);
|
||||||
|
|
||||||
|
r = mkdir_parents(t, 0755);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to create parent directories of %s: %m", t);
|
||||||
|
|
||||||
|
if (S_ISDIR(st.st_mode)) {
|
||||||
|
if (mkdir(t, 0755) < 0 && errno != EEXIST)
|
||||||
|
return log_error_errno(errno, "Failed to create directory %s: %m", t);
|
||||||
|
} else {
|
||||||
|
r = touch(t);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to create file %s: %m", t);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Some submounts might be a stack of multiple mounts on top of the same path. We have to
|
||||||
|
* make sure we move all of them to the destination. Since the kernel does not provide us
|
||||||
|
* with an interface to move a stack mounts, we do it manually by popping the stack one by
|
||||||
|
* one onto a temporary location (where we'll get the stack in reverse order), before popping
|
||||||
|
* it again one by one to the desired location (which will be in the original order again).
|
||||||
|
* Because we don't know upfront whether a mount will be stacked or not, we don't try to
|
||||||
|
* optimize this for non-stacked mounts.
|
||||||
|
*/
|
||||||
|
|
||||||
|
stack = S_ISDIR(st.st_mode) ? dir_stack : file_stack;
|
||||||
|
|
||||||
|
while (path_is_mount_point(m->path)) {
|
||||||
|
r = mount_follow_verbose(LOG_DEBUG, m->path, stack, NULL, MS_BIND|MS_REC, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to mount %s to %s: %m", m->path, stack);
|
||||||
|
|
||||||
|
r = umount_verbose(LOG_DEBUG, m->path, MNT_DETACH);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to unmount %s", m->path);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (path_is_mount_point(stack)) {
|
||||||
|
r = mount_follow_verbose(LOG_DEBUG, stack, t, NULL, MS_BIND|MS_REC, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to mount %s to %s: %m", stack, t);
|
||||||
|
|
||||||
|
r = umount_verbose(LOG_DEBUG, stack, MNT_DETACH);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to unmount %s", stack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
static int daemon_reload(void) {
|
static int daemon_reload(void) {
|
||||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||||
int r;
|
int r;
|
||||||
|
@ -286,9 +386,12 @@ static int daemon_reload(void) {
|
||||||
|
|
||||||
static int unmerge_hierarchy(
|
static int unmerge_hierarchy(
|
||||||
ImageClass image_class,
|
ImageClass image_class,
|
||||||
const char *p) {
|
const char *p,
|
||||||
|
const char *submounts_path,
|
||||||
|
const char *stack_path) {
|
||||||
|
|
||||||
_cleanup_free_ char *dot_dir = NULL, *work_dir_info_file = NULL;
|
_cleanup_free_ char *dot_dir = NULL, *work_dir_info_file = NULL;
|
||||||
|
int n_unmerged = 0;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(p);
|
assert(p);
|
||||||
|
@ -338,6 +441,12 @@ static int unmerge_hierarchy(
|
||||||
return log_error_errno(r, "Failed to unmount '%s': %m", dot_dir);
|
return log_error_errno(r, "Failed to unmount '%s': %m", dot_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* After we've unmounted the metadata directory, save all other submounts so we can restore
|
||||||
|
* them after unmerging the hierarchy. */
|
||||||
|
r = move_submounts(p, submounts_path, stack_path);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
r = umount_verbose(LOG_ERR, p, MNT_DETACH|UMOUNT_NOFOLLOW);
|
r = umount_verbose(LOG_ERR, p, MNT_DETACH|UMOUNT_NOFOLLOW);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
@ -349,9 +458,68 @@ static int unmerge_hierarchy(
|
||||||
}
|
}
|
||||||
|
|
||||||
log_info("Unmerged '%s'.", p);
|
log_info("Unmerged '%s'.", p);
|
||||||
|
n_unmerged++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return n_unmerged;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int unmerge_subprocess(
|
||||||
|
ImageClass image_class,
|
||||||
|
char **hierarchies,
|
||||||
|
const char *workspace) {
|
||||||
|
|
||||||
|
int r, ret = 0;
|
||||||
|
|
||||||
|
/* Mark the whole of /run as MS_SLAVE, so that we can mount stuff below it that doesn't show up on
|
||||||
|
* the host otherwise. */
|
||||||
|
r = mount_nofollow_verbose(LOG_ERR, NULL, "/run", NULL, MS_SLAVE|MS_REC, NULL);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to remount /run/ MS_SLAVE: %m");
|
||||||
|
|
||||||
|
/* Let's create the workspace if it's missing */
|
||||||
|
r = mkdir_p(workspace, 0700);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to create '%s': %m", workspace);
|
||||||
|
|
||||||
|
_cleanup_free_ char *stack_path = path_join(workspace, "submounts/stack");
|
||||||
|
if (!stack_path)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
STRV_FOREACH(h, hierarchies) {
|
||||||
|
_cleanup_free_ char *submounts_path = NULL, *resolved = NULL;
|
||||||
|
|
||||||
|
submounts_path = path_join(workspace, "submounts", *h);
|
||||||
|
if (!submounts_path)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
r = chase(*h, arg_root, CHASE_PREFIX_ROOT, &resolved, NULL);
|
||||||
|
if (r == -ENOENT) {
|
||||||
|
log_debug_errno(r, "Hierarchy '%s%s' does not exist, ignoring.", strempty(arg_root), *h);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (r < 0) {
|
||||||
|
RET_GATHER(ret, log_error_errno(r, "Failed to resolve path to hierarchy '%s%s': %m", strempty(arg_root), *h));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = unmerge_hierarchy(image_class, resolved, submounts_path, stack_path);
|
||||||
|
if (r < 0) {
|
||||||
|
RET_GATHER(ret, r);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (r == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* If we unmerged something, then we have to move the submounts from the hierarchy back into
|
||||||
|
* place in the host's original hierarchy. */
|
||||||
|
|
||||||
|
r = move_submounts(submounts_path, resolved, stack_path);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int unmerge(
|
static int unmerge(
|
||||||
|
@ -359,42 +527,42 @@ static int unmerge(
|
||||||
char **hierarchies,
|
char **hierarchies,
|
||||||
bool no_reload) {
|
bool no_reload) {
|
||||||
|
|
||||||
int r, ret = 0;
|
|
||||||
bool need_to_reload;
|
bool need_to_reload;
|
||||||
|
pid_t pid;
|
||||||
|
int r;
|
||||||
|
|
||||||
r = need_reload(image_class, hierarchies, no_reload);
|
r = need_reload(image_class, hierarchies, no_reload);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
need_to_reload = r > 0;
|
need_to_reload = r > 0;
|
||||||
|
|
||||||
STRV_FOREACH(p, hierarchies) {
|
r = safe_fork("(sd-unmerge)", FORK_DEATHSIG_SIGTERM|FORK_LOG|FORK_NEW_MOUNTNS, &pid);
|
||||||
_cleanup_free_ char *resolved = NULL;
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to fork off child: %m");
|
||||||
|
if (r == 0) {
|
||||||
|
/* Child with its own mount namespace */
|
||||||
|
|
||||||
r = chase(*p, arg_root, CHASE_PREFIX_ROOT, &resolved, NULL);
|
r = unmerge_subprocess(image_class, hierarchies, "/run/systemd/sysext");
|
||||||
if (r == -ENOENT) {
|
|
||||||
log_debug_errno(r, "Hierarchy '%s%s' does not exist, ignoring.", strempty(arg_root), *p);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (r < 0) {
|
|
||||||
log_error_errno(r, "Failed to resolve path to hierarchy '%s%s': %m", strempty(arg_root), *p);
|
|
||||||
if (ret == 0)
|
|
||||||
ret = r;
|
|
||||||
|
|
||||||
continue;
|
/* Our namespace ceases to exist here, also implicitly detaching all temporary mounts we
|
||||||
}
|
* created below /run. Nice! */
|
||||||
|
|
||||||
r = unmerge_hierarchy(image_class, resolved);
|
_exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS);
|
||||||
if (r < 0 && ret == 0)
|
|
||||||
ret = r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
r = wait_for_terminate_and_check("(sd-unmerge)", pid, WAIT_LOG_ABNORMAL);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r > 0)
|
||||||
|
return log_error_errno(SYNTHETIC_ERRNO(EPROTO), "Failed to unmerge hierarchies");
|
||||||
|
|
||||||
if (need_to_reload) {
|
if (need_to_reload) {
|
||||||
r = daemon_reload();
|
r = daemon_reload();
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int verb_unmerge(int argc, char **argv, void *userdata) {
|
static int verb_unmerge(int argc, char **argv, void *userdata) {
|
||||||
|
@ -1708,23 +1876,43 @@ static int merge_subprocess(
|
||||||
paths[k] = TAKE_PTR(p);
|
paths[k] = TAKE_PTR(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set up a directory where we can unstack stack mounts. This is required to move around stacked
|
||||||
|
* mounts from one path to another as we cannot move the entire stack at once so we have to pop it
|
||||||
|
* one mount at a time to a temporary location before restacking it in the desired location. */
|
||||||
|
_cleanup_free_ char *stack_path = path_join(workspace, "submounts/stack");
|
||||||
|
if (!stack_path)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
/* Let's now unmerge the status quo ante, since to build the new overlayfs we need a reference to the
|
/* Let's now unmerge the status quo ante, since to build the new overlayfs we need a reference to the
|
||||||
* underlying fs. */
|
* underlying fs. */
|
||||||
STRV_FOREACH(h, hierarchies) {
|
STRV_FOREACH(h, hierarchies) {
|
||||||
_cleanup_free_ char *resolved = NULL;
|
_cleanup_free_ char *submounts_path = NULL, *resolved = NULL;
|
||||||
|
|
||||||
|
submounts_path = path_join(workspace, "submounts", *h);
|
||||||
|
if (!submounts_path)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
r = chase(*h, arg_root, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &resolved, NULL);
|
r = chase(*h, arg_root, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &resolved, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to resolve hierarchy '%s%s': %m", strempty(arg_root), *h);
|
return log_error_errno(r, "Failed to resolve hierarchy '%s%s': %m", strempty(arg_root), *h);
|
||||||
|
|
||||||
r = unmerge_hierarchy(image_class, resolved);
|
r = unmerge_hierarchy(image_class, resolved, submounts_path, stack_path);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r > 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* If we didn't unmerge anything, then we have to move the submounts from the host's
|
||||||
|
* original hierarchy. */
|
||||||
|
|
||||||
|
r = move_submounts(resolved, submounts_path, stack_path);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create overlayfs mounts for all hierarchies */
|
/* Create overlayfs mounts for all hierarchies */
|
||||||
STRV_FOREACH(h, hierarchies) {
|
STRV_FOREACH(h, hierarchies) {
|
||||||
_cleanup_free_ char *meta_path = NULL, *overlay_path = NULL, *merge_hierarchy_workspace = NULL;
|
_cleanup_free_ char *meta_path = NULL, *overlay_path = NULL, *merge_hierarchy_workspace = NULL, *submounts_path = NULL;
|
||||||
|
|
||||||
meta_path = path_join(workspace, "meta", *h); /* The place where to store metadata about this instance */
|
meta_path = path_join(workspace, "meta", *h); /* The place where to store metadata about this instance */
|
||||||
if (!meta_path)
|
if (!meta_path)
|
||||||
|
@ -1739,6 +1927,10 @@ static int merge_subprocess(
|
||||||
if (!merge_hierarchy_workspace)
|
if (!merge_hierarchy_workspace)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
|
submounts_path = path_join(workspace, "submounts", *h);
|
||||||
|
if (!submounts_path)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
r = merge_hierarchy(
|
r = merge_hierarchy(
|
||||||
image_class,
|
image_class,
|
||||||
*h,
|
*h,
|
||||||
|
@ -1750,6 +1942,13 @@ static int merge_subprocess(
|
||||||
merge_hierarchy_workspace);
|
merge_hierarchy_workspace);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
|
/* After the new hierarchy is set up, move the submounts from the original hierarchy into
|
||||||
|
* place. */
|
||||||
|
|
||||||
|
r = move_submounts(submounts_path, overlay_path, stack_path);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* And move them all into place. This is where things appear in the host namespace */
|
/* And move them all into place. This is where things appear in the host namespace */
|
||||||
|
|
|
@ -197,7 +197,7 @@ _unused_ static void test_compress_stream(const char *compression,
|
||||||
ASSERT_OK(compress(src, dst, -1, &uncompressed_size));
|
ASSERT_OK(compress(src, dst, -1, &uncompressed_size));
|
||||||
|
|
||||||
if (cat) {
|
if (cat) {
|
||||||
assert_se(asprintf(&cmd, "%s %s | diff %s -", cat, pattern, srcfile) > 0);
|
assert_se(asprintf(&cmd, "%s %s | diff '%s' -", cat, pattern, srcfile) > 0);
|
||||||
assert_se(system(cmd) == 0);
|
assert_se(system(cmd) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +212,7 @@ _unused_ static void test_compress_stream(const char *compression,
|
||||||
r = decompress(dst, dst2, st.st_size);
|
r = decompress(dst, dst2, st.st_size);
|
||||||
assert_se(r == 0);
|
assert_se(r == 0);
|
||||||
|
|
||||||
assert_se(asprintf(&cmd2, "diff %s %s", srcfile, pattern2) > 0);
|
assert_se(asprintf(&cmd2, "diff '%s' %s", srcfile, pattern2) > 0);
|
||||||
assert_se(system(cmd2) == 0);
|
assert_se(system(cmd2) == 0);
|
||||||
|
|
||||||
log_debug("/* test faulty decompression */");
|
log_debug("/* test faulty decompression */");
|
||||||
|
|
|
@ -52,7 +52,8 @@ static void test_event_spawn_self(const char *self, const char *arg, bool with_p
|
||||||
|
|
||||||
log_debug("/* %s(%s, %s) */", __func__, arg, yes_no(with_pidfd));
|
log_debug("/* %s(%s, %s) */", __func__, arg, yes_no(with_pidfd));
|
||||||
|
|
||||||
assert_se(cmd = strjoin(self, " ", arg));
|
/* 'self' may contain spaces, hence needs to be quoted. */
|
||||||
|
assert_se(cmd = strjoin("'", self, "' ", arg));
|
||||||
|
|
||||||
test_event_spawn_core(with_pidfd, cmd, result_buf, BUF_SIZE);
|
test_event_spawn_core(with_pidfd, cmd, result_buf, BUF_SIZE);
|
||||||
|
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
|
||||||
set -e
|
|
||||||
|
|
||||||
TEST_DESCRIPTION="Test Multi-Profile UKI Boots"
|
|
||||||
|
|
||||||
# shellcheck source=test/test-functions
|
|
||||||
. "${TEST_BASE_DIR:?}/test-functions"
|
|
||||||
|
|
||||||
do_test "$@"
|
|
|
@ -4,32 +4,32 @@ set -e
|
||||||
|
|
||||||
ANALYZE="${1:-systemd-analyze}"
|
ANALYZE="${1:-systemd-analyze}"
|
||||||
|
|
||||||
$ANALYZE compare-versions 1 lt 2
|
"$ANALYZE" compare-versions 1 lt 2
|
||||||
$ANALYZE compare-versions 1 '<' 2
|
"$ANALYZE" compare-versions 1 '<' 2
|
||||||
$ANALYZE compare-versions 1 le 2
|
"$ANALYZE" compare-versions 1 le 2
|
||||||
$ANALYZE compare-versions 1 '<=' 2
|
"$ANALYZE" compare-versions 1 '<=' 2
|
||||||
$ANALYZE compare-versions 1 ne 2
|
"$ANALYZE" compare-versions 1 ne 2
|
||||||
$ANALYZE compare-versions 1 '!=' 2
|
"$ANALYZE" compare-versions 1 '!=' 2
|
||||||
( ! $ANALYZE compare-versions 1 ge 2 )
|
( ! "$ANALYZE" compare-versions 1 ge 2 )
|
||||||
( ! $ANALYZE compare-versions 1 '>=' 2 )
|
( ! "$ANALYZE" compare-versions 1 '>=' 2 )
|
||||||
( ! $ANALYZE compare-versions 1 eq 2 )
|
( ! "$ANALYZE" compare-versions 1 eq 2 )
|
||||||
( ! $ANALYZE compare-versions 1 '==' 2 )
|
( ! "$ANALYZE" compare-versions 1 '==' 2 )
|
||||||
( ! $ANALYZE compare-versions 1 gt 2 )
|
( ! "$ANALYZE" compare-versions 1 gt 2 )
|
||||||
( ! $ANALYZE compare-versions 1 '>' 2 )
|
( ! "$ANALYZE" compare-versions 1 '>' 2 )
|
||||||
|
|
||||||
test "$($ANALYZE compare-versions 1 2)" = '1 < 2'
|
test "$("$ANALYZE" compare-versions 1 2)" = '1 < 2'
|
||||||
test "$($ANALYZE compare-versions 2 2)" = '2 == 2'
|
test "$("$ANALYZE" compare-versions 2 2)" = '2 == 2'
|
||||||
test "$($ANALYZE compare-versions 2 1)" = '2 > 1'
|
test "$("$ANALYZE" compare-versions 2 1)" = '2 > 1'
|
||||||
test "$($ANALYZE compare-versions '' '')" = "'' == ''"
|
test "$("$ANALYZE" compare-versions '' '')" = "'' == ''"
|
||||||
|
|
||||||
set +e
|
set +e
|
||||||
|
|
||||||
$ANALYZE compare-versions 1 2; ret1=$?
|
"$ANALYZE" compare-versions 1 2; ret1=$?
|
||||||
$ANALYZE compare-versions 2 2; ret2=$?
|
"$ANALYZE" compare-versions 2 2; ret2=$?
|
||||||
$ANALYZE compare-versions 2 1; ret3=$?
|
"$ANALYZE" compare-versions 2 1; ret3=$?
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
test $ret1 == 12
|
test "$ret1" == 12
|
||||||
test $ret2 == 0
|
test "$ret2" == 0
|
||||||
test $ret3 == 11
|
test "$ret3" == 11
|
||||||
|
|
|
@ -44,9 +44,9 @@ test_one() (
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [[ "${input##*/}" =~ \.fstab\.input ]]; then
|
if [[ "${input##*/}" =~ \.fstab\.input ]]; then
|
||||||
SYSTEMD_LOG_LEVEL=debug SYSTEMD_IN_INITRD="$initrd" SYSTEMD_SYSFS_CHECK=no SYSTEMD_PROC_CMDLINE="fstab=yes root=fstab" SYSTEMD_FSTAB="$input" SYSTEMD_SYSROOT_FSTAB="/dev/null" $generator "$out" "$out" "$out"
|
SYSTEMD_LOG_LEVEL=debug SYSTEMD_IN_INITRD="$initrd" SYSTEMD_SYSFS_CHECK=no SYSTEMD_PROC_CMDLINE="fstab=yes root=fstab" SYSTEMD_FSTAB="$input" SYSTEMD_SYSROOT_FSTAB="/dev/null" "$generator" "$out" "$out" "$out"
|
||||||
else
|
else
|
||||||
SYSTEMD_LOG_LEVEL=debug SYSTEMD_IN_INITRD="$initrd" SYSTEMD_SYSFS_CHECK=no SYSTEMD_PROC_CMDLINE="fstab=no $(cat "$input")" $generator "$out" "$out" "$out"
|
SYSTEMD_LOG_LEVEL=debug SYSTEMD_IN_INITRD="$initrd" SYSTEMD_SYSFS_CHECK=no SYSTEMD_PROC_CMDLINE="fstab=no $(cat "$input")" "$generator" "$out" "$out" "$out"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# The option x-systemd.growfs creates symlink to system's systemd-growfs@.service in .mount.wants directory.
|
# The option x-systemd.growfs creates symlink to system's systemd-growfs@.service in .mount.wants directory.
|
||||||
|
|
|
@ -53,7 +53,7 @@ for f in $(find "$SOURCE"/test-*.input | sort -V); do
|
||||||
echo "*** Running $f"
|
echo "*** Running $f"
|
||||||
prepare_testdir "${f%.input}"
|
prepare_testdir "${f%.input}"
|
||||||
cp "$f" "$TESTDIR/usr/lib/sysusers.d/test.conf"
|
cp "$f" "$TESTDIR/usr/lib/sysusers.d/test.conf"
|
||||||
$SYSUSERS --root="$TESTDIR"
|
"$SYSUSERS" --root="$TESTDIR"
|
||||||
|
|
||||||
compare "${f%.*}" ""
|
compare "${f%.*}" ""
|
||||||
done
|
done
|
||||||
|
@ -62,7 +62,7 @@ for f in $(find "$SOURCE"/test-*.input | sort -V); do
|
||||||
echo "*** Running $f on stdin"
|
echo "*** Running $f on stdin"
|
||||||
prepare_testdir "${f%.input}"
|
prepare_testdir "${f%.input}"
|
||||||
touch "$TESTDIR/etc/sysusers.d/test.conf"
|
touch "$TESTDIR/etc/sysusers.d/test.conf"
|
||||||
$SYSUSERS --root="$TESTDIR" - <"$f"
|
"$SYSUSERS" --root="$TESTDIR" - <"$f"
|
||||||
|
|
||||||
compare "${f%.*}" "on stdin"
|
compare "${f%.*}" "on stdin"
|
||||||
done
|
done
|
||||||
|
@ -72,9 +72,9 @@ for f in $(find "$SOURCE"/test-*.input | sort -V); do
|
||||||
prepare_testdir "${f%.input}"
|
prepare_testdir "${f%.input}"
|
||||||
touch "$TESTDIR/etc/sysusers.d/test.conf"
|
touch "$TESTDIR/etc/sysusers.d/test.conf"
|
||||||
# this overrides test.conf which is masked on disk
|
# this overrides test.conf which is masked on disk
|
||||||
$SYSUSERS --root="$TESTDIR" --replace=/etc/sysusers.d/test.conf - <"$f"
|
"$SYSUSERS" --root="$TESTDIR" --replace=/etc/sysusers.d/test.conf - <"$f"
|
||||||
# this should be ignored
|
# this should be ignored
|
||||||
$SYSUSERS --root="$TESTDIR" --replace=/usr/lib/sysusers.d/test.conf - <"$SOURCE/test-1.input"
|
"$SYSUSERS" --root="$TESTDIR" --replace=/usr/lib/sysusers.d/test.conf - <"$SOURCE/test-1.input"
|
||||||
|
|
||||||
compare "${f%.*}" "on stdin with --replace"
|
compare "${f%.*}" "on stdin with --replace"
|
||||||
done
|
done
|
||||||
|
@ -84,9 +84,9 @@ echo "*** Testing --inline"
|
||||||
prepare_testdir "$SOURCE/inline"
|
prepare_testdir "$SOURCE/inline"
|
||||||
# copy a random file to make sure it is ignored
|
# copy a random file to make sure it is ignored
|
||||||
cp "$f" "$TESTDIR/etc/sysusers.d/confuse.conf"
|
cp "$f" "$TESTDIR/etc/sysusers.d/confuse.conf"
|
||||||
$SYSUSERS --root="$TESTDIR" --inline \
|
"$SYSUSERS" --root="$TESTDIR" --inline \
|
||||||
"u u1 222 - - /bin/zsh" \
|
"u u1 222 - - /bin/zsh" \
|
||||||
"g g1 111"
|
"g g1 111"
|
||||||
|
|
||||||
compare "$SOURCE/inline" "(--inline)"
|
compare "$SOURCE/inline" "(--inline)"
|
||||||
|
|
||||||
|
@ -95,19 +95,19 @@ echo "*** Testing --inline with --replace"
|
||||||
prepare_testdir "$SOURCE/inline"
|
prepare_testdir "$SOURCE/inline"
|
||||||
# copy a random file to make sure it is ignored
|
# copy a random file to make sure it is ignored
|
||||||
cp "$f" "$TESTDIR/etc/sysusers.d/confuse.conf"
|
cp "$f" "$TESTDIR/etc/sysusers.d/confuse.conf"
|
||||||
$SYSUSERS --root="$TESTDIR" \
|
"$SYSUSERS" --root="$TESTDIR" \
|
||||||
--inline \
|
--inline \
|
||||||
--replace=/etc/sysusers.d/confuse.conf \
|
--replace=/etc/sysusers.d/confuse.conf \
|
||||||
"u u1 222 - - /bin/zsh" \
|
"u u1 222 - - /bin/zsh" \
|
||||||
"g g1 111"
|
"g g1 111"
|
||||||
|
|
||||||
compare "$SOURCE/inline" "(--inline --replace=…)"
|
compare "$SOURCE/inline" "(--inline --replace=…)"
|
||||||
|
|
||||||
echo "*** Testing --inline with no /etc"
|
echo "*** Testing --inline with no /etc"
|
||||||
rm -rf "${TESTDIR:?}/etc"
|
rm -rf "${TESTDIR:?}/etc"
|
||||||
$SYSUSERS --root="$TESTDIR" --inline \
|
"$SYSUSERS" --root="$TESTDIR" --inline \
|
||||||
"u u1 222 - - /bin/zsh" \
|
"u u1 222 - - /bin/zsh" \
|
||||||
"g g1 111"
|
"g g1 111"
|
||||||
|
|
||||||
compare "$SOURCE/inline" "(--inline)"
|
compare "$SOURCE/inline" "(--inline)"
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ for f in $(find "$SOURCE"/test-*.input | sort -V); do
|
||||||
echo "*** Running $f (with login.defs)"
|
echo "*** Running $f (with login.defs)"
|
||||||
prepare_testdir "${f%.input}"
|
prepare_testdir "${f%.input}"
|
||||||
cp "$f" "$TESTDIR/usr/lib/sysusers.d/test.conf"
|
cp "$f" "$TESTDIR/usr/lib/sysusers.d/test.conf"
|
||||||
$SYSUSERS --root="$TESTDIR"
|
"$SYSUSERS" --root="$TESTDIR"
|
||||||
|
|
||||||
# shellcheck disable=SC2050
|
# shellcheck disable=SC2050
|
||||||
[ @ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES@ = 1 ] && bound=555 || bound=$system_guid_max
|
[ @ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES@ = 1 ] && bound=555 || bound=$system_guid_max
|
||||||
|
@ -152,7 +152,7 @@ for f in $(find "$SOURCE"/test-*.input | sort -V); do
|
||||||
echo "*** Running $f (with login.defs symlinked)"
|
echo "*** Running $f (with login.defs symlinked)"
|
||||||
prepare_testdir "${f%.input}"
|
prepare_testdir "${f%.input}"
|
||||||
cp "$f" "$TESTDIR/usr/lib/sysusers.d/test.conf"
|
cp "$f" "$TESTDIR/usr/lib/sysusers.d/test.conf"
|
||||||
$SYSUSERS --root="$TESTDIR"
|
"$SYSUSERS" --root="$TESTDIR"
|
||||||
|
|
||||||
# shellcheck disable=SC2050
|
# shellcheck disable=SC2050
|
||||||
[ @ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES@ = 1 ] && bound=555 || bound=$system_guid_max
|
[ @ENABLE_COMPAT_MUTABLE_UID_BOUNDARIES@ = 1 ] && bound=555 || bound=$system_guid_max
|
||||||
|
@ -166,7 +166,7 @@ for f in $(find "$SOURCE"/unhappy-*.input | sort -V); do
|
||||||
echo "*** Running test $f"
|
echo "*** Running test $f"
|
||||||
prepare_testdir "${f%.input}"
|
prepare_testdir "${f%.input}"
|
||||||
cp "$f" "$TESTDIR/usr/lib/sysusers.d/test.conf"
|
cp "$f" "$TESTDIR/usr/lib/sysusers.d/test.conf"
|
||||||
SYSTEMD_LOG_LEVEL=info $SYSUSERS --root="$TESTDIR" 2>&1 | tail -n1 | sed -r 's/^[^:]+:[^:]+://' >"$TESTDIR/err"
|
SYSTEMD_LOG_LEVEL=info "$SYSUSERS" --root="$TESTDIR" 2>&1 | tail -n1 | sed -r 's/^[^:]+:[^:]+://' >"$TESTDIR/err"
|
||||||
if ! diff -u "$TESTDIR/err" "${f%.*}.expected-err"; then
|
if ! diff -u "$TESTDIR/err" "${f%.*}.expected-err"; then
|
||||||
echo >&2 "**** Unexpected error output for $f"
|
echo >&2 "**** Unexpected error output for $f"
|
||||||
cat >&2 "$TESTDIR/err"
|
cat >&2 "$TESTDIR/err"
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
set -eux
|
set -eux
|
||||||
set -o pipefail
|
set -o pipefail
|
||||||
|
|
||||||
|
# shellcheck source=test/units/util.sh
|
||||||
|
. "$(dirname "$0")"/util.sh
|
||||||
|
|
||||||
FAKE_ROOTS_DIR="$(mktemp -d --tmpdir="" fake-roots-XXX)"
|
FAKE_ROOTS_DIR="$(mktemp -d --tmpdir="" fake-roots-XXX)"
|
||||||
FSTYPE=$(stat --file-system --format "%T" /usr)
|
FSTYPE=$(stat --file-system --format "%T" /usr)
|
||||||
|
|
||||||
|
@ -1008,5 +1011,26 @@ if [[ -w /usr ]]; then
|
||||||
fi
|
fi
|
||||||
run_sysext_tests "$FAKE_ROOTS_DIR"
|
run_sysext_tests "$FAKE_ROOTS_DIR"
|
||||||
|
|
||||||
|
install_extension_images
|
||||||
|
|
||||||
|
# Test that nested mountpoints are carried over into and back from the sysext overlayfs.
|
||||||
|
ln -s /tmp/app0.raw /var/lib/extensions/app0.raw
|
||||||
|
mkdir /tmp/foo
|
||||||
|
mkdir /tmp/bar
|
||||||
|
mount --bind /tmp/bar /usr/share
|
||||||
|
mount --bind /tmp/foo /usr/share
|
||||||
|
systemd-sysext merge
|
||||||
|
test -f /usr/lib/systemd/system/some_file
|
||||||
|
mountpoint /usr/share
|
||||||
|
touch /tmp/foo/abc
|
||||||
|
test -f /usr/share/abc
|
||||||
|
umount /usr/share
|
||||||
|
test ! -f /usr/share/abc
|
||||||
|
systemd-sysext unmerge
|
||||||
|
test ! -f /usr/lib/systemd/system/some_file
|
||||||
|
mountpoint /usr/share
|
||||||
|
touch /tmp/bar/stuff
|
||||||
|
test -f /usr/share/stuff
|
||||||
|
umount /usr/share
|
||||||
|
|
||||||
exit 0
|
exit 0
|
||||||
|
|
|
@ -17,9 +17,9 @@ if test -f /run/systemd/stub/profile; then
|
||||||
fi
|
fi
|
||||||
echo "CURRENT MEASUREMENT:"
|
echo "CURRENT MEASUREMENT:"
|
||||||
/usr/lib/systemd/systemd-measure --current
|
/usr/lib/systemd/systemd-measure --current
|
||||||
if test -f /run/systemd/tpm2-pcr-signature.json ; then
|
if test -f /run/systemd/tpm2-pcr-signature.json; then
|
||||||
echo "CURRENT SIGNATURE:"
|
echo "CURRENT SIGNATURE:"
|
||||||
jq < /run/systemd/tpm2-pcr-signature.json
|
jq </run/systemd/tpm2-pcr-signature.json
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "CURRENT EVENT LOG + PCRS:"
|
echo "CURRENT EVENT LOG + PCRS:"
|
||||||
|
@ -45,7 +45,7 @@ TITLE="Profile Two"' --measure-base=/tmp/extended1.efi --cmdline="testprofile2=1
|
||||||
|
|
||||||
# Prepare a disk image, locked to the PCR measurements of the UKI we just generated
|
# Prepare a disk image, locked to the PCR measurements of the UKI we just generated
|
||||||
truncate -s 32M /root/encrypted.raw
|
truncate -s 32M /root/encrypted.raw
|
||||||
echo -n "geheim" > /root/encrypted.secret
|
echo -n "geheim" >/root/encrypted.secret
|
||||||
cryptsetup luksFormat -q --pbkdf pbkdf2 --pbkdf-force-iterations 1000 --use-urandom /root/encrypted.raw --key-file=/root/encrypted.secret
|
cryptsetup luksFormat -q --pbkdf pbkdf2 --pbkdf-force-iterations 1000 --use-urandom /root/encrypted.raw --key-file=/root/encrypted.secret
|
||||||
systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs= --tpm2-public-key=/root/pcrsign.public.pem --unlock-key-file=/root/encrypted.secret /root/encrypted.raw
|
systemd-cryptenroll --tpm2-device=auto --tpm2-pcrs= --tpm2-public-key=/root/pcrsign.public.pem --unlock-key-file=/root/encrypted.secret /root/encrypted.raw
|
||||||
rm -f /root/encrypted.secret
|
rm -f /root/encrypted.secret
|
||||||
|
@ -62,12 +62,12 @@ else
|
||||||
|
|
||||||
if [ "$ID" = "profile0" ]; then
|
if [ "$ID" = "profile0" ]; then
|
||||||
grep -v testprofile /proc/cmdline
|
grep -v testprofile /proc/cmdline
|
||||||
echo "default $(basename "$CURRENT_UKI")@profile1" > "$(bootctl -p)/loader/loader.conf"
|
echo "default $(basename "$CURRENT_UKI")@profile1" >"$(bootctl -p)/loader/loader.conf"
|
||||||
reboot
|
reboot
|
||||||
exit 0
|
exit 0
|
||||||
elif [ "$ID" = "profile1" ]; then
|
elif [ "$ID" = "profile1" ]; then
|
||||||
grep testprofile1=1 /proc/cmdline
|
grep testprofile1=1 /proc/cmdline
|
||||||
echo "default $(basename "$CURRENT_UKI")@profile2" > "$(bootctl -p)/loader/loader.conf"
|
echo "default $(basename "$CURRENT_UKI")@profile2" >"$(bootctl -p)/loader/loader.conf"
|
||||||
reboot
|
reboot
|
||||||
exit 0
|
exit 0
|
||||||
elif [ "$ID" = "profile2" ]; then
|
elif [ "$ID" = "profile2" ]; then
|
||||||
|
|
Loading…
Reference in New Issue