Compare commits

...

15 Commits

Author SHA1 Message Date
Zbigniew Jędrzejewski-Szmek ff1ef4757e
Merge 8da8996181 into 4a346b779a 2024-11-25 13:42:20 +01:00
Daan De Meyer 4a346b779a test: Dump coredumps from journal in the integration test wrapper
Fixes #35277
2024-11-25 19:12:11 +09:00
Yu Watanabe 0e42004f3e networkd-test.py: disable IPv6AcceptRA= if not necessary
To speed up the test. Otherwise, it takes about few seconds interfaces
to enter the configured state. And may networkd-wait-online timeouts.
2024-11-25 10:07:26 +00:00
Luca Boccassi 6fd3496cfd test: mask tmpfiles.d file shipped by selinux policy package in containers
This tmpfiles.d wants to write to sysfs, which is read-only in containers,
so systemd-tmpfiles --create fails in TEST-22-TMPFILES when ran in nspawn
if the selinux policy package is instealled. Mask it, as it's not our
config file, we don't need it in the test.
2024-11-25 15:25:55 +09:00
Daan De Meyer bb486fe9df mkosi: Use shared extra tree between initrd and main image
Let's share more between initrd and main system and use a shared
extra tree to achieve that.
2024-11-25 15:09:58 +09:00
Zbigniew Jędrzejewski-Szmek 8da8996181 gpt-auto-generator: improve log message
We said "exiting", but then the program continues to do other operations
and log additional messages.
2024-11-20 15:05:16 +01:00
Zbigniew Jędrzejewski-Szmek fb1ad8c2df shared/exec-util: fix logging of the args of an executed program
The debug logs has lots of "About to execute /some/path (null)". This
occurs when the args array is empty. Instead, only print "(null)" if
we failed with oom.

Having strv_skip() return NULL makes this pleasant to write without repeating
strv_isempty() a few times.
2024-11-20 15:05:16 +01:00
Zbigniew Jędrzejewski-Szmek 7a5997bad1 test-execve: minor simplification 2024-11-20 15:05:16 +01:00
Zbigniew Jędrzejewski-Szmek 64e225d4c3 various: handle the positive condition after strv_skip() first 2024-11-20 15:05:16 +01:00
Zbigniew Jędrzejewski-Szmek d9cb7338f9 busctl: use RET_GATHER 2024-11-20 15:05:16 +01:00
Zbigniew Jędrzejewski-Szmek 654fa34796 busctl: use STRV_FOREACH in the usual fashion
Also put positive branch first, do not use 'i' as a char** variable name.
2024-11-20 15:05:16 +01:00
Zbigniew Jędrzejewski-Szmek 0638a45ec9 analyze: use STRV_FOREACH in consistent fashion
Also put positive condition first.
2024-11-20 15:05:16 +01:00
Zbigniew Jędrzejewski-Szmek e97f1ad4c9 basic/strv: return NULL from strv_skip
strv_skip was written to carefully return the original array, but this turns
out to be an unnecessary complication. After the previous patch, no caller
cares about the distinction between NULL and { NULL }, but various callers need
to wrap the process the returned value with strv_isempty(), sometimes more than
once. Let's always return NULL for an empty result to allow callers to be
simplified.
2024-11-20 15:05:16 +01:00
Zbigniew Jędrzejewski-Szmek 48e5aec4a3 homectl: split out inspect_home() and authenticate_home()
mangle_user_list() was doing a microoptimization of avoiding of copying of a
single string by constructing the strv object manually. This seems like more
trouble than it's worth, considering that this is called once in the program's
life.

Rework the code to have inspect_home() and authenticate_home() that handle a
single home name and call them in a loop from the outer function.
2024-11-20 14:58:56 +01:00
Zbigniew Jędrzejewski-Szmek 907a3b128c vconsole-setup: reword error messages
I was looking at some logs, and — without context —
"Setting source virtual console failed" doesn't make sense. It's a source
internally in vconsole-setup because we configure it and then use it to copy
the settings to other consoles. But at the point this message is emitted it's
not yet a source of anything. Also, "setting" sounds like we'd like to assign
it somewhere, which is even more confusing. Reword the messages to be more
down-to-earth and meaningful without looking at the code.
2024-11-19 17:18:14 +01:00
37 changed files with 388 additions and 355 deletions

View File

@ -38,9 +38,8 @@ SignExpectedPcr=yes
[Content] [Content]
ExtraTrees= ExtraTrees=
mkosi.extra.common
mkosi.crt:/usr/lib/verity.d/mkosi.crt # sysext verification key mkosi.crt:/usr/lib/verity.d/mkosi.crt # sysext verification key
mkosi.leak-sanitizer-suppressions:/usr/lib/systemd/leak-sanitizer-suppressions
mkosi.coredump-journal-storage.conf:/usr/lib/systemd/coredump.conf.d/10-coredump-journal-storage.conf
%O/minimal-0.root-%a.raw:/usr/share/minimal_0.raw %O/minimal-0.root-%a.raw:/usr/share/minimal_0.raw
%O/minimal-0.root-%a-verity.raw:/usr/share/minimal_0.verity %O/minimal-0.root-%a-verity.raw:/usr/share/minimal_0.verity
%O/minimal-0.root-%a-verity-sig.raw:/usr/share/minimal_0.verity.sig %O/minimal-0.root-%a-verity-sig.raw:/usr/share/minimal_0.verity.sig

View File

@ -6,9 +6,7 @@ Include=
%D/mkosi.sanitizers %D/mkosi.sanitizers
[Content] [Content]
ExtraTrees= ExtraTrees=%D/mkosi.extra.common
%D/mkosi.leak-sanitizer-suppressions:/usr/lib/systemd/leak-sanitizer-suppressions
%D/mkosi.coredump-journal-storage.conf:/usr/lib/systemd/coredump.conf.d/10-coredump-journal-storage.conf
Packages= Packages=
findutils findutils

View File

@ -47,30 +47,25 @@ int verb_architectures(int argc, char *argv[], void *userdata) {
(void) table_hide_column_from_display(table, (size_t) 0); (void) table_hide_column_from_display(table, (size_t) 0);
if (strv_isempty(strv_skip(argv, 1))) char **args = strv_skip(argv, 1);
for (Architecture a = 0; a < _ARCHITECTURE_MAX; a++) { if (args) {
r = add_arch(table, a); STRV_FOREACH(arg, args) {
if (r < 0)
return r;
}
else {
STRV_FOREACH(as, strv_skip(argv, 1)) {
Architecture a; Architecture a;
if (streq(*as, "native")) if (streq(*arg, "native"))
a = native_architecture(); a = native_architecture();
else if (streq(*as, "uname")) else if (streq(*arg, "uname"))
a = uname_architecture(); a = uname_architecture();
else if (streq(*as, "secondary")) { else if (streq(*arg, "secondary")) {
#ifdef ARCHITECTURE_SECONDARY #ifdef ARCHITECTURE_SECONDARY
a = ARCHITECTURE_SECONDARY; a = ARCHITECTURE_SECONDARY;
#else #else
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No secondary architecture."); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No secondary architecture.");
#endif #endif
} else } else
a = architecture_from_string(*as); a = architecture_from_string(*arg);
if (a < 0) if (a < 0)
return log_error_errno(a, "Architecture \"%s\" not known.", *as); return log_error_errno(a, "Architecture \"%s\" not known.", *arg);
r = add_arch(table, a); r = add_arch(table, a);
if (r < 0) if (r < 0)
@ -78,7 +73,12 @@ int verb_architectures(int argc, char *argv[], void *userdata) {
} }
(void) table_set_sort(table, (size_t) 0); (void) table_set_sort(table, (size_t) 0);
} } else
for (Architecture a = 0; a < _ARCHITECTURE_MAX; a++) {
r = add_arch(table, a);
if (r < 0)
return r;
}
r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend); r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend);
if (r < 0) if (r < 0)

View File

@ -9,12 +9,11 @@
#include "strv.h" #include "strv.h"
int verb_cat_config(int argc, char *argv[], void *userdata) { int verb_cat_config(int argc, char *argv[], void *userdata) {
char **list;
int r; int r;
pager_open(arg_pager_flags); pager_open(arg_pager_flags);
list = strv_skip(argv, 1); char **list = strv_skip(argv, 1);
STRV_FOREACH(arg, list) { STRV_FOREACH(arg, list) {
const char *t = NULL; const char *t = NULL;

View File

@ -17,7 +17,24 @@ int verb_exit_status(int argc, char *argv[], void *userdata) {
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to right-align status: %m"); return log_error_errno(r, "Failed to right-align status: %m");
if (strv_isempty(strv_skip(argv, 1))) char **args = strv_skip(argv, 1);
if (args)
STRV_FOREACH(arg, args) {
int status;
status = exit_status_from_string(*arg);
if (status < 0)
return log_error_errno(status, "Invalid exit status \"%s\".", *arg);
assert(status >= 0 && (size_t) status < ELEMENTSOF(exit_status_mappings));
r = table_add_many(table,
TABLE_STRING, exit_status_mappings[status].name ?: "-",
TABLE_INT, status,
TABLE_STRING, exit_status_class(status) ?: "-");
if (r < 0)
return table_log_add_error(r);
}
else
for (size_t i = 0; i < ELEMENTSOF(exit_status_mappings); i++) { for (size_t i = 0; i < ELEMENTSOF(exit_status_mappings); i++) {
if (!exit_status_mappings[i].name) if (!exit_status_mappings[i].name)
continue; continue;
@ -29,22 +46,6 @@ int verb_exit_status(int argc, char *argv[], void *userdata) {
if (r < 0) if (r < 0)
return table_log_add_error(r); return table_log_add_error(r);
} }
else
for (int i = 1; i < argc; i++) {
int status;
status = exit_status_from_string(argv[i]);
if (status < 0)
return log_error_errno(status, "Invalid exit status \"%s\".", argv[i]);
assert(status >= 0 && (size_t) status < ELEMENTSOF(exit_status_mappings));
r = table_add_many(table,
TABLE_STRING, exit_status_mappings[status].name ?: "-",
TABLE_INT, status,
TABLE_STRING, exit_status_class(status) ?: "-");
if (r < 0)
return table_log_add_error(r);
}
r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend); r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend);
if (r < 0) if (r < 0)

View File

@ -106,15 +106,30 @@ static void dump_filesystem_set(const FilesystemSet *set) {
} }
int verb_filesystems(int argc, char *argv[], void *userdata) { int verb_filesystems(int argc, char *argv[], void *userdata) {
bool first = true;
#if ! HAVE_LIBBPF #if ! HAVE_LIBBPF
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Not compiled with libbpf support, sorry."); return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Not compiled with libbpf support, sorry.");
#endif #endif
pager_open(arg_pager_flags); pager_open(arg_pager_flags);
if (strv_isempty(strv_skip(argv, 1))) { char **args = strv_skip(argv, 1);
if (args)
STRV_FOREACH(name, args) {
if (name != args)
puts("");
const FilesystemSet *set = filesystem_set_find(*name);
if (!set) {
/* make sure the error appears below normal output */
fflush(stdout);
return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
"Filesystem set \"%s\" not found.", *name);
}
dump_filesystem_set(set);
}
else {
_cleanup_set_free_ Set *kernel = NULL, *known = NULL; _cleanup_set_free_ Set *kernel = NULL, *known = NULL;
int k; int k;
@ -126,27 +141,24 @@ int verb_filesystems(int argc, char *argv[], void *userdata) {
for (FilesystemGroups i = 0; i < _FILESYSTEM_SET_MAX; i++) { for (FilesystemGroups i = 0; i < _FILESYSTEM_SET_MAX; i++) {
const FilesystemSet *set = filesystem_sets + i; const FilesystemSet *set = filesystem_sets + i;
if (!first) if (i > 0)
puts(""); puts("");
dump_filesystem_set(set); dump_filesystem_set(set);
filesystem_set_remove(kernel, set); filesystem_set_remove(kernel, set);
if (i != FILESYSTEM_SET_KNOWN) if (i != FILESYSTEM_SET_KNOWN)
filesystem_set_remove(known, set); filesystem_set_remove(known, set);
first = false;
} }
if (arg_quiet) /* Let's not show the extra stuff in quiet mode */ if (arg_quiet) /* Let's not show the extra stuff in quiet mode */
return 0; return 0;
if (!set_isempty(known)) { if (!set_isempty(known)) {
_cleanup_free_ char **l = NULL;
printf("\n" printf("\n"
"# %sUngrouped filesystems%s (known but not included in any of the groups except @known):\n", "# %sUngrouped filesystems%s (known but not included in any of the groups except @known):\n",
ansi_highlight(), ansi_normal()); ansi_highlight(), ansi_normal());
l = set_get_strv(known); _cleanup_free_ char **l = set_get_strv(known);
if (!l) if (!l)
return log_oom(); return log_oom();
@ -197,25 +209,7 @@ int verb_filesystems(int argc, char *argv[], void *userdata) {
STRV_FOREACH(filesystem, l) STRV_FOREACH(filesystem, l)
printf("# %s\n", *filesystem); printf("# %s\n", *filesystem);
} }
} else }
STRV_FOREACH(name, strv_skip(argv, 1)) {
const FilesystemSet *set;
if (!first)
puts("");
set = filesystem_set_find(*name);
if (!set) {
/* make sure the error appears below normal output */
fflush(stdout);
return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
"Filesystem set \"%s\" not found.", *name);
}
dump_filesystem_set(set);
first = false;
}
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -35,11 +35,12 @@ int verb_malloc(int argc, char *argv[], void *userdata) {
char **services = STRV_MAKE("org.freedesktop.systemd1"); char **services = STRV_MAKE("org.freedesktop.systemd1");
int r; int r;
if (!strv_isempty(strv_skip(argv, 1))) { char **args = strv_skip(argv, 1);
services = strv_skip(argv, 1); if (args) {
STRV_FOREACH(service, services) STRV_FOREACH(service, args)
if (!service_name_is_valid(*service)) if (!service_name_is_valid(*service))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "D-Bus service name '%s' is not valid.", *service); return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "D-Bus service name '%s' is not valid.", *service);
services = args;
} }
r = acquire_bus(&bus, NULL); r = acquire_bus(&bus, NULL);

View File

@ -114,19 +114,14 @@ int verb_pcrs(int argc, char *argv[], void *userdata) {
if (!alg) /* hide hash column if we couldn't acquire it */ if (!alg) /* hide hash column if we couldn't acquire it */
(void) table_set_display(table, 0, 1); (void) table_set_display(table, 0, 1);
if (strv_isempty(strv_skip(argv, 1))) char **args = strv_skip(argv, 1);
for (uint32_t pi = 0; pi < _TPM2_PCR_INDEX_MAX_DEFINED; pi++) { if (args) {
r = add_pcr_to_table(table, alg, pi); STRV_FOREACH(arg, args) {
if (r < 0)
return r;
}
else {
for (int i = 1; i < argc; i++) {
int pi; int pi;
pi = tpm2_pcr_index_from_string(argv[i]); pi = tpm2_pcr_index_from_string(*arg);
if (pi < 0) if (pi < 0)
return log_error_errno(pi, "PCR index \"%s\" not known.", argv[i]); return log_error_errno(pi, "PCR index \"%s\" not known.", *arg);
r = add_pcr_to_table(table, alg, pi); r = add_pcr_to_table(table, alg, pi);
if (r < 0) if (r < 0)
@ -134,7 +129,12 @@ int verb_pcrs(int argc, char *argv[], void *userdata) {
} }
(void) table_set_sort(table, (size_t) 0); (void) table_set_sort(table, (size_t) 0);
} } else
for (uint32_t pi = 0; pi < _TPM2_PCR_INDEX_MAX_DEFINED; pi++) {
r = add_pcr_to_table(table, alg, pi);
if (r < 0)
return r;
}
r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, /* show_header= */true); r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, /* show_header= */true);
if (r < 0) if (r < 0)

View File

@ -103,12 +103,30 @@ static void dump_syscall_filter(const SyscallFilterSet *set) {
} }
int verb_syscall_filters(int argc, char *argv[], void *userdata) { int verb_syscall_filters(int argc, char *argv[], void *userdata) {
bool first = true;
int r; int r;
pager_open(arg_pager_flags); pager_open(arg_pager_flags);
if (strv_isempty(strv_skip(argv, 1))) { char **args = strv_skip(argv, 1);
if (args)
STRV_FOREACH(name, args) {
const SyscallFilterSet *set;
if (name != args)
puts("");
set = syscall_filter_set_find(*name);
if (!set) {
/* make sure the error appears below normal output */
fflush(stdout);
return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
"Filter set \"%s\" not found.", *name);
}
dump_syscall_filter(set);
}
else {
_cleanup_set_free_ Set *kernel = NULL, *known = NULL; _cleanup_set_free_ Set *kernel = NULL, *known = NULL;
int k = 0; /* explicit initialization to appease gcc */ int k = 0; /* explicit initialization to appease gcc */
@ -121,27 +139,24 @@ int verb_syscall_filters(int argc, char *argv[], void *userdata) {
for (int i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) { for (int i = 0; i < _SYSCALL_FILTER_SET_MAX; i++) {
const SyscallFilterSet *set = syscall_filter_sets + i; const SyscallFilterSet *set = syscall_filter_sets + i;
if (!first) if (i > 0)
puts(""); puts("");
dump_syscall_filter(set); dump_syscall_filter(set);
syscall_set_remove(kernel, set); syscall_set_remove(kernel, set);
if (i != SYSCALL_FILTER_SET_KNOWN) if (i != SYSCALL_FILTER_SET_KNOWN)
syscall_set_remove(known, set); syscall_set_remove(known, set);
first = false;
} }
if (arg_quiet) /* Let's not show the extra stuff in quiet mode */ if (arg_quiet) /* Let's not show the extra stuff in quiet mode */
return 0; return 0;
if (!set_isempty(known)) { if (!set_isempty(known)) {
_cleanup_free_ char **l = NULL;
printf("\n" printf("\n"
"# %sUngrouped System Calls%s (known but not included in any of the groups except @known):\n", "# %sUngrouped System Calls%s (known but not included in any of the groups except @known):\n",
ansi_highlight(), ansi_normal()); ansi_highlight(), ansi_normal());
l = set_get_strv(known); _cleanup_free_ char **l = set_get_strv(known);
if (!l) if (!l)
return log_oom(); return log_oom();
@ -157,13 +172,11 @@ int verb_syscall_filters(int argc, char *argv[], void *userdata) {
if (!arg_quiet) if (!arg_quiet)
log_notice_errno(k, "# Not showing unlisted system calls, couldn't retrieve kernel system call list: %m"); log_notice_errno(k, "# Not showing unlisted system calls, couldn't retrieve kernel system call list: %m");
} else if (!set_isempty(kernel)) { } else if (!set_isempty(kernel)) {
_cleanup_free_ char **l = NULL;
printf("\n" printf("\n"
"# %sUnlisted System Calls%s (supported by the local kernel, but not included in any of the groups listed above):\n", "# %sUnlisted System Calls%s (supported by the local kernel, but not included in any of the groups listed above):\n",
ansi_highlight(), ansi_normal()); ansi_highlight(), ansi_normal());
l = set_get_strv(kernel); _cleanup_free_ char **l = set_get_strv(kernel);
if (!l) if (!l)
return log_oom(); return log_oom();
@ -172,25 +185,7 @@ int verb_syscall_filters(int argc, char *argv[], void *userdata) {
STRV_FOREACH(syscall, l) STRV_FOREACH(syscall, l)
printf("# %s\n", *syscall); printf("# %s\n", *syscall);
} }
} else }
STRV_FOREACH(name, strv_skip(argv, 1)) {
const SyscallFilterSet *set;
if (!first)
puts("");
set = syscall_filter_set_find(*name);
if (!set) {
/* make sure the error appears below normal output */
fflush(stdout);
return log_error_errno(SYNTHETIC_ERRNO(ENOENT),
"Filter set \"%s\" not found.", *name);
}
dump_syscall_filter(set);
first = false;
}
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -75,11 +75,12 @@ static int test_timestamp_one(const char *p) {
int verb_timestamp(int argc, char *argv[], void *userdata) { int verb_timestamp(int argc, char *argv[], void *userdata) {
int r = 0; int r = 0;
STRV_FOREACH(p, strv_skip(argv, 1)) { char **args = strv_skip(argv, 1);
RET_GATHER(r, test_timestamp_one(*p)); STRV_FOREACH(arg, args) {
if (arg != args)
puts("");
if (p[1]) RET_GATHER(r, test_timestamp_one(*arg));
putchar('\n');
} }
return r; return r;

View File

@ -956,14 +956,16 @@ bool strv_fnmatch_full(
} }
char** strv_skip(char **l, size_t n) { char** strv_skip(char **l, size_t n) {
while (n > 0) { while (n > 0) {
if (strv_isempty(l)) if (strv_isempty(l))
return l; return NULL;
l++, n--; l++, n--;
} }
/* To simplify callers, always return NULL instead of a zero-item array. */
if (strv_isempty(l))
return NULL;
return l; return l;
} }

View File

@ -547,9 +547,21 @@ static int tree(int argc, char **argv, void *userdata) {
if (r < 0) if (r < 0)
return r; return r;
if (argc <= 1) { char **args = strv_skip(argv, 1);
if (args)
STRV_FOREACH(arg, args) {
if (arg != args)
puts("");
if (args[1]) {
pager_open(arg_pager_flags);
printf("Service %s%s%s:\n", ansi_highlight(), *arg, ansi_normal());
}
RET_GATHER(r, tree_one(bus, *arg));
}
else {
_cleanup_strv_free_ char **names = NULL; _cleanup_strv_free_ char **names = NULL;
bool not_first = false;
r = sd_bus_list_names(bus, &names, NULL); r = sd_bus_list_names(bus, &names, NULL);
if (r < 0) if (r < 0)
@ -557,42 +569,21 @@ static int tree(int argc, char **argv, void *userdata) {
pager_open(arg_pager_flags); pager_open(arg_pager_flags);
STRV_FOREACH(i, names) { STRV_FOREACH(name, names) {
int q; if (!arg_unique && (*name)[0] == ':')
if (!arg_unique && (*i)[0] == ':')
continue; continue;
if (!arg_acquired && (*i)[0] == ':') if (!arg_acquired && (*name)[0] == ':')
continue; continue;
if (not_first) if (name != names)
printf("\n"); puts("");
printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_normal()); printf("Service %s%s%s:\n", ansi_highlight(), *name, ansi_normal());
q = tree_one(bus, *i); RET_GATHER(r, tree_one(bus, *name));
if (q < 0 && r >= 0)
r = q;
not_first = true;
}
} else
STRV_FOREACH(i, strv_skip(argv, 1)) {
int q;
if (i > argv+1)
printf("\n");
if (argv[2]) {
pager_open(arg_pager_flags);
printf("Service %s%s%s:\n", ansi_highlight(), *i, ansi_normal());
}
q = tree_one(bus, *i);
if (q < 0 && r >= 0)
r = q;
} }
}
return r; return r;
} }

View File

@ -663,8 +663,9 @@ static int add_root_mount(void) {
r = efi_loader_get_device_part_uuid(NULL); r = efi_loader_get_device_part_uuid(NULL);
if (r == -ENOENT) { if (r == -ENOENT) {
log_notice("EFI loader partition unknown, exiting.\n" log_notice("EFI loader partition unknown, not processing %s.\n"
"(The boot loader did not set EFI variable LoaderDevicePartUUID.)"); "(The boot loader did not set EFI variable LoaderDevicePartUUID.)",
in_initrd() ? "/sysroot" : "/");
return 0; return 0;
} else if (r < 0) } else if (r < 0)
return log_error_errno(r, "Failed to read loader partition UUID: %m"); return log_error_errno(r, "Failed to read loader partition UUID: %m");

View File

@ -691,122 +691,110 @@ static void dump_home_record(UserRecord *hr) {
} }
} }
static char **mangle_user_list(char **list, char ***ret_allocated) { static int inspect_home(sd_bus *bus, const char *name) {
_cleanup_free_ char *myself = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
char **l; _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
_cleanup_(user_record_unrefp) UserRecord *hr = NULL;
const char *json;
int incomplete;
uid_t uid;
int r;
if (!strv_isempty(list)) { r = parse_uid(name, &uid);
*ret_allocated = NULL; if (r < 0) {
return list; if (!valid_user_group_name(name, 0))
} return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid user name '%s'.", name);
myself = getusername_malloc(); r = bus_call_method(bus, bus_mgr, "GetUserRecordByName", &error, &reply, "s", name);
if (!myself) } else
return NULL; r = bus_call_method(bus, bus_mgr, "GetUserRecordByUID", &error, &reply, "u", (uint32_t) uid);
if (r < 0)
return log_error_errno(r, "Failed to inspect home: %s", bus_error_message(&error, r));
l = new(char*, 2); r = sd_bus_message_read(reply, "sbo", &json, &incomplete, NULL);
if (!l) if (r < 0)
return NULL; return bus_log_parse_error(r);
l[0] = TAKE_PTR(myself); r = sd_json_parse(json, SD_JSON_PARSE_SENSITIVE, &v, NULL, NULL);
l[1] = NULL; if (r < 0)
return log_error_errno(r, "Failed to parse JSON identity: %m");
*ret_allocated = l; hr = user_record_new();
return l; if (!hr)
return log_oom();
r = user_record_load(hr, v, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_LOG|USER_RECORD_PERMISSIVE);
if (r < 0)
return r;
hr->incomplete = incomplete;
dump_home_record(hr);
return 0;
} }
static int inspect_home(int argc, char *argv[], void *userdata) { static int inspect_homes(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
_cleanup_strv_free_ char **mangled_list = NULL; int r;
int r, ret = 0;
char **items;
pager_open(arg_pager_flags);
r = acquire_bus(&bus); r = acquire_bus(&bus);
if (r < 0) if (r < 0)
return r; return r;
items = mangle_user_list(strv_skip(argv, 1), &mangled_list); pager_open(arg_pager_flags);
if (!items)
return log_oom();
STRV_FOREACH(i, items) { char **args = strv_skip(argv, 1);
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; if (args) {
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; _cleanup_free_ char *myself = getusername_malloc();
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; if (!myself)
_cleanup_(user_record_unrefp) UserRecord *hr = NULL;
const char *json;
int incomplete;
uid_t uid;
r = parse_uid(*i, &uid);
if (r < 0) {
if (!valid_user_group_name(*i, 0)) {
log_error("Invalid user name '%s'.", *i);
if (ret == 0)
ret = -EINVAL;
continue;
}
r = bus_call_method(bus, bus_mgr, "GetUserRecordByName", &error, &reply, "s", *i);
} else
r = bus_call_method(bus, bus_mgr, "GetUserRecordByUID", &error, &reply, "u", (uint32_t) uid);
if (r < 0) {
log_error_errno(r, "Failed to inspect home: %s", bus_error_message(&error, r));
if (ret == 0)
ret = r;
continue;
}
r = sd_bus_message_read(reply, "sbo", &json, &incomplete, NULL);
if (r < 0) {
bus_log_parse_error(r);
if (ret == 0)
ret = r;
continue;
}
r = sd_json_parse(json, SD_JSON_PARSE_SENSITIVE, &v, NULL, NULL);
if (r < 0) {
log_error_errno(r, "Failed to parse JSON identity: %m");
if (ret == 0)
ret = r;
continue;
}
hr = user_record_new();
if (!hr)
return log_oom(); return log_oom();
r = user_record_load(hr, v, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_LOG|USER_RECORD_PERMISSIVE); return inspect_home(bus, myself);
if (r < 0) { } else {
if (ret == 0) STRV_FOREACH(arg, args)
ret = r; RET_GATHER(r, inspect_home(bus, *arg));
continue; return r;
}
hr->incomplete = incomplete;
dump_home_record(hr);
} }
return ret;
} }
static int authenticate_home(int argc, char *argv[], void *userdata) { static int authenticate_home(sd_bus *bus, const char *name) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_(user_record_unrefp) UserRecord *secret = NULL;
_cleanup_strv_free_ char **mangled_list = NULL; int r;
int r, ret = 0;
char **items;
items = mangle_user_list(strv_skip(argv, 1), &mangled_list); r = acquire_passed_secrets(name, &secret);
if (!items) if (r < 0)
return log_oom(); return r;
for (;;) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
r = bus_message_new_method_call(bus, &m, bus_mgr, "AuthenticateHome");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(m, "s", name);
if (r < 0)
return bus_log_create_error(r);
r = bus_message_append_secret(m, secret);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_call(bus, m, HOME_SLOW_BUS_CALL_TIMEOUT_USEC, &error, NULL);
if (r < 0) {
r = handle_generic_user_record_error(name, secret, &error, r, false);
if (r >= 0)
continue;
}
return r;
}
}
static int authenticate_homes(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
r = acquire_bus(&bus); r = acquire_bus(&bus);
if (r < 0) if (r < 0)
@ -814,44 +802,19 @@ static int authenticate_home(int argc, char *argv[], void *userdata) {
(void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password); (void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
STRV_FOREACH(i, items) { char **args = strv_skip(argv, 1);
_cleanup_(user_record_unrefp) UserRecord *secret = NULL; if (args) {
_cleanup_free_ char *myself = getusername_malloc();
if (!myself)
return log_oom();
r = acquire_passed_secrets(*i, &secret); return authenticate_home(bus, myself);
if (r < 0) } else {
return r; STRV_FOREACH(arg, args)
RET_GATHER(r, authenticate_home(bus, *arg));
for (;;) { return r;
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
r = bus_message_new_method_call(bus, &m, bus_mgr, "AuthenticateHome");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(m, "s", *i);
if (r < 0)
return bus_log_create_error(r);
r = bus_message_append_secret(m, secret);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_call(bus, m, HOME_SLOW_BUS_CALL_TIMEOUT_USEC, &error, NULL);
if (r < 0) {
r = handle_generic_user_record_error(*i, secret, &error, r, false);
if (r < 0) {
if (ret == 0)
ret = r;
break;
}
} else
break;
}
} }
return ret;
} }
static int update_last_change(sd_json_variant **v, bool with_password, bool override) { static int update_last_change(sd_json_variant **v, bool with_password, bool override) {
@ -4727,8 +4690,8 @@ static int run(int argc, char *argv[]) {
{ "list", VERB_ANY, 1, VERB_DEFAULT, list_homes }, { "list", VERB_ANY, 1, VERB_DEFAULT, list_homes },
{ "activate", 2, VERB_ANY, 0, activate_home }, { "activate", 2, VERB_ANY, 0, activate_home },
{ "deactivate", 2, VERB_ANY, 0, deactivate_home }, { "deactivate", 2, VERB_ANY, 0, deactivate_home },
{ "inspect", VERB_ANY, VERB_ANY, 0, inspect_home }, { "inspect", VERB_ANY, VERB_ANY, 0, inspect_homes },
{ "authenticate", VERB_ANY, VERB_ANY, 0, authenticate_home }, { "authenticate", VERB_ANY, VERB_ANY, 0, authenticate_homes },
{ "create", VERB_ANY, 2, 0, create_home }, { "create", VERB_ANY, 2, 0, create_home },
{ "remove", 2, VERB_ANY, 0, remove_home }, { "remove", 2, VERB_ANY, 0, remove_home },
{ "update", VERB_ANY, 2, 0, update_home }, { "update", VERB_ANY, 2, 0, update_home },

View File

@ -133,17 +133,7 @@ static int verb_show(int argc, char **argv, void *userdata) {
int r; int r;
argv = strv_skip(argv, 1); argv = strv_skip(argv, 1);
if (strv_isempty(argv)) { if (argv)
if (!sd_id128_is_null(arg_app))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"'show --app-specific=' can only be used with explicit UUID input.");
for (const GptPartitionType *e = gpt_partition_type_table; e->name; e++) {
r = show_one(&table, e->name, e->uuid, e == gpt_partition_type_table);
if (r < 0)
return r;
}
} else
STRV_FOREACH(p, argv) { STRV_FOREACH(p, argv) {
sd_id128_t uuid; sd_id128_t uuid;
const char *id = NULL; const char *id = NULL;
@ -171,6 +161,17 @@ static int verb_show(int argc, char **argv, void *userdata) {
if (r < 0) if (r < 0)
return r; return r;
} }
else {
if (!sd_id128_is_null(arg_app))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"'show --app-specific=' can only be used with explicit UUID input.");
for (const GptPartitionType *e = gpt_partition_type_table; e->name; e++) {
r = show_one(&table, e->name, e->uuid, e == gpt_partition_type_table);
if (r < 0)
return r;
}
}
if (table) { if (table) {
r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend); r = table_print_with_pager(table, arg_json_format_flags, arg_pager_flags, arg_legend);

View File

@ -152,11 +152,13 @@ static int do_execute(
} }
if (DEBUG_LOGGING) { if (DEBUG_LOGGING) {
_cleanup_free_ char *args = NULL; _cleanup_free_ char *s = NULL;
if (argv)
args = quote_command_line(strv_skip(argv, 1), SHELL_ESCAPE_EMPTY);
log_debug("About to execute %s%s%s", t, argv ? " " : "", argv ? strnull(args) : ""); char **args = strv_skip(argv, 1);
if (args)
s = quote_command_line(args, SHELL_ESCAPE_EMPTY);
log_debug("About to execute %s%s%s", t, args ? " " : "", args ? strnull(s) : "");
} }
if (FLAGS_SET(flags, EXEC_DIR_WARN_WORLD_WRITABLE)) { if (FLAGS_SET(flags, EXEC_DIR_WARN_WORLD_WRITABLE)) {

View File

@ -172,14 +172,14 @@ int verb_list_dependencies(int argc, char *argv[], void *userdata) {
return r; return r;
patterns = strv_skip(argv, 1); patterns = strv_skip(argv, 1);
if (strv_isempty(patterns)) { if (patterns) {
units = strv_new(SPECIAL_DEFAULT_TARGET);
if (!units)
return log_oom();
} else {
r = expand_unit_names(bus, patterns, NULL, &units, NULL); r = expand_unit_names(bus, patterns, NULL, &units, NULL);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to expand names: %m"); return log_error_errno(r, "Failed to expand names: %m");
} else {
units = strv_new(SPECIAL_DEFAULT_TARGET);
if (!units)
return log_oom();
} }
pager_open(arg_pager_flags); pager_open(arg_pager_flags);

View File

@ -20,15 +20,13 @@
*/ */
static int run(int argc, char **argv) { static int run(int argc, char **argv) {
_cleanup_close_ int fd = -EBADF;
char **args = strv_skip(argv, 1);
int r; int r;
test_setup_logging(LOG_DEBUG); test_setup_logging(LOG_DEBUG);
args = !strv_isempty(args) ? args : STRV_MAKE("/bin/true"); char **args = strv_skip(argv, 1) ?: STRV_MAKE("/bin/true");
fd = open(args[0], O_RDONLY | O_CLOEXEC); _cleanup_close_ int fd = open(args[0], O_RDONLY | O_CLOEXEC);
if (fd < 0) if (fd < 0)
return log_error_errno(errno, "open(%s) failed: %m", args[0]); return log_error_errno(errno, "open(%s) failed: %m", args[0]);

View File

@ -1004,17 +1004,21 @@ TEST(strv_skip) {
test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 0, STRV_MAKE("foo", "bar", "baz")); test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 0, STRV_MAKE("foo", "bar", "baz"));
test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 1, STRV_MAKE("bar", "baz")); test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 1, STRV_MAKE("bar", "baz"));
test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 2, STRV_MAKE("baz")); test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 2, STRV_MAKE("baz"));
test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 3, STRV_MAKE(NULL)); test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 3, NULL);
test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 4, STRV_MAKE(NULL)); test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 4, NULL);
test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 55, STRV_MAKE(NULL)); test_strv_skip_one(STRV_MAKE("foo", "bar", "baz"), 55, NULL);
test_strv_skip_one(STRV_MAKE("quux"), 0, STRV_MAKE("quux")); test_strv_skip_one(STRV_MAKE("quux"), 0, STRV_MAKE("quux"));
test_strv_skip_one(STRV_MAKE("quux"), 1, STRV_MAKE(NULL)); test_strv_skip_one(STRV_MAKE("quux"), 1, NULL);
test_strv_skip_one(STRV_MAKE("quux"), 55, STRV_MAKE(NULL)); test_strv_skip_one(STRV_MAKE("quux"), 55, NULL);
test_strv_skip_one(STRV_MAKE(NULL), 0, STRV_MAKE(NULL)); test_strv_skip_one(STRV_MAKE(NULL), 0, NULL);
test_strv_skip_one(STRV_MAKE(NULL), 1, STRV_MAKE(NULL)); test_strv_skip_one(STRV_MAKE(NULL), 1, NULL);
test_strv_skip_one(STRV_MAKE(NULL), 55, STRV_MAKE(NULL)); test_strv_skip_one(STRV_MAKE(NULL), 55, NULL);
test_strv_skip_one(NULL, 0, NULL);
test_strv_skip_one(NULL, 1, NULL);
test_strv_skip_one(NULL, 55, NULL);
} }
TEST(strv_extend_n) { TEST(strv_extend_n) {

View File

@ -35,7 +35,10 @@ static int builtin_kmod(UdevEvent *event, int argc, char *argv[]) {
"%s: expected: load [module…]", argv[0]); "%s: expected: load [module…]", argv[0]);
char **modules = strv_skip(argv, 2); char **modules = strv_skip(argv, 2);
if (strv_isempty(modules)) { if (modules)
STRV_FOREACH(module, modules)
(void) module_load_and_warn(ctx, *module, /* verbose = */ false);
else {
const char *modalias; const char *modalias;
r = sd_device_get_property_value(dev, "MODALIAS", &modalias); r = sd_device_get_property_value(dev, "MODALIAS", &modalias);
@ -43,9 +46,7 @@ static int builtin_kmod(UdevEvent *event, int argc, char *argv[]) {
return log_device_warning_errno(dev, r, "Failed to read property \"MODALIAS\": %m"); return log_device_warning_errno(dev, r, "Failed to read property \"MODALIAS\": %m");
(void) module_load_and_warn(ctx, modalias, /* verbose = */ false); (void) module_load_and_warn(ctx, modalias, /* verbose = */ false);
} else }
STRV_FOREACH(module, modules)
(void) module_load_and_warn(ctx, *module, /* verbose = */ false);
return 0; return 0;
} }

View File

@ -630,7 +630,7 @@ static int run(int argc, char **argv) {
} else { } else {
fd = find_source_vc(&vc, &idx); fd = find_source_vc(&vc, &idx);
if (fd < 0 && fd != -EBUSY) if (fd < 0 && fd != -EBUSY)
return log_error_errno(fd, "No usable source console found: %m"); return log_error_errno(fd, "No virtual console that can be configured found: %m");
} }
utf8 = is_locale_utf8(); utf8 = is_locale_utf8();
@ -640,7 +640,7 @@ static int run(int argc, char **argv) {
/* We found only busy VCs, which might happen during the boot process when the boot splash is /* We found only busy VCs, which might happen during the boot process when the boot splash is
* displayed on the only allocated VC. In this case we don't interfere and avoid initializing * displayed on the only allocated VC. In this case we don't interfere and avoid initializing
* the VC partially as some operations are likely to fail. */ * the VC partially as some operations are likely to fail. */
log_notice("All allocated VCs are currently busy, skipping initialization of font and keyboard settings."); log_notice("All allocated virtual consoles are busy, will not configure key mapping and font.");
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
@ -664,7 +664,7 @@ static int run(int argc, char **argv) {
setup_remaining_vcs(fd, idx, utf8); setup_remaining_vcs(fd, idx, utf8);
else else
log_full(r == EX_OSERR ? LOG_NOTICE : LOG_WARNING, log_full(r == EX_OSERR ? LOG_NOTICE : LOG_WARNING,
"Setting source virtual console failed, ignoring remaining ones."); "Configuration of first virtual console failed, ignoring remaining ones.");
} }
return IN_SET(r, 0, EX_OSERR) && keyboard_ok ? EXIT_SUCCESS : EXIT_FAILURE; return IN_SET(r, 0, EX_OSERR) && keyboard_ok ? EXIT_SUCCESS : EXIT_FAILURE;

View File

@ -3,6 +3,7 @@
integration_tests += [ integration_tests += [
integration_test_template + { integration_test_template + {
'name' : fs.name(meson.current_source_dir()), 'name' : fs.name(meson.current_source_dir()),
'coredump-exclude-regex' : '/(bash|python3.[0-9]+|systemd-executor)$',
'cmdline' : integration_test_template['cmdline'] + [ 'cmdline' : integration_test_template['cmdline'] + [
''' '''

View File

@ -4,6 +4,7 @@ integration_tests += [
integration_test_template + { integration_test_template + {
'name' : fs.name(meson.current_source_dir()), 'name' : fs.name(meson.current_source_dir()),
'unit' : files('TEST-16-EXTEND-TIMEOUT.service'), 'unit' : files('TEST-16-EXTEND-TIMEOUT.service'),
'coredump-exclude-regex' : '/(bash|sleep)$',
}, },
] ]

View File

@ -4,5 +4,6 @@ integration_tests += [
integration_test_template + { integration_test_template + {
'name' : fs.name(meson.current_source_dir()), 'name' : fs.name(meson.current_source_dir()),
'vm' : true, 'vm' : true,
'coredump-exclude-regex' : '/(sleep|udevadm)$',
}, },
] ]

View File

@ -3,5 +3,6 @@
integration_tests += [ integration_tests += [
integration_test_template + { integration_test_template + {
'name' : fs.name(meson.current_source_dir()), 'name' : fs.name(meson.current_source_dir()),
'coredump-exclude-regex' : '/(sleep|bash|systemd-notify)$',
}, },
] ]

View File

@ -4,5 +4,7 @@ integration_tests += [
integration_test_template + { integration_test_template + {
'name' : fs.name(meson.current_source_dir()), 'name' : fs.name(meson.current_source_dir()),
'priority' : 10, 'priority' : 10,
# TODO: Remove when https://github.com/systemd/systemd/issues/35335 is fixed.
'coredump-exclude-regex' : '/systemd-localed',
}, },
] ]

View File

@ -5,6 +5,7 @@ integration_tests += [
'name' : fs.name(meson.current_source_dir()), 'name' : fs.name(meson.current_source_dir()),
'storage': 'persistent', 'storage': 'persistent',
'vm' : true, 'vm' : true,
'coredump-exclude-regex' : '/(test-usr-dump|test-dump|bash)$',
}, },
] ]

View File

@ -6,6 +6,7 @@
import argparse import argparse
import json import json
import os import os
import re
import shlex import shlex
import subprocess import subprocess
import sys import sys
@ -32,6 +33,59 @@ ExecStart=false
""" """
def process_coredumps(args: argparse.Namespace, journal_file: Path) -> bool:
# Collect executable paths of all coredumps and filter out the expected ones.
if args.coredump_exclude_regex:
exclude_regex = re.compile(args.coredump_exclude_regex)
else:
exclude_regex = None
result = subprocess.run(
[
args.mkosi,
'--directory', os.fspath(args.meson_source_dir),
'--extra-search-path', os.fspath(args.meson_build_dir),
'sandbox',
'coredumpctl',
'--file', journal_file,
'--json=short',
],
stdout=subprocess.PIPE,
text=True,
) # fmt: skip
# coredumpctl returns a non-zero exit status if there are no coredumps.
if result.returncode != 0:
return False
coredumps = json.loads(result.stdout)
coredumps = [
coredump for coredump in coredumps if not exclude_regex or not exclude_regex.search(coredump['exe'])
]
if not coredumps:
return False
subprocess.run(
[
args.mkosi,
'--directory', os.fspath(args.meson_source_dir),
'--extra-search-path', os.fspath(args.meson_build_dir),
'sandbox',
'coredumpctl',
'--file', journal_file,
'--no-pager',
'info',
*(coredump['exe'] for coredump in coredumps),
],
check=True,
) # fmt: skip
return True
def main() -> None: def main() -> None:
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--mkosi', required=True) parser.add_argument('--mkosi', required=True)
@ -44,6 +98,7 @@ def main() -> None:
parser.add_argument('--slow', action=argparse.BooleanOptionalAction) parser.add_argument('--slow', action=argparse.BooleanOptionalAction)
parser.add_argument('--vm', action=argparse.BooleanOptionalAction) parser.add_argument('--vm', action=argparse.BooleanOptionalAction)
parser.add_argument('--exit-code', required=True, type=int) parser.add_argument('--exit-code', required=True, type=int)
parser.add_argument('--coredump-exclude-regex', required=True)
parser.add_argument('mkosi_args', nargs='*') parser.add_argument('mkosi_args', nargs='*')
args = parser.parse_args() args = parser.parse_args()
@ -114,7 +169,9 @@ def main() -> None:
""" """
) )
journal_file = None journal_file = (args.meson_build_dir / (f'test/journal/{name}.journal')).absolute()
journal_file.unlink(missing_ok=True)
if not sys.stderr.isatty(): if not sys.stderr.isatty():
dropin += textwrap.dedent( dropin += textwrap.dedent(
""" """
@ -122,9 +179,6 @@ def main() -> None:
FailureAction=exit FailureAction=exit
""" """
) )
journal_file = (args.meson_build_dir / (f'test/journal/{name}.journal')).absolute()
journal_file.unlink(missing_ok=True)
elif not shell: elif not shell:
dropin += textwrap.dedent( dropin += textwrap.dedent(
""" """
@ -194,44 +248,42 @@ def main() -> None:
) )
exit(77) exit(77)
if journal_file and ( coredumps = process_coredumps(args, journal_file)
keep_journal == '0' or (result.returncode in (args.exit_code, 77) and keep_journal == 'fail')
if keep_journal == '0' or (
keep_journal == 'fail' and result.returncode in (args.exit_code, 77) and not coredumps
): ):
journal_file.unlink(missing_ok=True) journal_file.unlink(missing_ok=True)
if shell or result.returncode in (args.exit_code, 77): if shell or (result.returncode in (args.exit_code, 77) and not coredumps):
exit(0 if shell or result.returncode == args.exit_code else 77) exit(0 if shell or result.returncode == args.exit_code else 77)
if journal_file: ops = []
ops = []
if os.getenv('GITHUB_ACTIONS'): if os.getenv('GITHUB_ACTIONS'):
id = os.environ['GITHUB_RUN_ID'] id = os.environ['GITHUB_RUN_ID']
iteration = os.environ['GITHUB_RUN_ATTEMPT'] iteration = os.environ['GITHUB_RUN_ATTEMPT']
j = json.loads( j = json.loads(
subprocess.run( subprocess.run(
[ [
args.mkosi, args.mkosi,
'--directory', os.fspath(args.meson_source_dir), '--directory', os.fspath(args.meson_source_dir),
'--json', '--json',
'summary', 'summary',
], ],
stdout=subprocess.PIPE, stdout=subprocess.PIPE,
text=True, text=True,
).stdout ).stdout
) # fmt: skip ) # fmt: skip
distribution = j['Images'][-1]['Distribution'] distribution = j['Images'][-1]['Distribution']
release = j['Images'][-1]['Release'] release = j['Images'][-1]['Release']
artifact = f'ci-mkosi-{id}-{iteration}-{distribution}-{release}-failed-test-journals' artifact = f'ci-mkosi-{id}-{iteration}-{distribution}-{release}-failed-test-journals'
ops += [f'gh run download {id} --name {artifact} -D ci/{artifact}'] ops += [f'gh run download {id} --name {artifact} -D ci/{artifact}']
journal_file = Path(f'ci/{artifact}/test/journal/{name}.journal') journal_file = Path(f'ci/{artifact}/test/journal/{name}.journal')
ops += [f'journalctl --file {journal_file} --no-hostname -o short-monotonic -u {args.unit} -p info'] ops += [f'journalctl --file {journal_file} --no-hostname -o short-monotonic -u {args.unit} -p info']
print( print("Test failed, relevant logs can be viewed with: \n\n" f"{(' && '.join(ops))}\n", file=sys.stderr)
"Test failed, relevant logs can be viewed with: \n\n" f"{(' && '.join(ops))}\n",
file=sys.stderr,
)
# 0 also means we failed so translate that to a non-zero exit code to mark the test as failed. # 0 also means we failed so translate that to a non-zero exit code to mark the test as failed.
exit(result.returncode or 1) exit(result.returncode or 1)

View File

@ -297,6 +297,7 @@ integration_test_template = {
'qemu-args' : [], 'qemu-args' : [],
'exit-code' : 123, 'exit-code' : 123,
'vm' : false, 'vm' : false,
'coredump-exclude-regex' : '',
} }
testdata_subdirs = [ testdata_subdirs = [
'auxv', 'auxv',
@ -391,6 +392,7 @@ foreach integration_test : integration_tests
'--storage', integration_test['storage'], '--storage', integration_test['storage'],
'--firmware', integration_test['firmware'], '--firmware', integration_test['firmware'],
'--exit-code', integration_test['exit-code'].to_string(), '--exit-code', integration_test['exit-code'].to_string(),
'--coredump-exclude-regex', integration_test['coredump-exclude-regex'],
] ]
if 'unit' in integration_test if 'unit' in integration_test

View File

@ -248,6 +248,7 @@ Bridge=mybridge
[Match] [Match]
Name=mybridge Name=mybridge
[Network] [Network]
IPv6AcceptRA=no
DNS=192.168.250.1 DNS=192.168.250.1
Address=192.168.250.33/24 Address=192.168.250.33/24
Gateway=192.168.250.1 Gateway=192.168.250.1
@ -540,6 +541,7 @@ MACAddress=12:34:56:78:9a:bc
[Match] [Match]
Name=dummy0 Name=dummy0
[Network] [Network]
IPv6AcceptRA=no
Address=192.168.42.100/24 Address=192.168.42.100/24
DNS=192.168.42.1 DNS=192.168.42.1
Domains= ~company Domains= ~company
@ -573,6 +575,7 @@ MACAddress=12:34:56:78:9a:bc
self.write_network('50-myvpn.network', '''[Match] self.write_network('50-myvpn.network', '''[Match]
Name=dummy0 Name=dummy0
[Network] [Network]
IPv6AcceptRA=no
Address=192.168.42.100/24 Address=192.168.42.100/24
DNS=192.168.42.1 DNS=192.168.42.1
Domains= ~company ~. Domains= ~company ~.
@ -927,6 +930,7 @@ cat <<EOF >/run/systemd/network/50-test.network
Name={ifr} Name={ifr}
[Network] [Network]
IPv6AcceptRA=no
Address=192.168.5.1/24 Address=192.168.5.1/24
{addr6} {addr6}
DHCPServer=yes DHCPServer=yes
@ -1006,6 +1010,7 @@ MACAddress=12:34:56:78:9a:bc
[Match] [Match]
Name=dummy0 Name=dummy0
[Network] [Network]
IPv6AcceptRA=no
Address=192.168.42.100/24 Address=192.168.42.100/24
DNS=192.168.42.1 DNS=192.168.42.1
Domains= one two three four five six seven eight nine ten Domains= one two three four five six seven eight nine ten
@ -1035,6 +1040,7 @@ MACAddress=12:34:56:78:9a:bc
[Match] [Match]
Name=dummy0 Name=dummy0
[Network] [Network]
IPv6AcceptRA=no
Address=192.168.42.100/24 Address=192.168.42.100/24
DNS=192.168.42.1 DNS=192.168.42.1
''') ''')
@ -1107,7 +1113,12 @@ class MatchClientTest(unittest.TestCase, NetworkdTestingUtilities):
def test_basic_matching(self): def test_basic_matching(self):
"""Verify the Name= line works throughout this class.""" """Verify the Name= line works throughout this class."""
self.add_veth_pair('test_if1', 'fake_if2') self.add_veth_pair('test_if1', 'fake_if2')
self.write_network('50-test.network', "[Match]\nName=test_*\n[Network]") self.write_network('50-test.network', '''\
[Match]
Name=test_*
[Network]
IPv6AcceptRA=no
''')
subprocess.check_call(['systemctl', 'start', 'systemd-networkd']) subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
self.assert_link_states(test_if1='managed', fake_if2='unmanaged') self.assert_link_states(test_if1='managed', fake_if2='unmanaged')
@ -1118,11 +1129,13 @@ class MatchClientTest(unittest.TestCase, NetworkdTestingUtilities):
mac = '00:01:02:03:98:99' mac = '00:01:02:03:98:99'
self.add_veth_pair('test_veth', 'test_peer', self.add_veth_pair('test_veth', 'test_peer',
['addr', mac], ['addr', mac]) ['addr', mac], ['addr', mac])
self.write_network('50-no-veth.network', """\ self.write_network('50-no-veth.network', '''\
[Match] [Match]
MACAddress={} MACAddress={}
Name=!nonexistent *peer* Name=!nonexistent *peer*
[Network]""".format(mac)) [Network]
IPv6AcceptRA=no
'''.format(mac))
subprocess.check_call(['systemctl', 'start', 'systemd-networkd']) subprocess.check_call(['systemctl', 'start', 'systemd-networkd'])
self.assert_link_states(test_veth='managed', test_peer='unmanaged') self.assert_link_states(test_veth='managed', test_peer='unmanaged')

View File

@ -6,6 +6,14 @@ set -o pipefail
# shellcheck source=test/units/test-control.sh # shellcheck source=test/units/test-control.sh
. "$(dirname "$0")"/test-control.sh . "$(dirname "$0")"/test-control.sh
if systemd-detect-virt --quiet --container; then
# This comes from the selinux package and tries to write
# some files under sysfs, which will be read-only in a container,
# so mask it. It's not our tmpfiles.d file anyway.
mkdir -p /run/tmpfiles.d/
ln -s /dev/null /run/tmpfiles.d/selinux-policy.conf
fi
run_subtests run_subtests
touch /testok touch /testok