Compare commits
14 Commits
d7bfe68f04
...
44abc43793
Author | SHA1 | Date |
---|---|---|
Daan De Meyer | 44abc43793 | |
Marius Hoch | ff831e7c50 | |
Daan De Meyer | 3730f117d4 | |
Daan De Meyer | fee2b5aa48 | |
Daan De Meyer | 81af8f998e | |
chenjiayi | 4fc8a63f9e | |
Jason Yundt | dfb3155419 | |
Daan De Meyer | fc5037e7d7 | |
Yu Watanabe | 13f6ec7ce7 | |
Yu Watanabe | 6e1816ef16 | |
Yu Watanabe | 7ac1ad90d0 | |
Daan De Meyer | 729e26e8f9 | |
Yu Watanabe | d265b8afb7 | |
Yu Watanabe | 1aab0a5b10 |
|
@ -760,8 +760,9 @@ sensor:modalias:i2c:bmc150_accel:dmi:*:svnLENOVO:*:pvrLenovoYoga300-11IBR:*
|
||||||
sensor:modalias:acpi:ACCL0001*:dmi:*:svnLENOVO:pn60072:pvr851*:*
|
sensor:modalias:acpi:ACCL0001*:dmi:*:svnLENOVO:pn60072:pvr851*:*
|
||||||
ACCEL_MOUNT_MATRIX=0, 1, 0; -1, 0, 0; 0, 0, 1
|
ACCEL_MOUNT_MATRIX=0, 1, 0; -1, 0, 0; 0, 0, 1
|
||||||
|
|
||||||
# IdeaPad Duet 3 10IGL5 (82AT)
|
# IdeaPad Duet 3 10IGL5 (82AT) and 10IGL5-LTE (82HK)
|
||||||
sensor:modalias:acpi:SMO8B30*:dmi:*:svnLENOVO*:pn82AT:*
|
sensor:modalias:acpi:SMO8B30*:dmi:*:svnLENOVO*:pn82AT:*
|
||||||
|
sensor:modalias:acpi:SMO8B30*:dmi:*:svnLENOVO*:pn82HK:*
|
||||||
ACCEL_MOUNT_MATRIX=0, 1, 0; -1, 0, 0; 0, 0, 1
|
ACCEL_MOUNT_MATRIX=0, 1, 0; -1, 0, 0; 0, 0, 1
|
||||||
|
|
||||||
#########################################
|
#########################################
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "fileio.h"
|
#include "fileio.h"
|
||||||
#include "fs-util.h"
|
#include "fs-util.h"
|
||||||
|
#include "glyph-util.h"
|
||||||
#include "hexdecoct.h"
|
#include "hexdecoct.h"
|
||||||
#include "inotify-util.h"
|
#include "inotify-util.h"
|
||||||
#include "io-util.h"
|
#include "io-util.h"
|
||||||
|
@ -274,6 +275,52 @@ bool any_key_to_proceed(void) {
|
||||||
return key != 'q';
|
return key != 'q';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int show_menu(char **x, unsigned n_columns, unsigned width, unsigned percentage) {
|
||||||
|
unsigned break_lines, break_modulo;
|
||||||
|
size_t n, per_column, i, j;
|
||||||
|
|
||||||
|
assert(n_columns > 0);
|
||||||
|
|
||||||
|
n = strv_length(x);
|
||||||
|
per_column = DIV_ROUND_UP(n, n_columns);
|
||||||
|
|
||||||
|
break_lines = lines();
|
||||||
|
if (break_lines > 2)
|
||||||
|
break_lines--;
|
||||||
|
|
||||||
|
/* The first page gets two extra lines, since we want to show
|
||||||
|
* a title */
|
||||||
|
break_modulo = break_lines;
|
||||||
|
if (break_modulo > 3)
|
||||||
|
break_modulo -= 3;
|
||||||
|
|
||||||
|
for (i = 0; i < per_column; i++) {
|
||||||
|
|
||||||
|
for (j = 0; j < n_columns; j++) {
|
||||||
|
_cleanup_free_ char *e = NULL;
|
||||||
|
|
||||||
|
if (j * per_column + i >= n)
|
||||||
|
break;
|
||||||
|
|
||||||
|
e = ellipsize(x[j * per_column + i], width, percentage);
|
||||||
|
if (!e)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
printf("%4zu) %-*s", j * per_column + i + 1, (int) width, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
putchar('\n');
|
||||||
|
|
||||||
|
/* on the first screen we reserve 2 extra lines for the title */
|
||||||
|
if (i % break_lines == break_modulo) {
|
||||||
|
if (!any_key_to_proceed())
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int open_terminal(const char *name, int mode) {
|
int open_terminal(const char *name, int mode) {
|
||||||
_cleanup_close_ int fd = -EBADF;
|
_cleanup_close_ int fd = -EBADF;
|
||||||
unsigned c = 0;
|
unsigned c = 0;
|
||||||
|
|
|
@ -79,6 +79,7 @@ int read_one_char(FILE *f, char *ret, usec_t timeout, bool *need_nl);
|
||||||
int ask_char(char *ret, const char *replies, const char *text, ...) _printf_(3, 4);
|
int ask_char(char *ret, const char *replies, const char *text, ...) _printf_(3, 4);
|
||||||
int ask_string(char **ret, const char *text, ...) _printf_(2, 3);
|
int ask_string(char **ret, const char *text, ...) _printf_(2, 3);
|
||||||
bool any_key_to_proceed(void);
|
bool any_key_to_proceed(void);
|
||||||
|
int show_menu(char **x, unsigned n_columns, unsigned width, unsigned percentage);
|
||||||
|
|
||||||
int vt_disallocate(const char *name);
|
int vt_disallocate(const char *name);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -132,52 +132,6 @@ static void print_welcome(int rfd) {
|
||||||
done = true;
|
done = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int show_menu(char **x, unsigned n_columns, unsigned width, unsigned percentage) {
|
|
||||||
unsigned break_lines, break_modulo;
|
|
||||||
size_t n, per_column, i, j;
|
|
||||||
|
|
||||||
assert(n_columns > 0);
|
|
||||||
|
|
||||||
n = strv_length(x);
|
|
||||||
per_column = DIV_ROUND_UP(n, n_columns);
|
|
||||||
|
|
||||||
break_lines = lines();
|
|
||||||
if (break_lines > 2)
|
|
||||||
break_lines--;
|
|
||||||
|
|
||||||
/* The first page gets two extra lines, since we want to show
|
|
||||||
* a title */
|
|
||||||
break_modulo = break_lines;
|
|
||||||
if (break_modulo > 3)
|
|
||||||
break_modulo -= 3;
|
|
||||||
|
|
||||||
for (i = 0; i < per_column; i++) {
|
|
||||||
|
|
||||||
for (j = 0; j < n_columns; j++) {
|
|
||||||
_cleanup_free_ char *e = NULL;
|
|
||||||
|
|
||||||
if (j * per_column + i >= n)
|
|
||||||
break;
|
|
||||||
|
|
||||||
e = ellipsize(x[j * per_column + i], width, percentage);
|
|
||||||
if (!e)
|
|
||||||
return log_oom();
|
|
||||||
|
|
||||||
printf("%4zu) %-*s", j * per_column + i + 1, (int) width, e);
|
|
||||||
}
|
|
||||||
|
|
||||||
putchar('\n');
|
|
||||||
|
|
||||||
/* on the first screen we reserve 2 extra lines for the title */
|
|
||||||
if (i % break_lines == break_modulo) {
|
|
||||||
if (!any_key_to_proceed())
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int prompt_loop(const char *text, char **l, unsigned percentage, bool (*is_valid)(const char *name), char **ret) {
|
static int prompt_loop(const char *text, char **l, unsigned percentage, bool (*is_valid)(const char *name), char **ret) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
|
|
|
@ -2424,6 +2424,55 @@ static int has_regular_user(void) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int acquire_group_list(char ***ret) {
|
||||||
|
_cleanup_(userdb_iterator_freep) UserDBIterator *iterator = NULL;
|
||||||
|
_cleanup_strv_free_ char **groups = NULL;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(ret);
|
||||||
|
|
||||||
|
r = groupdb_all(USERDB_SUPPRESS_SHADOW|USERDB_EXCLUDE_DYNAMIC_USER, &iterator);
|
||||||
|
if (r == -ENOLINK)
|
||||||
|
log_debug_errno(r, "No groups found. (Didn't check via Varlink.)");
|
||||||
|
else if (r == -ESRCH)
|
||||||
|
log_debug_errno(r, "No groups found.");
|
||||||
|
else if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed to enumerate groups, ignoring: %m");
|
||||||
|
else {
|
||||||
|
for (;;) {
|
||||||
|
_cleanup_(group_record_unrefp) GroupRecord *gr = NULL;
|
||||||
|
|
||||||
|
r = groupdb_iterator_get(iterator, &gr);
|
||||||
|
if (r == -ESRCH)
|
||||||
|
break;
|
||||||
|
if (r < 0)
|
||||||
|
return log_debug_errno(r, "Failed acquire next group: %m");
|
||||||
|
|
||||||
|
if (!IN_SET(group_record_disposition(gr), USER_REGULAR, USER_SYSTEM))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (group_record_disposition(gr) == USER_REGULAR) {
|
||||||
|
_cleanup_(user_record_unrefp) UserRecord *ur = NULL;
|
||||||
|
|
||||||
|
r = userdb_by_name(gr->group_name, USERDB_SUPPRESS_SHADOW|USERDB_EXCLUDE_DYNAMIC_USER, &ur);
|
||||||
|
if (r < 0 && r != -ESRCH)
|
||||||
|
return log_debug_errno(r, "Failed to check if matching user exists for group '%s': %m", gr->group_name);
|
||||||
|
|
||||||
|
if (r >= 0 && user_record_disposition(ur) == USER_REGULAR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
r = strv_extend(&groups, gr->group_name);
|
||||||
|
if (r < 0)
|
||||||
|
return log_oom();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*ret = TAKE_PTR(groups);
|
||||||
|
return !!*ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int create_interactively(void) {
|
static int create_interactively(void) {
|
||||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||||
_cleanup_free_ char *username = NULL;
|
_cleanup_free_ char *username = NULL;
|
||||||
|
@ -2476,6 +2525,116 @@ static int create_interactively(void) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to set userName field: %m");
|
return log_error_errno(r, "Failed to set userName field: %m");
|
||||||
|
|
||||||
|
_cleanup_strv_free_ char **available = NULL, **groups = NULL;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
_cleanup_free_ char *s = NULL;
|
||||||
|
unsigned u;
|
||||||
|
|
||||||
|
r = ask_string(&s,
|
||||||
|
"%s Please enter an auxiliary group for user %s (empty to continue, \"list\" to list available groups): ",
|
||||||
|
special_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET), username);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to query user for auxiliary group: %m");
|
||||||
|
|
||||||
|
if (isempty(s))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (streq(s, "list")) {
|
||||||
|
if (!available) {
|
||||||
|
r = acquire_group_list(&available);
|
||||||
|
if (r < 0)
|
||||||
|
log_warning_errno(r, "Failed to enumerate available groups, ignoring: %m");
|
||||||
|
if (r == 0)
|
||||||
|
log_notice("Did not find any available groups");
|
||||||
|
if (r <= 0)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = show_menu(available, /*n_columns=*/ 3, /*width=*/ 20, /*percentage=*/ 60);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
putchar('\n');
|
||||||
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
r = safe_atou(s, &u);
|
||||||
|
if (r >= 0) {
|
||||||
|
if (u <= 0 || u > strv_length(available)) {
|
||||||
|
log_error("Specified entry number out of range.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info("Selected '%s'.", available[u-1]);
|
||||||
|
|
||||||
|
r = strv_extend(&groups, available[u-1]);
|
||||||
|
if (r < 0)
|
||||||
|
return log_oom();
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!valid_user_group_name(s, /* flags= */ 0)) {
|
||||||
|
log_notice("Specified group name is not a valid UNIX group name, try again: %s", s);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = groupdb_by_name(s, USERDB_SUPPRESS_SHADOW|USERDB_EXCLUDE_DYNAMIC_USER, /*ret=*/ NULL);
|
||||||
|
if (r == -ESRCH) {
|
||||||
|
log_notice("Specified auxiliary group does not exist, try again: %s", s);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to check if specified group '%s' already exists: %m", s);
|
||||||
|
|
||||||
|
r = strv_extend(&groups, s);
|
||||||
|
if (r < 0)
|
||||||
|
return log_oom();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (groups) {
|
||||||
|
r = sd_json_variant_set_field_strv(&arg_identity_extra, "memberOf", groups);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to set memberOf field: %m");
|
||||||
|
}
|
||||||
|
|
||||||
|
_cleanup_free_ char *shell = NULL;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
shell = mfree(shell);
|
||||||
|
|
||||||
|
r = ask_string(&shell,
|
||||||
|
"%s Please enter the shell to use for user %s (empty to skip): ",
|
||||||
|
special_glyph(SPECIAL_GLYPH_TRIANGULAR_BULLET), username);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to query user for username: %m");
|
||||||
|
|
||||||
|
if (isempty(shell)) {
|
||||||
|
log_info("No data entered, skipping.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!valid_shell(shell)) {
|
||||||
|
log_notice("Specified shell is not a valid UNIX shell path, try again: %s", shell);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = RET_NERRNO(access(shell, F_OK));
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to check if shell %s exists: %m", shell);
|
||||||
|
if (r >= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
log_notice("Specified shell '%s' is not installed, try another one.", shell);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shell) {
|
||||||
|
r = sd_json_variant_set_field_string(&arg_identity_extra, "shell", shell);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to set shell field: %m");
|
||||||
|
}
|
||||||
|
|
||||||
return create_home_common(/* input= */ NULL);
|
return create_home_common(/* input= */ NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,10 +1752,23 @@ 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 (;;) {
|
||||||
|
_cleanup_free_ char *word = NULL, *resolved = NULL;
|
||||||
|
|
||||||
|
r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
|
||||||
|
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) {
|
if (r < 0) {
|
||||||
log_syntax(unit, LOG_WARNING, filename, line, r,
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||||
"Failed to expand specifiers in ExcludeFiles= path, ignoring: %s", rvalue);
|
"Failed to expand specifiers in %s path, ignoring: %s", lvalue, word);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1764,6 +1778,7 @@ static int config_parse_exclude_files(
|
||||||
|
|
||||||
if (strv_consume(exclude_files, TAKE_PTR(resolved)) < 0)
|
if (strv_consume(exclude_files, TAKE_PTR(resolved)) < 0)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,7 +84,7 @@ 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"
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ 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" \
|
||||||
|
@ -105,7 +105,7 @@ 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"
|
||||||
|
|
||||||
|
@ -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"
|
||||||
|
|
Loading…
Reference in New Issue