Compare commits

...

53 Commits

Author SHA1 Message Date
Muhammad Nuzaihan Bin Kamal Luddin f1004d0b68
Merge 5507ec986f into a3c2a9ee5d 2024-09-19 16:39:04 +02:00
Yu Watanabe a3c2a9ee5d
Merge pull request #34486 from DaanDeMeyer/test-process-util
test-process-util: Migrate to new assertion macros
2024-09-19 23:28:15 +09:00
Daan De Meyer 062332f3db
Merge pull request #34481 from yuwata/has-tpm2
tpm2-util: several cleanups for tpm2_support()
2024-09-19 16:22:24 +02:00
Daan De Meyer bc9a9177b2
Merge pull request #34483 from yuwata/network-conf-parser-neighbor-nexthop
network: several cleanups for conf parsers
2024-09-19 13:59:56 +02:00
Daan De Meyer e5c6dcac87 test-process-util: Ignore EINVAL from setresuid() and setresgid()
If we're running in a user namespace with a single user and without
the nobody user, we'll get EINVAL from these system calls so make
sure we handle those gracefully.
2024-09-19 13:42:05 +02:00
Daan De Meyer 34a7ca6db2 test-process-util: Use FORK_REOPEN_LOG everywhere we close all fds
To make sure logging works in the child processes.
2024-09-19 13:42:05 +02:00
Daan De Meyer 397820961d test-process-util: Migrate to new assertion macros 2024-09-19 13:42:03 +02:00
Yu Watanabe 3b16e9f419 man/systemd-analyze: mention required libraries for TPM2 support
Closes #34477.
2024-09-19 19:21:08 +09:00
Yu Watanabe d5a7f3b7d4 tpm2-util: colorize output of 'systemd-analyze has-tpm2' 2024-09-19 19:14:19 +09:00
Yu Watanabe f1c16ca6d6 shell-completion/analyze: add has-tpm2 2024-09-19 19:08:49 +09:00
Yu Watanabe b094398b0f tpm2-util: update comment
has-tpm2 command is moved to systemd-analyze.

Follow-up for 58e359604f.
2024-09-19 19:08:10 +09:00
Yu Watanabe 1ee6570843 tpm2-util: do not load tpm2 libraries when not interested in the existence of the libraries
For example, 'bootctl status' only interested in if the efi has TPM2
support and a TPM2 driver is loaded. Hence, not necessary to load
libtss2.
2024-09-19 19:06:46 +09:00
Yu Watanabe b7f051c91d tpm2-util: introduce tpm2_is_fully_supported() 2024-09-19 19:04:15 +09:00
Yu Watanabe a13ead6814
Merge pull request #34479 from yuwata/sd-json-dispatch-field-table-static
tree-wide: make sd_json_dispatch_field table static
2024-09-19 18:59:17 +09:00
Yu Watanabe f901a7b39f network/nexthop: introduce generic conf parser for [NextHop] section 2024-09-19 18:41:47 +09:00
Yu Watanabe 9b01cf0406 network/nexthop: make conf parsers for Family= and Gateway= independent of each other 2024-09-19 18:41:46 +09:00
Yu Watanabe d5aae0713d network/nexthop: use log_section_warning() and friend 2024-09-19 18:40:38 +09:00
Daan De Meyer 1d8a81eb4e Add ASSERT_OK_ZERO_ERRNO() and ASSERT_OK_EQ_ERRNO() 2024-09-19 11:38:47 +02:00
Daan De Meyer 86c1317270
Merge pull request #34474 from DaanDeMeyer/user-group
Two integration test fixes
2024-09-19 09:20:03 +02:00
Daan De Meyer f4faac2073 test: Run TEST-74-AUX-UTILS in virtual machine
Various tests skip themselves when running in a container so make
sure the test runs in a virtual machine so we get full coverage.
2024-09-19 14:56:34 +09:00
Yu Watanabe 2bcc2a89f3 test: create .netdev file at last
Previously, when the test ran on mkosi, then networkd was not masked, and
might be already started. In that case, the interface test2 would be created
soon after the .netdev file is created, and the .link file would not be
applied to the interface. Hence, the later test case for
'networkctl cat @test2:link' would fail.

This make networkd always started at the beginning of the test, and
.netdev file created after .link file is created. So, .link file is
always applied to the interface created by the .netdev file.
2024-09-19 14:50:10 +09:00
Yu Watanabe 07e6a111c0 man: fix typo
Follow-up for 8aee931e7a.
2024-09-19 09:18:47 +09:00
Yu Watanabe c2648f6e23 efi: fix typo
Follow-up for f4e081051d.
2024-09-19 09:14:25 +09:00
Daan De Meyer 1d5b4317cd ci: Don't add testuser to wheel and systemd-journal groups
This breaks TEST-74-AUX-UTILS when run in a VM as the user gets access
to journal files that the test expects it can't access.
2024-09-19 08:47:53 +09:00
Yu Watanabe 8d6eedd8a3 network/neighbor: use log_section_warning_errno() 2024-09-19 04:03:11 +09:00
Yu Watanabe 91eaa90b81 network/neighbor: introduce generic Neighbor section parser 2024-09-19 03:59:34 +09:00
Yu Watanabe 3b5c5da73a network/neighbor: use struct in_addr_data 2024-09-19 03:58:28 +09:00
Yu Watanabe 1775654e2c conf-parser: drop unnecessary temporary variable 2024-09-19 03:39:15 +09:00
Yu Watanabe 0ea6d55a4b conf-parser: introduce config_parse_in_addr_data() 2024-09-19 03:38:22 +09:00
Yu Watanabe 26d35019de tree-wide: drop unnecessary 'struct' 2024-09-19 01:34:57 +09:00
Yu Watanabe b962338104 nsresource: make sd_json_dispatch_field table static
This also adds missing error check of sd_json_dispatch().

Follow-up for 54452c7b2a.
2024-09-19 01:34:57 +09:00
Yu Watanabe fae0b00434 creds-util: make sd_json_dispatch_field table static 2024-09-19 01:34:57 +09:00
Yu Watanabe f7923ef318 resolve: make sd_json_dispatch_field table static 2024-09-19 01:34:57 +09:00
Yu Watanabe 36df48d863 resolvectl: make sd_json_dispatch_field table static 2024-09-19 01:34:57 +09:00
Yu Watanabe 53c638db16 updatectl: make sd_json_dispatch_field table static
This also fixes memory leak of Version object on failure.

Follow-up for ec15bb71c2.
2024-09-19 01:34:57 +09:00
Yu Watanabe 751a247794 varlinkctl: make sd_json_dispatch_field table static 2024-09-19 01:34:56 +09:00
Yu Watanabe 07dbbda0fc ssh-generator: make sd_json_dispatch_field table static 2024-09-19 01:34:56 +09:00
Yu Watanabe ed4a6c476e machine: make sd_json_dispatch_field table static 2024-09-19 01:34:56 +09:00
Muhammad Nuzaihan Bin Kamal Luddin 5507ec986f log invalid dns type with error message 2024-09-18 01:55:35 +08:00
Muhammad Nuzaihan Bin Kamal Luddin fee8a01942 remove unneeded string variable and directly use the data 2024-09-17 18:15:35 +08:00
Muhammad Nuzaihan Bin Kamal Luddin 2e9b9408d2 change log_info to log_debug 2024-09-17 16:25:02 +08:00
Muhammad Nuzaihan Bin Kamal Luddin f8599ea6fb fix: finish up work as recommended 2024-09-17 16:23:48 +08:00
Muhammad Nuzaihan Bin Kamal Luddin 18b5e47238 remove strv.h from include in resolved-dns-stub.c so it is cleaner 2024-09-17 02:28:55 +08:00
Muhammad Nuzaihan Bin Kamal Luddin a7847d744e generate missing header files 2024-09-17 02:28:55 +08:00
Muhammad Nuzaihan Bin Kamal Luddin 04031c10f8 fix meson and make ci/cd happy 2024-09-17 02:28:55 +08:00
Muhammad Nuzaihan Bin Kamal Luddin 84831eff33 Revert "make ci/cd pipelines happy"
This reverts commit 69a6d3b193.
2024-09-17 02:28:55 +08:00
Muhammad Nuzaihan Bin Kamal Luddin a7a4b22282 make ci/cd pipelines happy 2024-09-17 02:28:55 +08:00
Muhammad Nuzaihan Bin Kamal Luddin 7f8faa1b9a remove dns-type-c 2024-09-17 02:28:55 +08:00
Muhammad Nuzaihan Bin Kamal Luddin bfed004837 do not cleanup and free Set * 2024-09-17 02:28:55 +08:00
Muhammad Nuzaihan Bin Kamal Luddin 1e79a8f8d6 Rework RecordRefuseType
* Add new configuration parser which translates configuration values to int
* Store ints in Set*
* Check value if exists in set in DNS stub when user queries
2024-09-17 02:28:55 +08:00
Muhammad Nuzaihan Bin Kamal Luddin 18e8f0f1ce remove stub 2024-09-17 02:28:55 +08:00
Muhammad Nuzaihan Bin Kamal Luddin 4d041317df rework to use RefuseRecordTypes= 2024-09-17 02:28:54 +08:00
Muhammad Nuzaihan Bin Kamal Luddin 9ea2a332c5 add an option to explicitly disable query IPv6 AAAA 2024-09-17 02:28:54 +08:00
45 changed files with 809 additions and 801 deletions

View File

@ -962,7 +962,9 @@ default ignore - -</programlisting>
discovered/supported/used, prints <literal>no</literal>. Otherwise prints
<literal>partial</literal>. In either of these two cases exits with non-zero exit status. It also shows
five lines indicating separately whether firmware, drivers, the system, the kernel and libraries
discovered/support/use TPM2.</para>
discovered/support/use TPM2. Currently, required libraries are <filename>libtss2-esys.so.0</filename>,
<filename>libtss2-rc.so.0</filename>, and <filename>libtss2-mu.so.0</filename>. The requirement may be
changed in the future release.</para>
<para>Note, this checks for TPM 2.0 devices only, and does not consider TPM 1.2 at all.</para>

View File

@ -29,7 +29,7 @@
<refsect1>
<title>Description</title>
<para><command>systemd-nsresourced</command> is a system service that permits transient delegation of a a
<para><command>systemd-nsresourced</command> is a system service that permits transient delegation of a
UID/GID range to a user namespace (see <citerefentry
project='man-pages'><refentrytitle>user_namespaces</refentrytitle><manvolnum>7</manvolnum></citerefentry>)
allocated by a client, via a Varlink IPC API.</para>

View File

@ -702,6 +702,7 @@ env = find_program('env')
rsync = find_program('rsync', required : false)
diff = find_program('diff')
find = find_program('find')
cp = find_program('cp')
ln_s = ln.full_path() + ' -frsT -- "${DESTDIR:-}@0@" "${DESTDIR:-}@1@"'

View File

@ -3,18 +3,11 @@
set -e
set -o nounset
if [[ "$DISTRIBUTION" =~ ubuntu|debian ]]; then
SUDO_GROUP=sudo
else
SUDO_GROUP=wheel
fi
useradd \
--uid 4711 \
--user-group \
--create-home \
--password "$(openssl passwd -1 testuser)" \
--groups "$SUDO_GROUP",systemd-journal \
--shell /bin/bash \
testuser

View File

@ -67,7 +67,7 @@ _systemd_analyze() {
)
local -A VERBS=(
[STANDALONE]='time blame unit-files unit-paths exit-status compare-versions calendar timestamp timespan pcrs srk'
[STANDALONE]='time blame unit-files unit-paths exit-status compare-versions calendar timestamp timespan pcrs srk has-tpm2'
[CRITICAL_CHAIN]='critical-chain'
[DOT]='dot'
[DUMP]='dump'

View File

@ -73,6 +73,7 @@ JSON or table format'
'timespan:Parse a systemd syntax timespan'
'security:Analyze security settings of a service'
'inspect-elf:Parse and print ELF package metadata'
'has-tpm2:Report whether TPM2 support is available'
# log-level, log-target, service-watchdogs have been deprecated
)

View File

@ -96,7 +96,7 @@ int verb_pcrs(int argc, char *argv[], void *userdata) {
const char *alg = NULL;
int r;
if (tpm2_support() != TPM2_SUPPORT_FULL)
if (!tpm2_is_fully_supported())
log_notice("System lacks full TPM2 support, not showing PCR state.");
else {
r = get_pcr_alg(&alg);

View File

@ -411,7 +411,6 @@ int verb_status(int argc, char *argv[], void *userdata) {
_cleanup_free_ char *fw_type = NULL, *fw_info = NULL, *loader = NULL, *loader_path = NULL, *stub = NULL, *stub_path = NULL,
*current_entry = NULL, *oneshot_entry = NULL, *default_entry = NULL;
uint64_t loader_features = 0, stub_features = 0;
Tpm2Support s;
int have;
(void) efi_get_variable_string_and_warn(EFI_LOADER_VARIABLE(LoaderFirmwareType), &fw_type);
@ -440,7 +439,7 @@ int verb_status(int argc, char *argv[], void *userdata) {
else
printf("\n");
s = tpm2_support();
Tpm2Support s = tpm2_support_full(TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER);
printf(" TPM2 Support: %s%s%s\n",
FLAGS_SET(s, TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER) ? ansi_highlight_green() :
(s & (TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER)) != 0 ? ansi_highlight_red() : ansi_highlight_yellow(),

View File

@ -450,7 +450,7 @@ static size_t pe_section_table_find_profile_length(
assert(start >= section_table);
assert(start < section_table + n_section_table);
/* Look for the next .profile (or the end of the table), this is where the the sections for this
/* Look for the next .profile (or the end of the table), this is where the sections for this
* profile end. The base profile does not start with a .profile, the others do, hence conditionally
* skip over the first entry. */
const PeSectionHeader *e;
@ -485,7 +485,7 @@ EFI_STATUS pe_locate_profile_sections(
if (!p)
return EFI_NOT_FOUND;
/* Look for the next .profile (or the end of the table), this is where the the sections for this
/* Look for the next .profile (or the end of the table), this is where the sections for this
* profile end. */
size_t n = pe_section_table_find_profile_length(section_table, n_section_table, p, profile);

View File

@ -1005,7 +1005,7 @@ static int validate_stub(void) {
bool found = false;
int r;
if (tpm2_support() != TPM2_SUPPORT_FULL)
if (!tpm2_is_fully_supported())
return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP), "Sorry, system lacks full TPM2 support.");
r = efi_stub_get_features(&features);

View File

@ -1229,7 +1229,7 @@ static int generic_method_get_interface_description(
sd_varlink_method_flags_t flags,
void *userdata) {
static const struct sd_json_dispatch_field dispatch_table[] = {
static const sd_json_dispatch_field dispatch_table[] = {
{ "interface", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, 0, SD_JSON_MANDATORY },
{}
};

View File

@ -416,19 +416,18 @@ static int list_machine_one(sd_varlink *link, Machine *m, bool more) {
}
static int vl_method_list(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
Manager *m = ASSERT_PTR(userdata);
const char *mn = NULL;
const sd_json_dispatch_field dispatch_table[] = {
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, PTR_TO_SIZE(&mn), 0 },
static const sd_json_dispatch_field dispatch_table[] = {
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, 0, 0 },
{}
};
Manager *m = ASSERT_PTR(userdata);
const char *mn = NULL;
int r;
assert(parameters);
r = sd_varlink_dispatch(link, parameters, dispatch_table, 0);
r = sd_varlink_dispatch(link, parameters, dispatch_table, &mn);
if (r != 0)
return r;

View File

@ -97,8 +97,8 @@ static int neighbor_append_json(Neighbor *n, sd_json_variant **array) {
return sd_json_variant_append_arraybo(
array,
SD_JSON_BUILD_PAIR_INTEGER("Family", n->family),
JSON_BUILD_PAIR_IN_ADDR("Destination", &n->in_addr, n->family),
SD_JSON_BUILD_PAIR_INTEGER("Family", n->dst_addr.family),
JSON_BUILD_PAIR_IN_ADDR("Destination", &n->dst_addr.address, n->dst_addr.family),
JSON_BUILD_PAIR_HW_ADDR("LinkLayerAddress", &n->ll_addr),
SD_JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(n->source)),
SD_JSON_BUILD_PAIR_STRING("ConfigState", state));
@ -168,7 +168,7 @@ static int nexthop_append_json(NextHop *n, sd_json_variant **array) {
return sd_json_variant_append_arraybo(
array,
SD_JSON_BUILD_PAIR_UNSIGNED("ID", n->id),
JSON_BUILD_PAIR_IN_ADDR_NON_NULL("Gateway", &n->gw, n->family),
JSON_BUILD_PAIR_IN_ADDR_NON_NULL("Gateway", &n->gw.address, n->family),
SD_JSON_BUILD_PAIR_UNSIGNED("Flags", n->flags),
SD_JSON_BUILD_PAIR_STRING("FlagsString", strempty(flags)),
SD_JSON_BUILD_PAIR_UNSIGNED("Protocol", n->protocol),

View File

@ -147,29 +147,29 @@ static int neighbor_dup(const Neighbor *neighbor, Neighbor **ret) {
static void neighbor_hash_func(const Neighbor *neighbor, struct siphash *state) {
assert(neighbor);
siphash24_compress_typesafe(neighbor->family, state);
siphash24_compress_typesafe(neighbor->dst_addr.family, state);
if (!IN_SET(neighbor->family, AF_INET, AF_INET6))
if (!IN_SET(neighbor->dst_addr.family, AF_INET, AF_INET6))
/* treat any other address family as AF_UNSPEC */
return;
/* Equality of neighbors are given by the destination address.
* See neigh_lookup() in the kernel. */
in_addr_hash_func(&neighbor->in_addr, neighbor->family, state);
in_addr_hash_func(&neighbor->dst_addr.address, neighbor->dst_addr.family, state);
}
static int neighbor_compare_func(const Neighbor *a, const Neighbor *b) {
int r;
r = CMP(a->family, b->family);
r = CMP(a->dst_addr.family, b->dst_addr.family);
if (r != 0)
return r;
if (!IN_SET(a->family, AF_INET, AF_INET6))
if (!IN_SET(a->dst_addr.family, AF_INET, AF_INET6))
/* treat any other address family as AF_UNSPEC */
return 0;
return memcmp(&a->in_addr, &b->in_addr, FAMILY_ADDRESS_SIZE(a->family));
return memcmp(&a->dst_addr.address, &b->dst_addr.address, FAMILY_ADDRESS_SIZE(a->dst_addr.family));
}
static int neighbor_get_request(Link *link, const Neighbor *neighbor, Request **ret) {
@ -244,7 +244,7 @@ static void log_neighbor_debug(const Neighbor *neighbor, const char *str, const
"%s %s neighbor (%s): lladdr: %s, dst: %s",
str, strna(network_config_source_to_string(neighbor->source)), strna(state),
HW_ADDR_TO_STR(&neighbor->ll_addr),
IN_ADDR_TO_STRING(neighbor->family, &neighbor->in_addr));
IN_ADDR_TO_STRING(neighbor->dst_addr.family, &neighbor->dst_addr.address));
}
static int neighbor_configure(Neighbor *neighbor, Link *link, Request *req) {
@ -261,7 +261,7 @@ static int neighbor_configure(Neighbor *neighbor, Link *link, Request *req) {
log_neighbor_debug(neighbor, "Configuring", link);
r = sd_rtnl_message_new_neigh(link->manager->rtnl, &m, RTM_NEWNEIGH,
link->ifindex, neighbor->family);
link->ifindex, neighbor->dst_addr.family);
if (r < 0)
return r;
@ -273,7 +273,7 @@ static int neighbor_configure(Neighbor *neighbor, Link *link, Request *req) {
if (r < 0)
return r;
r = netlink_message_append_in_addr_union(m, NDA_DST, neighbor->family, &neighbor->in_addr);
r = netlink_message_append_in_addr_union(m, NDA_DST, neighbor->dst_addr.family, &neighbor->dst_addr.address);
if (r < 0)
return r;
@ -338,7 +338,7 @@ static int link_request_neighbor(Link *link, const Neighbor *neighbor) {
"The link layer address length (%zu) for neighbor %s does not match with "
"the hardware address length (%zu), ignoring the setting.",
neighbor->ll_addr.length,
IN_ADDR_TO_STRING(neighbor->family, &neighbor->in_addr),
IN_ADDR_TO_STRING(neighbor->dst_addr.family, &neighbor->dst_addr.address),
link->hw_addr.length);
return 0;
}
@ -451,11 +451,11 @@ int neighbor_remove(Neighbor *neighbor, Link *link) {
log_neighbor_debug(neighbor, "Removing", link);
r = sd_rtnl_message_new_neigh(link->manager->rtnl, &m, RTM_DELNEIGH,
link->ifindex, neighbor->family);
link->ifindex, neighbor->dst_addr.family);
if (r < 0)
return log_link_error_errno(link, r, "Could not allocate RTM_DELNEIGH message: %m");
r = netlink_message_append_in_addr_union(m, NDA_DST, neighbor->family, &neighbor->in_addr);
r = netlink_message_append_in_addr_union(m, NDA_DST, neighbor->dst_addr.family, &neighbor->dst_addr.address);
if (r < 0)
return log_link_error_errno(link, r, "Could not append NDA_DST attribute: %m");
@ -593,19 +593,19 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
return log_oom();
/* First, retrieve the fundamental information about the neighbor. */
r = sd_rtnl_message_neigh_get_family(message, &tmp->family);
r = sd_rtnl_message_neigh_get_family(message, &tmp->dst_addr.family);
if (r < 0) {
log_link_warning(link, "rtnl: received neighbor message without family, ignoring.");
return 0;
}
if (tmp->family == AF_BRIDGE) /* Currently, we do not support it. */
if (tmp->dst_addr.family == AF_BRIDGE) /* Currently, we do not support it. */
return 0;
if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
log_link_debug(link, "rtnl: received neighbor message with invalid family '%i', ignoring.", tmp->family);
if (!IN_SET(tmp->dst_addr.family, AF_INET, AF_INET6)) {
log_link_debug(link, "rtnl: received neighbor message with invalid family '%i', ignoring.", tmp->dst_addr.family);
return 0;
}
r = netlink_message_read_in_addr_union(message, NDA_DST, tmp->family, &tmp->in_addr);
r = netlink_message_read_in_addr_union(message, NDA_DST, tmp->dst_addr.family, &tmp->dst_addr.address);
if (r < 0) {
log_link_warning_errno(link, r, "rtnl: received neighbor message without valid address, ignoring: %m");
return 0;
@ -660,28 +660,28 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
return 1;
}
#define log_neighbor_section(neighbor, fmt, ...) \
({ \
const Neighbor *_neighbor = (neighbor); \
log_section_warning_errno( \
_neighbor ? _neighbor->section : NULL, \
SYNTHETIC_ERRNO(EINVAL), \
fmt " Ignoring [Neighbor] section.", \
##__VA_ARGS__); \
})
static int neighbor_section_verify(Neighbor *neighbor) {
if (section_is_invalid(neighbor->section))
return -EINVAL;
if (neighbor->family == AF_UNSPEC)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: Neighbor section without Address= configured. "
"Ignoring [Neighbor] section from line %u.",
neighbor->section->filename, neighbor->section->line);
if (neighbor->dst_addr.family == AF_UNSPEC)
return log_neighbor_section(neighbor, "Neighbor section without Address= configured.");
if (neighbor->family == AF_INET6 && !socket_ipv6_is_supported())
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: Neighbor section with an IPv6 destination address configured, "
"but the kernel does not support IPv6. "
"Ignoring [Neighbor] section from line %u.",
neighbor->section->filename, neighbor->section->line);
if (neighbor->dst_addr.family == AF_INET6 && !socket_ipv6_is_supported())
return log_neighbor_section(neighbor, "Neighbor section with an IPv6 destination address configured, but the kernel does not support IPv6.");
if (neighbor->ll_addr.length == 0)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: Neighbor section without LinkLayerAddress= configured. "
"Ignoring [Neighbor] section from line %u.",
neighbor->section->filename, neighbor->section->line);
return log_neighbor_section(neighbor, "Neighbor section without LinkLayerAddress= configured.");
return 0;
}
@ -709,7 +709,7 @@ int network_drop_invalid_neighbors(Network *network) {
log_warning("%s: Duplicated neighbor settings for %s is specified at line %u and %u, "
"dropping the neighbor setting specified at line %u.",
dup->section->filename,
IN_ADDR_TO_STRING(neighbor->family, &neighbor->in_addr),
IN_ADDR_TO_STRING(neighbor->dst_addr.family, &neighbor->dst_addr.address),
neighbor->section->line,
dup->section->line, dup->section->line);
/* neighbor_detach() will drop the neighbor from neighbors_by_section. */
@ -728,7 +728,7 @@ int network_drop_invalid_neighbors(Network *network) {
}
int config_parse_neighbor_address(
int config_parse_neighbor_section(
const char *unit,
const char *filename,
unsigned line,
@ -740,76 +740,26 @@ int config_parse_neighbor_address(
void *data,
void *userdata) {
_cleanup_(neighbor_unref_or_set_invalidp) Neighbor *n = NULL;
static const ConfigSectionParser table[_NEIGHBOR_CONF_PARSER_MAX] = {
[NEIGHBOR_DESTINATION_ADDRESS] = { .parser = config_parse_in_addr_data, .ltype = 0, .offset = offsetof(Neighbor, dst_addr), },
[NEIGHBOR_LINK_LAYER_ADDRESS] = { .parser = config_parse_hw_addr, .ltype = 0, .offset = offsetof(Neighbor, ll_addr), },
};
_cleanup_(neighbor_unref_or_set_invalidp) Neighbor *neighbor = NULL;
Network *network = ASSERT_PTR(userdata);
int r;
assert(filename);
assert(section);
assert(lvalue);
assert(rvalue);
r = neighbor_new_static(network, filename, section_line, &n);
r = neighbor_new_static(network, filename, section_line, &neighbor);
if (r < 0)
return log_oom();
if (isempty(rvalue)) {
n->family = AF_UNSPEC;
n->in_addr = IN_ADDR_NULL;
TAKE_PTR(n);
return 0;
}
r = config_section_parse(table, ELEMENTSOF(table),
unit, filename, line, section, section_line, lvalue, ltype, rvalue, neighbor);
if (r <= 0) /* 0 means non-critical error, but the section will be ignored. */
return r;
r = in_addr_from_string_auto(rvalue, &n->family, &n->in_addr);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Neighbor Address is invalid, ignoring assignment: %s", rvalue);
return 0;
}
TAKE_PTR(n);
return 0;
}
int config_parse_neighbor_lladdr(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_(neighbor_unref_or_set_invalidp) Neighbor *n = NULL;
Network *network = ASSERT_PTR(userdata);
int r;
assert(filename);
assert(section);
assert(lvalue);
assert(rvalue);
r = neighbor_new_static(network, filename, section_line, &n);
if (r < 0)
return log_oom();
if (isempty(rvalue)) {
n->ll_addr = HW_ADDR_NULL;
TAKE_PTR(n);
return 0;
}
r = parse_hw_addr(rvalue, &n->ll_addr);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Neighbor %s= is invalid, ignoring assignment: %s",
lvalue, rvalue);
return 0;
}
TAKE_PTR(n);
TAKE_PTR(neighbor);
return 0;
}

View File

@ -23,8 +23,7 @@ typedef struct Neighbor {
unsigned n_ref;
int family;
union in_addr_union in_addr;
struct in_addr_data dst_addr;
struct hw_addr_data ll_addr;
} Neighbor;
@ -46,5 +45,11 @@ int manager_rtnl_process_neighbor(sd_netlink *rtnl, sd_netlink_message *message,
DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(Neighbor, neighbor);
CONFIG_PARSER_PROTOTYPE(config_parse_neighbor_address);
CONFIG_PARSER_PROTOTYPE(config_parse_neighbor_lladdr);
typedef enum NeighborConfParserType {
NEIGHBOR_DESTINATION_ADDRESS,
NEIGHBOR_LINK_LAYER_ADDRESS,
_NEIGHBOR_CONF_PARSER_MAX,
_NEIGHBOR_CONF_PARSER_INVALID = -EINVAL,
} NeighborConfParserType;
CONFIG_PARSER_PROTOTYPE(config_parse_neighbor_section);

View File

@ -173,9 +173,9 @@ Address.NetLabel, config_parse_address_section,
Address.NFTSet, config_parse_address_section, ADDRESS_NFT_SET, 0
IPv6AddressLabel.Prefix, config_parse_ipv6_address_label_section, IPV6_ADDRESS_LABEL_PREFIX, 0
IPv6AddressLabel.Label, config_parse_ipv6_address_label_section, IPV6_ADDRESS_LABEL, 0
Neighbor.Address, config_parse_neighbor_address, 0, 0
Neighbor.LinkLayerAddress, config_parse_neighbor_lladdr, 0, 0
Neighbor.MACAddress, config_parse_neighbor_lladdr, 0, 0 /* deprecated */
Neighbor.Address, config_parse_neighbor_section, NEIGHBOR_DESTINATION_ADDRESS, 0
Neighbor.LinkLayerAddress, config_parse_neighbor_section, NEIGHBOR_LINK_LAYER_ADDRESS, 0
Neighbor.MACAddress, config_parse_neighbor_section, NEIGHBOR_LINK_LAYER_ADDRESS, 0 /* deprecated */
RoutingPolicyRule.TypeOfService, config_parse_routing_policy_rule, ROUTING_POLICY_RULE_TOS, 0
RoutingPolicyRule.Priority, config_parse_routing_policy_rule, ROUTING_POLICY_RULE_PRIORITY, 0
RoutingPolicyRule.GoTo, config_parse_routing_policy_rule, ROUTING_POLICY_RULE_GOTO, 0
@ -219,12 +219,12 @@ Route.QuickAck, config_parse_route_metric_boolean,
Route.TCPCongestionControlAlgorithm, config_parse_route_metric_tcp_congestion, RTAX_CC_ALGO, 0
Route.FastOpenNoCookie, config_parse_route_metric_boolean, RTAX_FASTOPEN_NO_COOKIE, 0
Route.TTLPropagate, config_parse_warn_compat, DISABLED_LEGACY, 0
NextHop.Id, config_parse_nexthop_id, 0, 0
NextHop.Gateway, config_parse_nexthop_gateway, 0, 0
NextHop.Family, config_parse_nexthop_family, 0, 0
NextHop.OnLink, config_parse_nexthop_onlink, 0, 0
NextHop.Blackhole, config_parse_nexthop_blackhole, 0, 0
NextHop.Group, config_parse_nexthop_group, 0, 0
NextHop.Id, config_parse_nexthop_section, NEXTHOP_ID, 0
NextHop.Gateway, config_parse_nexthop_section, NEXTHOP_GATEWAY, 0
NextHop.Family, config_parse_nexthop_section, NEXTHOP_FAMILY, 0
NextHop.OnLink, config_parse_nexthop_section, NEXTHOP_ONLINK, 0
NextHop.Blackhole, config_parse_nexthop_section, NEXTHOP_BLACKHOLE, 0
NextHop.Group, config_parse_nexthop_section, NEXTHOP_GROUP, 0
DHCPv4.RequestAddress, config_parse_in_addr_non_null, AF_INET, offsetof(Network, dhcp_request_address)
DHCPv4.ClientIdentifier, config_parse_dhcp_client_identifier, 0, offsetof(Network, dhcp_client_identifier)
DHCPv4.UseDNS, config_parse_tristate, 0, offsetof(Network, dhcp_use_dns)

View File

@ -854,7 +854,7 @@ bool network_has_static_ipv6_configurations(Network *network) {
return true;
ORDERED_HASHMAP_FOREACH(neighbor, network->neighbors_by_section)
if (neighbor->family == AF_INET6)
if (neighbor->dst_addr.family == AF_INET6)
return true;
if (!hashmap_isempty(network->address_labels_by_section))

View File

@ -236,7 +236,7 @@ static int nexthop_compare_full(const NextHop *a, const NextHop *b) {
return r;
if (IN_SET(a->family, AF_INET, AF_INET6)) {
r = memcmp(&a->gw, &b->gw, FAMILY_ADDRESS_SIZE(a->family));
r = memcmp(&a->gw.address, &b->gw.address, FAMILY_ADDRESS_SIZE(a->family));
if (r != 0)
return r;
}
@ -481,7 +481,7 @@ static void log_nexthop_debug(const NextHop *nexthop, const char *str, Manager *
log_link_debug(link, "%s %s nexthop (%s): id: %"PRIu32", gw: %s, blackhole: %s, group: %s, flags: %s",
str, strna(network_config_source_to_string(nexthop->source)), strna(state),
nexthop->id,
IN_ADDR_TO_STRING(nexthop->family, &nexthop->gw),
IN_ADDR_TO_STRING(nexthop->family, &nexthop->gw.address),
yes_no(nexthop->blackhole), strna(group), strna(flags));
}
@ -627,8 +627,8 @@ static int nexthop_configure(NextHop *nexthop, Link *link, Request *req) {
if (r < 0)
return r;
if (in_addr_is_set(nexthop->family, &nexthop->gw)) {
r = netlink_message_append_in_addr_union(m, NHA_GATEWAY, nexthop->family, &nexthop->gw);
if (in_addr_is_set(nexthop->family, &nexthop->gw.address)) {
r = netlink_message_append_in_addr_union(m, NHA_GATEWAY, nexthop->family, &nexthop->gw.address);
if (r < 0)
return r;
@ -722,7 +722,7 @@ static bool nexthop_is_ready_to_configure(Link *link, const NextHop *nexthop) {
return r;
}
return gateway_is_ready(link, FLAGS_SET(nexthop->flags, RTNH_F_ONLINK), nexthop->family, &nexthop->gw);
return gateway_is_ready(link, FLAGS_SET(nexthop->flags, RTNH_F_ONLINK), nexthop->family, &nexthop->gw.address);
}
static int nexthop_process_request(Request *req, Link *link, NextHop *nexthop) {
@ -1093,9 +1093,9 @@ int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message,
(void) nexthop_update_group(nexthop, message);
if (nexthop->family != AF_UNSPEC) {
r = netlink_message_read_in_addr_union(message, NHA_GATEWAY, nexthop->family, &nexthop->gw);
r = netlink_message_read_in_addr_union(message, NHA_GATEWAY, nexthop->family, &nexthop->gw.address);
if (r == -ENODATA)
nexthop->gw = IN_ADDR_NULL;
nexthop->gw.address = IN_ADDR_NULL;
else if (r < 0)
log_debug_errno(r, "rtnl: could not get NHA_GATEWAY attribute, ignoring: %m");
}
@ -1129,66 +1129,60 @@ int manager_rtnl_process_nexthop(sd_netlink *rtnl, sd_netlink_message *message,
return 1;
}
#define log_nexthop_section(nexthop, fmt, ...) \
({ \
const NextHop *_nexthop = (nexthop); \
log_section_warning_errno( \
_nexthop ? _nexthop->section : NULL, \
SYNTHETIC_ERRNO(EINVAL), \
fmt " Ignoring [NextHop] section.", \
##__VA_ARGS__); \
})
static int nexthop_section_verify(NextHop *nh) {
if (section_is_invalid(nh->section))
return -EINVAL;
if (!nh->network->manager->manage_foreign_nexthops && nh->id == 0)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: [NextHop] section without specifying Id= is not supported "
"if ManageForeignNextHops=no is set in networkd.conf. "
"Ignoring [NextHop] section from line %u.",
nh->section->filename, nh->section->line);
return log_nexthop_section(nh, "Nexthop without specifying Id= is not supported if ManageForeignNextHops=no is set in networkd.conf.");
if (nh->family == AF_UNSPEC)
nh->family = nh->gw.family;
else if (nh->gw.family != AF_UNSPEC && nh->gw.family != nh->family)
return log_nexthop_section(nh, "Family= and Gateway= settings for nexthop contradict each other.");
assert(nh->gw.family == nh->family || nh->gw.family == AF_UNSPEC);
if (!hashmap_isempty(nh->group)) {
if (in_addr_is_set(nh->family, &nh->gw))
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: nexthop group cannot have gateway address. "
"Ignoring [NextHop] section from line %u.",
nh->section->filename, nh->section->line);
if (in_addr_is_set(nh->family, &nh->gw.address))
return log_nexthop_section(nh, "Nexthop group cannot have gateway address.");
if (nh->family != AF_UNSPEC)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: nexthop group cannot have Family= setting. "
"Ignoring [NextHop] section from line %u.",
nh->section->filename, nh->section->line);
return log_nexthop_section(nh, "Nexthop group cannot have Family= setting.");
if (nh->blackhole)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: nexthop group cannot be a blackhole. "
"Ignoring [NextHop] section from line %u.",
nh->section->filename, nh->section->line);
return log_nexthop_section(nh, "Nexthop group cannot be a blackhole.");
if (nh->onlink > 0)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: nexthop group cannot have on-link flag. "
"Ignoring [NextHop] section from line %u.",
nh->section->filename, nh->section->line);
return log_nexthop_section(nh, "Nexthop group cannot have on-link flag.");
} else if (nh->family == AF_UNSPEC)
/* When neither Family=, Gateway=, nor Group= is specified, assume IPv4. */
nh->family = AF_INET;
if (nh->blackhole) {
if (in_addr_is_set(nh->family, &nh->gw))
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: blackhole nexthop cannot have gateway address. "
"Ignoring [NextHop] section from line %u.",
nh->section->filename, nh->section->line);
if (in_addr_is_set(nh->family, &nh->gw.address))
return log_nexthop_section(nh, "Blackhole nexthop cannot have gateway address.");
if (nh->onlink > 0)
return log_warning_errno(SYNTHETIC_ERRNO(EINVAL),
"%s: blackhole nexthop cannot have on-link flag. "
"Ignoring [NextHop] section from line %u.",
nh->section->filename, nh->section->line);
return log_nexthop_section(nh, "Blackhole nexthop cannot have on-link flag.");
}
if (nh->onlink < 0 && in_addr_is_set(nh->family, &nh->gw) &&
if (nh->onlink < 0 && in_addr_is_set(nh->family, &nh->gw.address) &&
ordered_hashmap_isempty(nh->network->addresses_by_section)) {
/* If no address is configured, in most cases the gateway cannot be reachable.
* TODO: we may need to improve the condition above. */
log_warning("%s: Gateway= without static address configured. "
"Enabling OnLink= option.",
nh->section->filename);
log_section_warning(nh->section, "Nexthop with Gateway= specified, but no static address configured. Enabling OnLink= option.");
nh->onlink = true;
}
@ -1262,7 +1256,7 @@ int manager_build_nexthop_ids(Manager *manager) {
return 0;
}
int config_parse_nexthop_id(
static int config_parse_nexthop_family(
const char *unit,
const char *filename,
unsigned line,
@ -1274,261 +1268,38 @@ int config_parse_nexthop_id(
void *data,
void *userdata) {
_cleanup_(nexthop_unref_or_set_invalidp) NextHop *n = NULL;
Network *network = userdata;
uint32_t id;
int *family = ASSERT_PTR(data);
if (isempty(rvalue))
*family = AF_UNSPEC;
else if (streq(rvalue, "ipv4"))
*family = AF_INET;
else if (streq(rvalue, "ipv6"))
*family = AF_INET6;
else
return log_syntax_parse_error(unit, filename, line, 0, lvalue, rvalue);
return 1;
}
static int config_parse_nexthop_group(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
Hashmap **group = ASSERT_PTR(data);
int r;
assert(filename);
assert(section);
assert(lvalue);
assert(rvalue);
assert(data);
r = nexthop_new_static(network, filename, section_line, &n);
if (r < 0)
return log_oom();
if (isempty(rvalue)) {
n->id = 0;
TAKE_PTR(n);
return 0;
}
r = safe_atou32(rvalue, &id);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Could not parse nexthop id \"%s\", ignoring assignment: %m", rvalue);
return 0;
}
if (id == 0) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Invalid nexthop id \"%s\", ignoring assignment: %m", rvalue);
return 0;
}
n->id = id;
TAKE_PTR(n);
return 0;
}
int config_parse_nexthop_gateway(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_(nexthop_unref_or_set_invalidp) NextHop *n = NULL;
Network *network = userdata;
int r;
assert(filename);
assert(section);
assert(lvalue);
assert(rvalue);
assert(data);
r = nexthop_new_static(network, filename, section_line, &n);
if (r < 0)
return log_oom();
if (isempty(rvalue)) {
n->family = AF_UNSPEC;
n->gw = IN_ADDR_NULL;
TAKE_PTR(n);
return 0;
}
r = in_addr_from_string_auto(rvalue, &n->family, &n->gw);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
return 0;
}
TAKE_PTR(n);
return 0;
}
int config_parse_nexthop_family(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_(nexthop_unref_or_set_invalidp) NextHop *n = NULL;
Network *network = userdata;
AddressFamily a;
int r;
assert(filename);
assert(section);
assert(lvalue);
assert(rvalue);
assert(data);
r = nexthop_new_static(network, filename, section_line, &n);
if (r < 0)
return log_oom();
if (isempty(rvalue) &&
!in_addr_is_set(n->family, &n->gw)) {
/* Accept an empty string only when Gateway= is null or not specified. */
n->family = AF_UNSPEC;
TAKE_PTR(n);
return 0;
}
a = nexthop_address_family_from_string(rvalue);
if (a < 0) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Invalid %s='%s', ignoring assignment: %m", lvalue, rvalue);
return 0;
}
if (in_addr_is_set(n->family, &n->gw) &&
((a == ADDRESS_FAMILY_IPV4 && n->family == AF_INET6) ||
(a == ADDRESS_FAMILY_IPV6 && n->family == AF_INET))) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Specified family '%s' conflicts with the family of the previously specified Gateway=, "
"ignoring assignment.", rvalue);
return 0;
}
switch (a) {
case ADDRESS_FAMILY_IPV4:
n->family = AF_INET;
break;
case ADDRESS_FAMILY_IPV6:
n->family = AF_INET6;
break;
default:
assert_not_reached();
}
TAKE_PTR(n);
return 0;
}
int config_parse_nexthop_onlink(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_(nexthop_unref_or_set_invalidp) NextHop *n = NULL;
Network *network = userdata;
int r;
assert(filename);
assert(section);
assert(lvalue);
assert(rvalue);
assert(data);
r = nexthop_new_static(network, filename, section_line, &n);
if (r < 0)
return log_oom();
r = parse_tristate(rvalue, &n->onlink);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
return 0;
}
TAKE_PTR(n);
return 0;
}
int config_parse_nexthop_blackhole(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_(nexthop_unref_or_set_invalidp) NextHop *n = NULL;
Network *network = userdata;
int r;
assert(filename);
assert(section);
assert(lvalue);
assert(rvalue);
assert(data);
r = nexthop_new_static(network, filename, section_line, &n);
if (r < 0)
return log_oom();
r = parse_boolean(rvalue);
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
return 0;
}
n->blackhole = r;
TAKE_PTR(n);
return 0;
}
int config_parse_nexthop_group(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
_cleanup_(nexthop_unref_or_set_invalidp) NextHop *n = NULL;
Network *network = userdata;
int r;
assert(filename);
assert(section);
assert(lvalue);
assert(rvalue);
assert(data);
r = nexthop_new_static(network, filename, section_line, &n);
if (r < 0)
return log_oom();
if (isempty(rvalue)) {
n->group = hashmap_free_free(n->group);
TAKE_PTR(n);
return 0;
*group = hashmap_free_free(*group);
return 1;
}
for (const char *p = rvalue;;) {
@ -1538,15 +1309,10 @@ int config_parse_nexthop_group(
char *sep;
r = extract_first_word(&p, &word, NULL, 0);
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
log_syntax(unit, LOG_WARNING, filename, line, r,
"Invalid %s=, ignoring assignment: %s", lvalue, rvalue);
return 0;
}
if (r < 0)
return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
if (r == 0)
break;
return 1;
nhg = new0(struct nexthop_grp, 1);
if (!nhg)
@ -1586,7 +1352,7 @@ int config_parse_nexthop_group(
continue;
}
r = hashmap_ensure_put(&n->group, NULL, UINT32_TO_PTR(nhg->id), nhg);
r = hashmap_ensure_put(group, NULL, UINT32_TO_PTR(nhg->id), nhg);
if (r == -ENOMEM)
return log_oom();
if (r == -EEXIST) {
@ -1598,7 +1364,44 @@ int config_parse_nexthop_group(
assert(r > 0);
TAKE_PTR(nhg);
}
}
TAKE_PTR(n);
int config_parse_nexthop_section(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
static const ConfigSectionParser table[_NEXTHOP_CONF_PARSER_MAX] = {
[NEXTHOP_ID] = { .parser = config_parse_uint32, .ltype = 0, .offset = offsetof(NextHop, id), },
[NEXTHOP_GATEWAY] = { .parser = config_parse_in_addr_data, .ltype = 0, .offset = offsetof(NextHop, gw), },
[NEXTHOP_FAMILY] = { .parser = config_parse_nexthop_family, .ltype = 0, .offset = offsetof(NextHop, family), },
[NEXTHOP_ONLINK] = { .parser = config_parse_tristate, .ltype = 0, .offset = offsetof(NextHop, onlink), },
[NEXTHOP_BLACKHOLE] = { .parser = config_parse_bool, .ltype = 0, .offset = offsetof(NextHop, blackhole), },
[NEXTHOP_GROUP] = { .parser = config_parse_nexthop_group, .ltype = 0, .offset = offsetof(NextHop, group), },
};
_cleanup_(nexthop_unref_or_set_invalidp) NextHop *nexthop = NULL;
Network *network = ASSERT_PTR(userdata);
int r;
assert(filename);
r = nexthop_new_static(network, filename, section_line, &nexthop);
if (r < 0)
return log_oom();
r = config_section_parse(table, ELEMENTSOF(table),
unit, filename, line, section, section_line, lvalue, ltype, rvalue, nexthop);
if (r <= 0) /* 0 means non-critical error, but the section will be ignored. */
return r;
TAKE_PTR(nexthop);
return 0;
}

View File

@ -36,7 +36,7 @@ typedef struct NextHop {
Hashmap *group; /* NHA_GROUP */
bool blackhole; /* NHA_BLACKHOLE */
int ifindex; /* NHA_OIF */
union in_addr_union gw; /* NHA_GATEWAY */
struct in_addr_data gw; /* NHA_GATEWAY, gw.family is only used by conf parser. */
/* Only used in conf parser and nexthop_section_verify(). */
int onlink;
@ -71,9 +71,15 @@ int manager_build_nexthop_ids(Manager *manager);
DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(NextHop, nexthop);
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_id);
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_gateway);
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_family);
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_onlink);
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_blackhole);
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_group);
typedef enum NextHopConfParserType {
NEXTHOP_ID,
NEXTHOP_GATEWAY,
NEXTHOP_FAMILY,
NEXTHOP_ONLINK,
NEXTHOP_BLACKHOLE,
NEXTHOP_GROUP,
_NEXTHOP_CONF_PARSER_MAX,
_NEXTHOP_CONF_PARSER_INVALID = -EINVAL,
} NextHopConfParserType;
CONFIG_PARSER_PROTOTYPE(config_parse_nexthop_section);

View File

@ -1742,7 +1742,7 @@ static int oci_seccomp_args(const char *name, sd_json_variant *v, sd_json_dispat
int r;
JSON_VARIANT_ARRAY_FOREACH(e, v) {
static const struct sd_json_dispatch_field table[] = {
static const sd_json_dispatch_field table[] = {
{ "index", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint32, offsetof(struct scmp_arg_cmp, arg), SD_JSON_MANDATORY },
{ "value", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint64, offsetof(struct scmp_arg_cmp, datum_a), SD_JSON_MANDATORY },
{ "valueTwo", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint64, offsetof(struct scmp_arg_cmp, datum_b), 0 },

View File

@ -369,7 +369,7 @@ static int run(int argc, char *argv[]) {
event = TPM2_EVENT_PHASE;
}
if (arg_graceful && tpm2_support() != TPM2_SUPPORT_FULL) {
if (arg_graceful && !tpm2_is_fully_supported()) {
log_notice("No complete TPM2 support detected, exiting gracefully.");
return EXIT_SUCCESS;
}

View File

@ -2876,55 +2876,76 @@ static int print_answer(sd_json_variant *answer) {
return 0;
}
typedef struct MonitorQueryParams {
sd_json_variant *question;
sd_json_variant *answer;
sd_json_variant *collected_questions;
int rcode;
int error;
int ede_code;
const char *state;
const char *result;
const char *ede_msg;
} MonitorQueryParams;
static void monitor_query_params_done(MonitorQueryParams *p) {
assert(p);
sd_json_variant_unref(p->question);
sd_json_variant_unref(p->answer);
sd_json_variant_unref(p->collected_questions);
}
static void monitor_query_dump(sd_json_variant *v) {
_cleanup_(sd_json_variant_unrefp) sd_json_variant *question = NULL, *answer = NULL, *collected_questions = NULL;
int rcode = -1, error = 0, ede_code = -1;
const char *state = NULL, *result = NULL, *ede_msg = NULL;
assert(v);
sd_json_dispatch_field dispatch_table[] = {
{ "question", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, PTR_TO_SIZE(&question), SD_JSON_MANDATORY },
{ "answer", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, PTR_TO_SIZE(&answer), 0 },
{ "collectedQuestions", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, PTR_TO_SIZE(&collected_questions), 0 },
{ "state", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, PTR_TO_SIZE(&state), SD_JSON_MANDATORY },
{ "result", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, PTR_TO_SIZE(&result), 0 },
{ "rcode", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, PTR_TO_SIZE(&rcode), 0 },
{ "errno", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, PTR_TO_SIZE(&error), 0 },
{ "extendedDNSErrorCode", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, PTR_TO_SIZE(&ede_code), 0 },
{ "extendedDNSErrorMessage", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, PTR_TO_SIZE(&ede_msg), 0 },
static const sd_json_dispatch_field dispatch_table[] = {
{ "question", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, offsetof(MonitorQueryParams, question), SD_JSON_MANDATORY },
{ "answer", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, offsetof(MonitorQueryParams, answer), 0 },
{ "collectedQuestions", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, offsetof(MonitorQueryParams, collected_questions), 0 },
{ "state", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(MonitorQueryParams, state), SD_JSON_MANDATORY },
{ "result", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(MonitorQueryParams, result), 0 },
{ "rcode", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(MonitorQueryParams, rcode), 0 },
{ "errno", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(MonitorQueryParams, error), 0 },
{ "extendedDNSErrorCode", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(MonitorQueryParams, ede_code), 0 },
{ "extendedDNSErrorMessage", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(MonitorQueryParams, ede_msg), 0 },
{}
};
if (sd_json_dispatch(v, dispatch_table, SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS, NULL) < 0)
_cleanup_(monitor_query_params_done) MonitorQueryParams p = {
.rcode = -1,
.ede_code = -1,
};
assert(v);
if (sd_json_dispatch(v, dispatch_table, SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS, &p) < 0)
return;
/* First show the current question */
print_question('Q', ansi_highlight_cyan(), question);
print_question('Q', ansi_highlight_cyan(), p.question);
/* And then show the questions that led to this one in case this was a CNAME chain */
print_question('C', ansi_highlight_grey(), collected_questions);
print_question('C', ansi_highlight_grey(), p.collected_questions);
printf("%s%s S%s: %s",
streq_ptr(state, "success") ? ansi_highlight_green() : ansi_highlight_red(),
streq_ptr(p.state, "success") ? ansi_highlight_green() : ansi_highlight_red(),
special_glyph(SPECIAL_GLYPH_ARROW_LEFT),
ansi_normal(),
strna(streq_ptr(state, "errno") ? errno_to_name(error) :
streq_ptr(state, "rcode-failure") ? dns_rcode_to_string(rcode) :
state));
strna(streq_ptr(p.state, "errno") ? errno_to_name(p.error) :
streq_ptr(p.state, "rcode-failure") ? dns_rcode_to_string(p.rcode) :
p.state));
if (!isempty(result))
printf(": %s", result);
if (!isempty(p.result))
printf(": %s", p.result);
if (ede_code >= 0)
if (p.ede_code >= 0)
printf(" (%s%s%s)",
FORMAT_DNS_EDE_RCODE(ede_code),
!isempty(ede_msg) ? ": " : "",
strempty(ede_msg));
FORMAT_DNS_EDE_RCODE(p.ede_code),
!isempty(p.ede_msg) ? ": " : "",
strempty(p.ede_msg));
puts("");
print_answer(answer);
print_answer(p.answer);
}
static int monitor_reply(

View File

@ -414,3 +414,61 @@ int manager_parse_config_file(Manager *m) {
return 0;
}
int config_parse_refuse_record_types(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
Manager *m = ASSERT_PTR(userdata);
int r;
assert(filename);
assert(lvalue);
assert(rvalue);
if (isempty(rvalue)) {
data = mfree(data);
return 1;
}
r = free_and_strdup_warn(data, empty_to_null(rvalue));
if (r < 0)
return r;
char* record_type_string;
int refused_record_type;
/* Get int values of DNS type for example "AAAA" string to get int value and store in Set */
Set *refused_records = NULL;
for (;;) {
r = extract_first_word(data, &record_type_string, ",", 0);
if (r < 0)
return r;
if (r == 0)
break;
refused_record_type = dns_type_from_string(record_type_string);
/* log error of invalid dns type */
if (refused_record_type == _DNS_TYPE_INVALID)
log_error("dns type is invalid");
r = set_ensure_put(&refused_records, NULL, INT_TO_PTR(refused_record_type));
if (r == -ENOMEM)
return log_oom();
}
m->refuse_record_types = refused_records;
return 1;
}

View File

@ -480,6 +480,14 @@ int dns_query_new(
assert(m);
/* Check for records that is refused and refuse query for the records if matched in configuration */
DNS_QUESTION_FOREACH(key, question_utf8) {
if (set_contains(m->refuse_record_types, INT_TO_PTR(key->type))) {
log_debug("Got request for %s record that is refused.", dns_type_to_string(key->type));
return -ENOSYS;
}
}
if (question_bypass) {
/* It's either a "bypass" query, or a regular one, but can't be both. */
if (question_utf8 || question_idna)

View File

@ -2145,26 +2145,31 @@ int dns_resource_key_to_json(DnsResourceKey *key, sd_json_variant **ret) {
}
int dns_resource_key_from_json(sd_json_variant *v, DnsResourceKey **ret) {
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
uint16_t type = 0, class = 0;
const char *name = NULL;
int r;
struct params {
uint16_t type;
uint16_t class;
const char *name;
};
sd_json_dispatch_field dispatch_table[] = {
{ "class", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint16, PTR_TO_SIZE(&class), SD_JSON_MANDATORY },
{ "type", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint16, PTR_TO_SIZE(&type), SD_JSON_MANDATORY },
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, PTR_TO_SIZE(&name), SD_JSON_MANDATORY },
static const sd_json_dispatch_field dispatch_table[] = {
{ "class", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint16, offsetof(struct params, class), SD_JSON_MANDATORY },
{ "type", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint16, offsetof(struct params, type), SD_JSON_MANDATORY },
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(struct params, name), SD_JSON_MANDATORY },
{}
};
_cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;
struct params p;
int r;
assert(v);
assert(ret);
r = sd_json_dispatch(v, dispatch_table, 0, NULL);
r = sd_json_dispatch(v, dispatch_table, 0, &p);
if (r < 0)
return r;
key = dns_resource_key_new(class, type, name);
key = dns_resource_key_new(p.class, p.type, p.name);
if (!key)
return -ENOMEM;

View File

@ -992,6 +992,13 @@ static void dns_stub_process_query(Manager *m, DnsStubListenerExtra *l, DnsStrea
SD_RESOLVED_NO_SEARCH|
(DNS_PACKET_DO(p) ? SD_RESOLVED_REQUIRE_PRIMARY : 0)|
SD_RESOLVED_CLAMP_TTL);
/* Refuse query if there is -ENOSYS */
if (r == -ENOSYS) {
dns_stub_send_failure(m, l, s, p, DNS_RCODE_REFUSED, false);
return;
}
if (r < 0) {
log_error_errno(r, "Failed to generate query object: %m");
dns_stub_send_failure(m, l, s, p, DNS_RCODE_SERVFAIL, false);

View File

@ -33,3 +33,4 @@ Resolve.ResolveUnicastSingleLabel, config_parse_bool, 0,
Resolve.DNSStubListenerExtra, config_parse_dns_stub_listener_extra, 0, offsetof(Manager, dns_extra_stub_listeners)
Resolve.CacheFromLocalhost, config_parse_bool, 0, offsetof(Manager, cache_from_localhost)
Resolve.StaleRetentionSec, config_parse_sec, 0, offsetof(Manager, stale_retention_usec)
Resolve.RefuseRecordTypes, config_parse_refuse_record_types, 0, offsetof(Manager, refuse_record_types)

View File

@ -137,6 +137,9 @@ struct Manager {
struct stat etc_hosts_stat;
bool read_etc_hosts;
/* List of refused DNS Record Types*/
Set *refuse_record_types;
OrderedSet *dns_extra_stub_listeners;
/* Local DNS stub on 127.0.0.53:53 */

View File

@ -35,3 +35,4 @@
#ReadEtcHosts=yes
#ResolveUnicastSingleLabel=no
#StaleRetentionSec=0
#RefuseRecordTypes=

View File

@ -667,7 +667,7 @@ static int has_tpm2(void) {
*
* Note that we don't check if we ourselves are built with TPM2 support here! */
return FLAGS_SET(tpm2_support(), TPM2_SUPPORT_SUBSYSTEM|TPM2_SUPPORT_FIRMWARE);
return FLAGS_SET(tpm2_support_full(TPM2_SUPPORT_SUBSYSTEM|TPM2_SUPPORT_FIRMWARE), TPM2_SUPPORT_SUBSYSTEM|TPM2_SUPPORT_FIRMWARE);
}
static int condition_test_security(Condition *c, char **env) {

View File

@ -1764,7 +1764,7 @@ int config_parse_hw_addr(
void *data,
void *userdata) {
struct hw_addr_data a, *hwaddr = ASSERT_PTR(data);
struct hw_addr_data *hwaddr = ASSERT_PTR(data);
int r;
assert(filename);
@ -1776,11 +1776,10 @@ int config_parse_hw_addr(
return 1;
}
r = parse_hw_addr_full(rvalue, ltype, &a);
r = parse_hw_addr_full(rvalue, ltype, hwaddr);
if (r < 0)
return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
*hwaddr = a;
return 1;
}
@ -1973,6 +1972,36 @@ int config_parse_in_addr_non_null(
return 1;
}
int config_parse_in_addr_data(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
struct in_addr_data *p = ASSERT_PTR(data);
int r;
assert(filename);
assert(lvalue);
if (isempty(rvalue)) {
*p = (struct in_addr_data) {};
return 1;
}
r = in_addr_from_string_auto(rvalue, &p->family, &p->address);
if (r < 0)
return log_syntax_parse_error(unit, filename, line, r, lvalue, rvalue);
return 1;
}
int config_parse_unsigned_bounded(
const char *unit,
const char *filename,

View File

@ -278,6 +278,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_uint32_invert_flag);
CONFIG_PARSER_PROTOTYPE(config_parse_id128);
CONFIG_PARSER_PROTOTYPE(config_parse_tristate);
CONFIG_PARSER_PROTOTYPE(config_parse_string);
CONFIG_PARSER_PROTOTYPE(config_parse_refuse_record_types);
CONFIG_PARSER_PROTOTYPE(config_parse_dns_name);
CONFIG_PARSER_PROTOTYPE(config_parse_hostname);
CONFIG_PARSER_PROTOTYPE(config_parse_path);
@ -304,6 +305,7 @@ CONFIG_PARSER_PROTOTYPE(config_parse_hw_addrs);
CONFIG_PARSER_PROTOTYPE(config_parse_ether_addr);
CONFIG_PARSER_PROTOTYPE(config_parse_ether_addrs);
CONFIG_PARSER_PROTOTYPE(config_parse_in_addr_non_null);
CONFIG_PARSER_PROTOTYPE(config_parse_in_addr_data);
CONFIG_PARSER_PROTOTYPE(config_parse_percent);
CONFIG_PARSER_PROTOTYPE(config_parse_permyriad);
CONFIG_PARSER_PROTOTYPE(config_parse_pid);

View File

@ -886,7 +886,7 @@ int encrypt_credential_and_warn(
* container tpm2_support will detect this, and will return a different flag combination of
* TPM2_SUPPORT_FULL, effectively skipping the use of TPM2 when inside one. */
try_tpm2 = tpm2_support() == TPM2_SUPPORT_FULL;
try_tpm2 = tpm2_is_fully_supported();
if (!try_tpm2)
log_debug("System lacks TPM2 support or running in a container, not attempting to use TPM2.");
} else
@ -1582,14 +1582,12 @@ int ipc_encrypt_credential(const char *name, usec_t timestamp, usec_t not_after,
return log_error_errno(sd_varlink_error_to_errno(error_id, reply), "Failed to encrypt: %s", error_id);
}
r = sd_json_dispatch(
reply,
(const sd_json_dispatch_field[]) {
{ "blob", SD_JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, PTR_TO_SIZE(ret), SD_JSON_MANDATORY },
{},
},
SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS,
/* userdata= */ NULL);
static const sd_json_dispatch_field dispatch_table[] = {
{ "blob", SD_JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, 0, SD_JSON_MANDATORY },
{},
};
r = sd_json_dispatch(reply, dispatch_table, SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS, ret);
if (r < 0)
return r;
@ -1649,14 +1647,12 @@ int ipc_decrypt_credential(const char *validate_name, usec_t validate_timestamp,
return log_error_errno(sd_varlink_error_to_errno(error_id, reply), "Failed to decrypt: %s", error_id);
}
r = sd_json_dispatch(
reply,
(const sd_json_dispatch_field[]) {
{ "data", SD_JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, PTR_TO_SIZE(ret), SD_JSON_MANDATORY },
{},
},
SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS,
/* userdata= */ NULL);
static const sd_json_dispatch_field dispatch_table[] = {
{ "data", SD_JSON_VARIANT_STRING, json_dispatch_unbase64_iovec, 0, SD_JSON_MANDATORY },
{},
};
r = sd_json_dispatch(reply, dispatch_table, SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS, ret);
if (r < 0)
return r;

View File

@ -250,6 +250,18 @@ int nsresource_add_cgroup(int userns_fd, int cgroup_fd) {
return 1;
}
typedef struct InterfaceParams {
char *host_interface_name;
char *namespace_interface_name;
} InterfaceParams;
static void interface_params_done(InterfaceParams *p) {
assert(p);
free(p->host_interface_name);
free(p->namespace_interface_name);
}
int nsresource_add_netif(
int userns_fd,
int netns_fd,
@ -313,20 +325,20 @@ int nsresource_add_netif(
if (error_id)
return log_debug_errno(sd_varlink_error_to_errno(error_id, reply), "Failed to add network to user namespace: %s", error_id);
_cleanup_free_ char *host_interface_name = NULL, *namespace_interface_name = NULL;
r = sd_json_dispatch(
reply,
(const sd_json_dispatch_field[]) {
{ "hostInterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, PTR_TO_SIZE(&host_interface_name) },
{ "namespaceInterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, PTR_TO_SIZE(&namespace_interface_name) },
},
SD_JSON_ALLOW_EXTENSIONS,
/* userdata= */ NULL);
static const sd_json_dispatch_field dispatch_table[] = {
{ "hostInterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(InterfaceParams, host_interface_name), 0 },
{ "namespaceInterfaceName", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(InterfaceParams, namespace_interface_name), 0 },
};
_cleanup_(interface_params_done) InterfaceParams p = {};
r = sd_json_dispatch(reply, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &p);
if (r < 0)
return r;
if (ret_host_ifname)
*ret_host_ifname = TAKE_PTR(host_interface_name);
*ret_host_ifname = TAKE_PTR(p.host_interface_name);
if (ret_namespace_ifname)
*ret_namespace_ifname = TAKE_PTR(namespace_interface_name);
*ret_namespace_ifname = TAKE_PTR(p.namespace_interface_name);
return 1;
}

View File

@ -281,6 +281,44 @@ static inline int run_test_table(void) {
} \
})
#define ASSERT_OK_ZERO_ERRNO(expr) \
({ \
typeof(expr) _result = (expr); \
if (_result < 0) { \
log_error_errno(errno, "%s:%i: Assertion failed: expected \"%s\" to succeed but got the following error: %m", \
PROJECT_FILE, __LINE__, #expr); \
abort(); \
} \
if (_result != 0) { \
char _sexpr[DECIMAL_STR_MAX(typeof(expr))]; \
xsprintf(_sexpr, DECIMAL_STR_FMT(_result), _result); \
log_error("%s:%i: Assertion failed: expected \"%s\" to be zero, but it is %s.", \
PROJECT_FILE, __LINE__, #expr, _sexpr); \
abort(); \
} \
})
#define ASSERT_OK_EQ_ERRNO(expr1, expr2) \
({ \
typeof(expr1) _expr1 = (expr1); \
typeof(expr2) _expr2 = (expr2); \
if (_expr1 < 0) { \
log_error_errno(errno, "%s:%i: Assertion failed: expected \"%s\" to succeed but got the following error: %m", \
PROJECT_FILE, __LINE__, #expr1); \
abort(); \
} \
if (_expr1 != _expr2) { \
char _sexpr1[DECIMAL_STR_MAX(typeof(expr1))]; \
char _sexpr2[DECIMAL_STR_MAX(typeof(expr2))]; \
xsprintf(_sexpr1, DECIMAL_STR_FMT(_expr1), _expr1); \
xsprintf(_sexpr2, DECIMAL_STR_FMT(_expr2), _expr2); \
log_error("%s:%i: Assertion failed: expected \"%s == %s\", but %s != %s", \
PROJECT_FILE, __LINE__, #expr1, #expr2, _sexpr1, _sexpr2); \
abort(); \
} \
})
#define ASSERT_FAIL(expr) \
({ \
typeof(expr) _result = (expr); \

View File

@ -3,6 +3,7 @@
#include <sys/file.h>
#include "alloc-util.h"
#include "ansi-color.h"
#include "constants.h"
#include "creds-util.h"
#include "cryptsetup-util.h"
@ -7872,11 +7873,11 @@ int tpm2_sym_mode_from_string(const char *mode) {
return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Unknown symmetric mode name '%s'", mode);
}
Tpm2Support tpm2_support(void) {
Tpm2Support tpm2_support_full(Tpm2Support mask) {
Tpm2Support support = TPM2_SUPPORT_NONE;
int r;
if (detect_container() <= 0) {
if (((mask & (TPM2_SUPPORT_SUBSYSTEM|TPM2_SUPPORT_DRIVER)) != 0) && detect_container() <= 0) {
/* Check if there's a /dev/tpmrm* device via sysfs. If we run in a container we likely just
* got the host sysfs mounted. Since devices are generally not virtualized for containers,
* let's assume containers never have a TPM, at least for now. */
@ -7893,18 +7894,24 @@ Tpm2Support tpm2_support(void) {
support |= TPM2_SUPPORT_SUBSYSTEM;
}
if (efi_has_tpm2())
if (FLAGS_SET(mask, TPM2_SUPPORT_FIRMWARE) && efi_has_tpm2())
support |= TPM2_SUPPORT_FIRMWARE;
#if HAVE_TPM2
support |= TPM2_SUPPORT_SYSTEM;
r = dlopen_tpm2();
if (r >= 0)
support |= TPM2_SUPPORT_LIBRARIES;
if (FLAGS_SET(mask, TPM2_SUPPORT_LIBRARIES)) {
r = dlopen_tpm2();
if (r >= 0)
support |= TPM2_SUPPORT_LIBRARIES;
}
#endif
return support;
return support & mask;
}
static void print_field(const char *s, bool supported) {
printf("%s%s%s%s\n", supported ? ansi_green() : ansi_red(), plus_minus(supported), s, ansi_normal());
}
int verb_has_tpm2_generic(bool quiet) {
@ -7914,22 +7921,17 @@ int verb_has_tpm2_generic(bool quiet) {
if (!quiet) {
if (s == TPM2_SUPPORT_FULL)
puts("yes");
printf("%syes%s\n", ansi_green(), ansi_normal());
else if (s == TPM2_SUPPORT_NONE)
puts("no");
printf("%sno%s\n", ansi_red(), ansi_normal());
else
puts("partial");
printf("%spartial%s\n", ansi_yellow(), ansi_normal());
printf("%sfirmware\n"
"%sdriver\n"
"%ssystem\n"
"%ssubsystem\n"
"%slibraries\n",
plus_minus(s & TPM2_SUPPORT_FIRMWARE),
plus_minus(s & TPM2_SUPPORT_DRIVER),
plus_minus(s & TPM2_SUPPORT_SYSTEM),
plus_minus(s & TPM2_SUPPORT_SUBSYSTEM),
plus_minus(s & TPM2_SUPPORT_LIBRARIES));
print_field("firmware", FLAGS_SET(s, TPM2_SUPPORT_FIRMWARE));
print_field("driver", FLAGS_SET(s, TPM2_SUPPORT_DRIVER));
print_field("system", FLAGS_SET(s, TPM2_SUPPORT_SYSTEM));
print_field("subsystem", FLAGS_SET(s, TPM2_SUPPORT_SUBSYSTEM));
print_field("libraries", FLAGS_SET(s, TPM2_SUPPORT_LIBRARIES));
}
/* Return inverted bit flags. So that TPM2_SUPPORT_FULL becomes EXIT_SUCCESS and the other values

View File

@ -450,8 +450,8 @@ typedef struct {
} systemd_tpm2_plugin_params;
typedef enum Tpm2Support {
/* NOTE! The systemd-creds tool returns these flags 1:1 as exit status. Hence these flags are pretty
* much ABI! Hence, be extra careful when changing/extending these definitions. */
/* NOTE! The systemd-analyze has-tpm2 command returns these flags 1:1 as exit status. Hence these
* flags are pretty much ABI! Hence, be extra careful when changing/extending these definitions. */
TPM2_SUPPORT_NONE = 0, /* no support */
TPM2_SUPPORT_FIRMWARE = 1 << 0, /* firmware reports TPM2 was used */
TPM2_SUPPORT_DRIVER = 1 << 1, /* the kernel has a driver loaded for it */
@ -461,7 +461,13 @@ typedef enum Tpm2Support {
TPM2_SUPPORT_FULL = TPM2_SUPPORT_FIRMWARE|TPM2_SUPPORT_DRIVER|TPM2_SUPPORT_SYSTEM|TPM2_SUPPORT_SUBSYSTEM|TPM2_SUPPORT_LIBRARIES,
} Tpm2Support;
Tpm2Support tpm2_support(void);
Tpm2Support tpm2_support_full(Tpm2Support mask);
static inline Tpm2Support tpm2_support(void) {
return tpm2_support_full(TPM2_SUPPORT_FULL);
}
static inline bool tpm2_is_fully_supported(void) {
return tpm2_support() == TPM2_SUPPORT_FULL;
}
int verb_has_tpm2_generic(bool quiet);

View File

@ -161,12 +161,12 @@ static int process_machine(const char *machine, const char *port) {
uint32_t cid = VMADDR_CID_ANY;
const sd_json_dispatch_field dispatch_table[] = {
{ "vSockCid", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint32, PTR_TO_SIZE(&cid), 0 },
static const sd_json_dispatch_field dispatch_table[] = {
{ "vSockCid", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint32, 0, 0 },
{}
};
r = sd_json_dispatch(result, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, NULL);
r = sd_json_dispatch(result, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &cid);
if (r < 0)
return log_error_errno(r, "Failed to parse Varlink reply: %m");

View File

@ -321,12 +321,27 @@ static int list_targets(sd_bus *bus) {
return table_print_with_pager(table, SD_JSON_FORMAT_OFF, arg_pager_flags, arg_legend);
}
typedef struct DescribeParams {
Version v;
sd_json_variant *contents_json;
bool newest;
bool available;
bool installed;
bool obsolete;
bool protected;
bool incomplete;
} DescribeParams;
static void describe_params_done(DescribeParams *p) {
assert(p);
version_done(&p->v);
sd_json_variant_unref(p->contents_json);
}
static int parse_describe(sd_bus_message *reply, Version *ret) {
Version v = {};
char *version_json = NULL;
_cleanup_(sd_json_variant_unrefp) sd_json_variant *json = NULL, *contents_json = NULL;
bool newest = false, available = false, installed = false, obsolete = false, protected = false,
incomplete = false;
_cleanup_(sd_json_variant_unrefp) sd_json_variant *json = NULL;
int r;
assert(reply);
@ -342,36 +357,37 @@ static int parse_describe(sd_bus_message *reply, Version *ret) {
assert(sd_json_variant_is_object(json));
r = sd_json_dispatch(json,
(const sd_json_dispatch_field[]) {
{ "version", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, PTR_TO_SIZE(&v.version), 0 },
{ "newest", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, PTR_TO_SIZE(&newest), 0 },
{ "available", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, PTR_TO_SIZE(&available), 0 },
{ "installed", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, PTR_TO_SIZE(&installed), 0 },
{ "obsolete", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, PTR_TO_SIZE(&obsolete), 0 },
{ "protected", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, PTR_TO_SIZE(&protected), 0 },
{ "incomplete", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, PTR_TO_SIZE(&incomplete), 0 },
{ "changelog_urls", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, PTR_TO_SIZE(&v.changelog), 0 },
{ "contents", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, PTR_TO_SIZE(&contents_json), 0 },
{},
},
SD_JSON_ALLOW_EXTENSIONS,
/* userdata= */ NULL);
static const sd_json_dispatch_field dispatch_table[] = {
{ "version", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DescribeParams, v.version), 0 },
{ "newest", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, newest), 0 },
{ "available", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, available), 0 },
{ "installed", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, installed), 0 },
{ "obsolete", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, obsolete), 0 },
{ "protected", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, protected), 0 },
{ "incomplete", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(DescribeParams, incomplete), 0 },
{ "changelog_urls", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, offsetof(DescribeParams, v.changelog), 0 },
{ "contents", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant, offsetof(DescribeParams, contents_json), 0 },
{},
};
_cleanup_(describe_params_done) DescribeParams p = {};
r = sd_json_dispatch(json, dispatch_table, SD_JSON_ALLOW_EXTENSIONS, &p);
if (r < 0)
return log_error_errno(r, "Failed to parse JSON: %m");
SET_FLAG(v.flags, UPDATE_NEWEST, newest);
SET_FLAG(v.flags, UPDATE_AVAILABLE, available);
SET_FLAG(v.flags, UPDATE_INSTALLED, installed);
SET_FLAG(v.flags, UPDATE_OBSOLETE, obsolete);
SET_FLAG(v.flags, UPDATE_PROTECTED, protected);
SET_FLAG(v.flags, UPDATE_INCOMPLETE, incomplete);
SET_FLAG(p.v.flags, UPDATE_NEWEST, p.newest);
SET_FLAG(p.v.flags, UPDATE_AVAILABLE, p.available);
SET_FLAG(p.v.flags, UPDATE_INSTALLED, p.installed);
SET_FLAG(p.v.flags, UPDATE_OBSOLETE, p.obsolete);
SET_FLAG(p.v.flags, UPDATE_PROTECTED, p.protected);
SET_FLAG(p.v.flags, UPDATE_INCOMPLETE, p.incomplete);
r = sd_json_variant_format(contents_json, 0, &v.contents_json);
r = sd_json_variant_format(p.contents_json, 0, &p.v.contents_json);
if (r < 0)
return log_error_errno(r, "Failed to format JSON for contents: %m");
*ret = TAKE_STRUCT(v);
*ret = TAKE_STRUCT(p.v);
return 0;
}

View File

@ -1141,6 +1141,18 @@ TEST(ASSERT) {
ASSERT_SIGNAL(ASSERT_OK_ERRNO(-1), SIGABRT);
ASSERT_SIGNAL(ASSERT_OK_ERRNO(-ENOANO), SIGABRT);
ASSERT_OK_ZERO_ERRNO(0);
ASSERT_SIGNAL(ASSERT_OK_ZERO_ERRNO(1), SIGABRT);
ASSERT_SIGNAL(ASSERT_OK_ZERO_ERRNO(255), SIGABRT);
ASSERT_SIGNAL(ASSERT_OK_ZERO_ERRNO(-1), SIGABRT);
ASSERT_SIGNAL(ASSERT_OK_ZERO_ERRNO(-ENOANO), SIGABRT);
ASSERT_OK_EQ_ERRNO(0, 0);
ASSERT_SIGNAL(ASSERT_OK_EQ_ERRNO(1, 0), SIGABRT);
ASSERT_SIGNAL(ASSERT_OK_EQ_ERRNO(255, 5), SIGABRT);
ASSERT_SIGNAL(ASSERT_OK_EQ_ERRNO(-1, 0), SIGABRT);
ASSERT_SIGNAL(ASSERT_OK_EQ_ERRNO(-ENOANO, 0), SIGABRT);
ASSERT_FAIL(-ENOENT);
ASSERT_FAIL(-EPERM);
ASSERT_SIGNAL(ASSERT_FAIL(0), SIGABRT);

View File

@ -54,46 +54,51 @@ static void test_pid_get_comm_one(pid_t pid) {
xsprintf(path, "/proc/"PID_FMT"/comm", pid);
if (stat(path, &st) == 0) {
assert_se(pid_get_comm(pid, &a) >= 0);
ASSERT_OK(pid_get_comm(pid, &a));
log_info("PID"PID_FMT" comm: '%s'", pid, a);
} else
log_warning("%s not exist.", path);
assert_se(pid_get_cmdline(pid, 0, PROCESS_CMDLINE_COMM_FALLBACK, &c) >= 0);
ASSERT_OK(pid_get_cmdline(pid, 0, PROCESS_CMDLINE_COMM_FALLBACK, &c));
log_info("PID"PID_FMT" cmdline: '%s'", pid, c);
assert_se(pid_get_cmdline(pid, 8, 0, &d) >= 0);
ASSERT_OK(pid_get_cmdline(pid, 8, 0, &d));
log_info("PID"PID_FMT" cmdline truncated to 8: '%s'", pid, d);
free(d);
assert_se(pid_get_cmdline(pid, 1, 0, &d) >= 0);
ASSERT_OK(pid_get_cmdline(pid, 1, 0, &d));
log_info("PID"PID_FMT" cmdline truncated to 1: '%s'", pid, d);
r = get_process_ppid(pid, &e);
assert_se(pid == 1 ? r == -EADDRNOTAVAIL : r >= 0);
if (pid == 1)
ASSERT_ERROR(r, EADDRNOTAVAIL);
else
ASSERT_OK(r);
if (r >= 0) {
log_info("PID"PID_FMT" PPID: "PID_FMT, pid, e);
assert_se(e > 0);
ASSERT_GT(e, 0);
}
assert_se(pid_is_kernel_thread(pid) == 0 || pid != 1);
ASSERT_TRUE(pid_is_kernel_thread(pid) == 0 || pid != 1);
r = get_process_exe(pid, &f);
assert_se(r >= 0 || r == -EACCES);
if (r != -EACCES)
ASSERT_OK(r);
log_info("PID"PID_FMT" exe: '%s'", pid, strna(f));
assert_se(pid_get_uid(pid, &u) == 0);
ASSERT_OK_ZERO(pid_get_uid(pid, &u));
log_info("PID"PID_FMT" UID: "UID_FMT, pid, u);
assert_se(get_process_gid(pid, &g) == 0);
ASSERT_OK_ZERO(get_process_gid(pid, &g));
log_info("PID"PID_FMT" GID: "GID_FMT, pid, g);
r = get_process_environ(pid, &env);
assert_se(r >= 0 || r == -EACCES);
if (r != -EACCES)
ASSERT_OK(r);
log_info("PID"PID_FMT" strlen(environ): %zi", pid, env ? (ssize_t)strlen(env) : (ssize_t)-errno);
if (!detect_container())
assert_se(get_ctty_devnr(pid, &h) == -ENXIO || pid != 1);
if (!detect_container() && pid == 1)
ASSERT_ERROR(get_ctty_devnr(pid, &h), ENXIO);
(void) getenv_for_pid(pid, "PATH", &i);
log_info("PID"PID_FMT" $PATH: '%s'", pid, strna(i));
@ -136,14 +141,14 @@ static void test_pid_get_cmdline_one(pid_t pid) {
r = pid_get_cmdline_strv(pid, 0, &strv_a);
if (r >= 0)
assert_se(joined = strv_join(strv_a, "\", \""));
ASSERT_NOT_NULL(joined = strv_join(strv_a, "\", \""));
log_info(" \"%s\"", r >= 0 ? joined : errno_to_name(r));
joined = mfree(joined);
r = pid_get_cmdline_strv(pid, PROCESS_CMDLINE_COMM_FALLBACK, &strv_b);
if (r >= 0)
assert_se(joined = strv_join(strv_b, "\", \""));
ASSERT_NOT_NULL(joined = strv_join(strv_b, "\", \""));
log_info(" \"%s\"", r >= 0 ? joined : errno_to_name(r));
}
@ -151,13 +156,13 @@ TEST(pid_get_cmdline) {
_cleanup_closedir_ DIR *d = NULL;
int r;
assert_se(proc_dir_open(&d) >= 0);
ASSERT_OK(proc_dir_open(&d));
for (;;) {
pid_t pid;
r = proc_dir_read(d, &pid);
assert_se(r >= 0);
ASSERT_OK(r);
if (r == 0) /* EOF */
break;
@ -171,8 +176,8 @@ static void test_pid_get_comm_escape_one(const char *input, const char *output)
log_debug("input: <%s> — output: <%s>", input, output);
assert_se(prctl(PR_SET_NAME, input) >= 0);
assert_se(pid_get_comm(0, &n) >= 0);
ASSERT_OK_ERRNO(prctl(PR_SET_NAME, input));
ASSERT_OK(pid_get_comm(0, &n));
log_debug("got: <%s>", n);
@ -182,7 +187,7 @@ static void test_pid_get_comm_escape_one(const char *input, const char *output)
TEST(pid_get_comm_escape) {
_cleanup_free_ char *saved = NULL;
assert_se(pid_get_comm(0, &saved) >= 0);
ASSERT_OK(pid_get_comm(0, &saved));
test_pid_get_comm_escape_one("", "");
test_pid_get_comm_escape_one("foo", "foo");
@ -195,62 +200,62 @@ TEST(pid_get_comm_escape) {
test_pid_get_comm_escape_one("xxxxäöüß", "xxxx\\303\\244\\303\\266\\303\\274\\303\\237");
test_pid_get_comm_escape_one("xxxxxäöüß", "xxxxx\\303\\244\\303\\266\\303\\274\\303\\237");
assert_se(prctl(PR_SET_NAME, saved) >= 0);
ASSERT_OK_ERRNO(prctl(PR_SET_NAME, saved));
}
TEST(pid_is_unwaited) {
pid_t pid;
pid = fork();
assert_se(pid >= 0);
ASSERT_OK_ERRNO(pid);
if (pid == 0) {
_exit(EXIT_SUCCESS);
} else {
int status;
assert_se(waitpid(pid, &status, 0) == pid);
assert_se(pid_is_unwaited(pid) == 0);
ASSERT_OK_EQ_ERRNO(waitpid(pid, &status, 0), pid);
ASSERT_OK_ZERO(pid_is_unwaited(pid));
}
assert_se(pid_is_unwaited(getpid_cached()) > 0);
assert_se(pid_is_unwaited(-1) < 0);
ASSERT_OK_POSITIVE(pid_is_unwaited(getpid_cached()));
ASSERT_FAIL(pid_is_unwaited(-1));
}
TEST(pid_is_alive) {
pid_t pid;
pid = fork();
assert_se(pid >= 0);
ASSERT_OK_ERRNO(pid);
if (pid == 0) {
_exit(EXIT_SUCCESS);
} else {
int status;
assert_se(waitpid(pid, &status, 0) == pid);
assert_se(pid_is_alive(pid) == 0);
ASSERT_OK_EQ_ERRNO(waitpid(pid, &status, 0), pid);
ASSERT_OK_ZERO(pid_is_alive(pid));
}
assert_se(pid_is_alive(getpid_cached()) > 0);
assert_se(pid_is_alive(-1) < 0);
ASSERT_OK_POSITIVE(pid_is_alive(getpid_cached()));
ASSERT_FAIL(pid_is_alive(-1));
}
TEST(personality) {
assert_se(personality_to_string(PER_LINUX));
assert_se(!personality_to_string(PERSONALITY_INVALID));
ASSERT_NOT_NULL(personality_to_string(PER_LINUX));
ASSERT_NULL(personality_to_string(PERSONALITY_INVALID));
ASSERT_STREQ(personality_to_string(PER_LINUX), architecture_to_string(native_architecture()));
assert_se(personality_from_string(personality_to_string(PER_LINUX)) == PER_LINUX);
assert_se(personality_from_string(architecture_to_string(native_architecture())) == PER_LINUX);
ASSERT_EQ(personality_from_string(personality_to_string(PER_LINUX)), (unsigned long) PER_LINUX);
ASSERT_EQ(personality_from_string(architecture_to_string(native_architecture())), (unsigned long) PER_LINUX);
#ifdef __x86_64__
ASSERT_STREQ(personality_to_string(PER_LINUX), "x86-64");
ASSERT_STREQ(personality_to_string(PER_LINUX32), "x86");
assert_se(personality_from_string("x86-64") == PER_LINUX);
assert_se(personality_from_string("x86") == PER_LINUX32);
assert_se(personality_from_string("ia64") == PERSONALITY_INVALID);
assert_se(personality_from_string(NULL) == PERSONALITY_INVALID);
ASSERT_EQ(personality_from_string("x86-64"), (unsigned long) PER_LINUX);
ASSERT_EQ(personality_from_string("x86"), (unsigned long) PER_LINUX32);
ASSERT_EQ(personality_from_string("ia64"), PERSONALITY_INVALID);
ASSERT_EQ(personality_from_string(NULL), PERSONALITY_INVALID);
assert_se(personality_from_string(personality_to_string(PER_LINUX32)) == PER_LINUX32);
ASSERT_EQ(personality_from_string(personality_to_string(PER_LINUX32)), (unsigned long) PER_LINUX32);
#endif
}
@ -288,30 +293,31 @@ TEST(pid_get_cmdline_harder) {
(void) wait_for_terminate(pid, &si);
assert_se(si.si_code == CLD_EXITED);
assert_se(si.si_status == 0);
ASSERT_EQ(si.si_code, CLD_EXITED);
ASSERT_OK_ZERO(si.si_status);
return;
}
assert_se(pid == 0);
ASSERT_OK_ZERO(pid);
r = detach_mount_namespace();
if (r < 0) {
log_warning_errno(r, "detach mount namespace failed: %m");
assert_se(ERRNO_IS_PRIVILEGE(r));
if (!ERRNO_IS_PRIVILEGE(r))
ASSERT_OK(r);
return;
}
fd = mkostemp(path, O_CLOEXEC);
assert_se(fd >= 0);
ASSERT_OK_ERRNO(fd);
/* Note that we don't unmount the following bind-mount at the end of the test because the kernel
* will clear up its /proc/PID/ hierarchy automatically as soon as the test stops. */
if (mount(path, "/proc/self/cmdline", "bind", MS_BIND, NULL) < 0) {
/* This happens under selinux… Abort the test in this case. */
log_warning_errno(errno, "mount(..., \"/proc/self/cmdline\", \"bind\", ...) failed: %m");
assert_se(IN_SET(errno, EPERM, EACCES));
ASSERT_TRUE(IN_SET(errno, EPERM, EACCES));
return;
}
@ -320,197 +326,197 @@ TEST(pid_get_cmdline_harder) {
if (setrlimit(RLIMIT_STACK, &RLIMIT_MAKE_CONST(RLIM_INFINITY)) < 0)
log_warning("Testing without RLIMIT_STACK=infinity");
assert_se(unlink(path) >= 0);
ASSERT_OK_ERRNO(unlink(path));
assert_se(prctl(PR_SET_NAME, "testa") >= 0);
ASSERT_OK_ERRNO(prctl(PR_SET_NAME, "testa"));
assert_se(pid_get_cmdline(0, SIZE_MAX, 0, &line) == -ENOENT);
ASSERT_ERROR(pid_get_cmdline(0, SIZE_MAX, 0, &line), ENOENT);
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "[testa]");
line = mfree(line);
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK | PROCESS_CMDLINE_QUOTE, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK | PROCESS_CMDLINE_QUOTE, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "\"[testa]\""); /* quoting is enabled here */
line = mfree(line);
assert_se(pid_get_cmdline(0, 0, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 0, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "");
line = mfree(line);
assert_se(pid_get_cmdline(0, 1, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 1, PROCESS_CMDLINE_COMM_FALLBACK, &line));
ASSERT_STREQ(line, "");
line = mfree(line);
assert_se(pid_get_cmdline(0, 2, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 2, PROCESS_CMDLINE_COMM_FALLBACK, &line));
ASSERT_STREQ(line, "[…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 3, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 3, PROCESS_CMDLINE_COMM_FALLBACK, &line));
ASSERT_STREQ(line, "[t…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 4, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 4, PROCESS_CMDLINE_COMM_FALLBACK, &line));
ASSERT_STREQ(line, "[te…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 5, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 5, PROCESS_CMDLINE_COMM_FALLBACK, &line));
ASSERT_STREQ(line, "[tes…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 6, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 6, PROCESS_CMDLINE_COMM_FALLBACK, &line));
ASSERT_STREQ(line, "[test…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 7, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 7, PROCESS_CMDLINE_COMM_FALLBACK, &line));
ASSERT_STREQ(line, "[testa]");
line = mfree(line);
assert_se(pid_get_cmdline(0, 8, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 8, PROCESS_CMDLINE_COMM_FALLBACK, &line));
ASSERT_STREQ(line, "[testa]");
line = mfree(line);
assert_se(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args) >= 0);
assert_se(strv_equal(args, STRV_MAKE("[testa]")));
ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
ASSERT_TRUE(strv_equal(args, STRV_MAKE("[testa]")));
args = strv_free(args);
/* Test with multiple arguments that don't require quoting */
assert_se(write(fd, "foo\0bar", 8) == 8);
ASSERT_OK_EQ_ERRNO(write(fd, "foo\0bar", 8), 8);
assert_se(pid_get_cmdline(0, SIZE_MAX, 0, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, 0, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo bar");
line = mfree(line);
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
ASSERT_STREQ(line, "foo bar");
line = mfree(line);
assert_se(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args) >= 0);
assert_se(strv_equal(args, STRV_MAKE("foo", "bar")));
ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
ASSERT_TRUE(strv_equal(args, STRV_MAKE("foo", "bar")));
args = strv_free(args);
assert_se(write(fd, "quux", 4) == 4);
assert_se(pid_get_cmdline(0, SIZE_MAX, 0, &line) >= 0);
ASSERT_OK_EQ_ERRNO(write(fd, "quux", 4), 4);
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, 0, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo bar quux");
line = mfree(line);
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo bar quux");
line = mfree(line);
assert_se(pid_get_cmdline(0, 1, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 1, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "");
line = mfree(line);
assert_se(pid_get_cmdline(0, 2, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 2, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "f…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 3, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 3, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "fo…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 4, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 4, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 5, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 5, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo …");
line = mfree(line);
assert_se(pid_get_cmdline(0, 6, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 6, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo b…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 7, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 7, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo ba…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 8, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 8, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo bar…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 9, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 9, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo bar …");
line = mfree(line);
assert_se(pid_get_cmdline(0, 10, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 10, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo bar q…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 11, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 11, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo bar qu…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 12, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 12, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo bar quux");
line = mfree(line);
assert_se(pid_get_cmdline(0, 13, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 13, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo bar quux");
line = mfree(line);
assert_se(pid_get_cmdline(0, 14, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 14, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo bar quux");
line = mfree(line);
assert_se(pid_get_cmdline(0, 1000, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 1000, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "foo bar quux");
line = mfree(line);
assert_se(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args) >= 0);
assert_se(strv_equal(args, STRV_MAKE("foo", "bar", "quux")));
ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
ASSERT_TRUE(strv_equal(args, STRV_MAKE("foo", "bar", "quux")));
args = strv_free(args);
assert_se(ftruncate(fd, 0) >= 0);
assert_se(prctl(PR_SET_NAME, "aaaa bbbb cccc") >= 0);
ASSERT_OK_ERRNO(ftruncate(fd, 0));
ASSERT_OK_ERRNO(prctl(PR_SET_NAME, "aaaa bbbb cccc"));
assert_se(pid_get_cmdline(0, SIZE_MAX, 0, &line) == -ENOENT);
ASSERT_ERROR(pid_get_cmdline(0, SIZE_MAX, 0, &line), ENOENT);
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "[aaaa bbbb cccc]");
line = mfree(line);
assert_se(pid_get_cmdline(0, 10, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 10, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "[aaaa bbb…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 11, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 11, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "[aaaa bbbb…");
line = mfree(line);
assert_se(pid_get_cmdline(0, 12, PROCESS_CMDLINE_COMM_FALLBACK, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, 12, PROCESS_CMDLINE_COMM_FALLBACK, &line));
log_debug("'%s'", line);
ASSERT_STREQ(line, "[aaaa bbbb …");
line = mfree(line);
assert_se(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args) >= 0);
assert_se(strv_equal(args, STRV_MAKE("[aaaa bbbb cccc]")));
ASSERT_OK(pid_get_cmdline_strv(0, PROCESS_CMDLINE_COMM_FALLBACK, &args));
ASSERT_TRUE(strv_equal(args, STRV_MAKE("[aaaa bbbb cccc]")));
args = strv_free(args);
/* Test with multiple arguments that do require quoting */
@ -520,24 +526,24 @@ TEST(pid_get_cmdline_harder) {
#define EXPECT1p "foo $'\\'bar\\'' $'\"bar$\"' $'x y z' $'!``'"
#define EXPECT1v STRV_MAKE("foo", "'bar'", "\"bar$\"", "x y z", "!``")
assert_se(lseek(fd, SEEK_SET, 0) == 0);
assert_se(write(fd, CMDLINE1, sizeof CMDLINE1) == sizeof CMDLINE1);
assert_se(ftruncate(fd, sizeof CMDLINE1) == 0);
ASSERT_OK_ZERO_ERRNO(lseek(fd, SEEK_SET, 0));
ASSERT_OK_EQ_ERRNO(write(fd, CMDLINE1, sizeof(CMDLINE1)), (ssize_t) sizeof(CMDLINE1));
ASSERT_OK_ZERO_ERRNO(ftruncate(fd, sizeof(CMDLINE1)));
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &line));
log_debug("got: ==%s==", line);
log_debug("exp: ==%s==", EXPECT1);
ASSERT_STREQ(line, EXPECT1);
line = mfree(line);
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, &line));
log_debug("got: ==%s==", line);
log_debug("exp: ==%s==", EXPECT1p);
ASSERT_STREQ(line, EXPECT1p);
line = mfree(line);
assert_se(pid_get_cmdline_strv(0, 0, &args) >= 0);
assert_se(strv_equal(args, EXPECT1v));
ASSERT_OK(pid_get_cmdline_strv(0, 0, &args));
ASSERT_TRUE(strv_equal(args, EXPECT1v));
args = strv_free(args);
#define CMDLINE2 "foo\0\1\2\3\0\0"
@ -545,24 +551,24 @@ TEST(pid_get_cmdline_harder) {
#define EXPECT2p "foo $'\\001\\002\\003'"
#define EXPECT2v STRV_MAKE("foo", "\1\2\3")
assert_se(lseek(fd, SEEK_SET, 0) == 0);
assert_se(write(fd, CMDLINE2, sizeof CMDLINE2) == sizeof CMDLINE2);
assert_se(ftruncate(fd, sizeof CMDLINE2) == 0);
ASSERT_OK_ZERO_ERRNO(lseek(fd, SEEK_SET, 0));
ASSERT_OK_EQ_ERRNO(write(fd, CMDLINE2, sizeof(CMDLINE2)), (ssize_t) sizeof(CMDLINE2));
ASSERT_OK_ZERO_ERRNO(ftruncate(fd, sizeof CMDLINE2));
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE, &line));
log_debug("got: ==%s==", line);
log_debug("exp: ==%s==", EXPECT2);
ASSERT_STREQ(line, EXPECT2);
line = mfree(line);
assert_se(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, &line) >= 0);
ASSERT_OK(pid_get_cmdline(0, SIZE_MAX, PROCESS_CMDLINE_QUOTE_POSIX, &line));
log_debug("got: ==%s==", line);
log_debug("exp: ==%s==", EXPECT2p);
ASSERT_STREQ(line, EXPECT2p);
line = mfree(line);
assert_se(pid_get_cmdline_strv(0, 0, &args) >= 0);
assert_se(strv_equal(args, EXPECT2v));
ASSERT_OK(pid_get_cmdline_strv(0, 0, &args));
ASSERT_TRUE(strv_equal(args, EXPECT2v));
args = strv_free(args);
safe_close(fd);
@ -577,10 +583,11 @@ TEST(getpid_cached) {
b = getpid_cached();
c = getpid();
assert_se(a == b && a == c);
ASSERT_EQ(a, b);
ASSERT_EQ(a, c);
child = fork();
assert_se(child >= 0);
ASSERT_OK_ERRNO(child);
if (child == 0) {
/* In child */
@ -588,7 +595,8 @@ TEST(getpid_cached) {
b = getpid_cached();
c = getpid();
assert_se(a == b && a == c);
ASSERT_EQ(a, b);
ASSERT_EQ(a, c);
_exit(EXIT_SUCCESS);
}
@ -596,11 +604,13 @@ TEST(getpid_cached) {
e = getpid_cached();
f = getpid();
assert_se(a == d && a == e && a == f);
ASSERT_EQ(a, d);
ASSERT_EQ(a, e);
ASSERT_EQ(a, f);
assert_se(wait_for_terminate(child, &si) >= 0);
assert_se(si.si_status == 0);
assert_se(si.si_code == CLD_EXITED);
ASSERT_OK(wait_for_terminate(child, &si));
ASSERT_EQ(si.si_status, 0);
ASSERT_EQ(si.si_code, CLD_EXITED);
}
TEST(getpid_measure) {
@ -635,7 +645,7 @@ TEST(safe_fork) {
BLOCK_SIGNALS(SIGCHLD);
r = safe_fork("(test-child)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_REARRANGE_STDIO|FORK_REOPEN_LOG, &pid);
assert_se(r >= 0);
ASSERT_OK(r);
if (r == 0) {
/* child */
@ -644,43 +654,42 @@ TEST(safe_fork) {
_exit(88);
}
assert_se(wait_for_terminate(pid, &status) >= 0);
assert_se(status.si_code == CLD_EXITED);
assert_se(status.si_status == 88);
ASSERT_OK(wait_for_terminate(pid, &status));
ASSERT_EQ(status.si_code, CLD_EXITED);
ASSERT_EQ(status.si_status, 88);
}
TEST(pid_to_ptr) {
assert_se(PTR_TO_PID(NULL) == 0);
ASSERT_EQ(PTR_TO_PID(NULL), 0);
ASSERT_NULL(PID_TO_PTR(0));
assert_se(PTR_TO_PID(PID_TO_PTR(1)) == 1);
assert_se(PTR_TO_PID(PID_TO_PTR(2)) == 2);
assert_se(PTR_TO_PID(PID_TO_PTR(-1)) == -1);
assert_se(PTR_TO_PID(PID_TO_PTR(-2)) == -2);
ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(1)), 1);
ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(2)), 2);
ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(-1)), -1);
ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(-2)), -2);
assert_se(PTR_TO_PID(PID_TO_PTR(INT16_MAX)) == INT16_MAX);
assert_se(PTR_TO_PID(PID_TO_PTR(INT16_MIN)) == INT16_MIN);
ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT16_MAX)), INT16_MAX);
ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT16_MIN)), INT16_MIN);
assert_se(PTR_TO_PID(PID_TO_PTR(INT32_MAX)) == INT32_MAX);
assert_se(PTR_TO_PID(PID_TO_PTR(INT32_MIN)) == INT32_MIN);
ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT32_MAX)), INT32_MAX);
ASSERT_EQ(PTR_TO_PID(PID_TO_PTR(INT32_MIN)), INT32_MIN);
}
static void test_ioprio_class_from_to_string_one(const char *val, int expected, int normalized) {
assert_se(ioprio_class_from_string(val) == expected);
ASSERT_EQ(ioprio_class_from_string(val), expected);
if (expected >= 0) {
_cleanup_free_ char *s = NULL;
unsigned ret;
int combined;
assert_se(ioprio_class_to_string_alloc(expected, &s) == 0);
ASSERT_OK_ZERO(ioprio_class_to_string_alloc(expected, &s));
/* We sometimes get a class number and sometimes a name back */
assert_se(streq(s, val) ||
safe_atou(val, &ret) == 0);
ASSERT_TRUE(streq(s, val) || safe_atou(val, &ret) == 0);
/* Make sure normalization works, i.e. NONE → BE gets normalized */
combined = ioprio_normalize(ioprio_prio_value(expected, 0));
assert_se(ioprio_prio_class(combined) == normalized);
assert_se(expected != IOPRIO_CLASS_NONE || ioprio_prio_data(combined) == 4);
ASSERT_EQ(ioprio_prio_class(combined), normalized);
ASSERT_TRUE(expected != IOPRIO_CLASS_NONE || ioprio_prio_data(combined) == 4);
}
}
@ -701,8 +710,8 @@ TEST(setpriority_closest) {
int r;
r = safe_fork("(test-setprio)",
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_WAIT|FORK_LOG, NULL);
assert_se(r >= 0);
FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_DEATHSIG_SIGTERM|FORK_WAIT|FORK_LOG|FORK_REOPEN_LOG, NULL);
ASSERT_OK(r);
if (r == 0) {
bool full_test;
@ -713,16 +722,21 @@ TEST(setpriority_closest) {
if (setrlimit(RLIMIT_NICE, &RLIMIT_MAKE_CONST(30)) < 0) {
/* If this fails we are probably unprivileged or in a userns of some kind, let's skip
* the full test */
assert_se(ERRNO_IS_PRIVILEGE(errno));
if (!ERRNO_IS_PRIVILEGE(errno))
ASSERT_OK_ERRNO(-1);
full_test = false;
} else {
/* However, if the hard limit was above 30, setrlimit would succeed unprivileged, so
* check if the UID/GID can be changed before enabling the full test. */
if (setresgid(GID_NOBODY, GID_NOBODY, GID_NOBODY) < 0) {
assert_se(ERRNO_IS_PRIVILEGE(errno));
/* If the nobody user does not exist (user namespace) we get EINVAL. */
if (!ERRNO_IS_PRIVILEGE(errno) && errno != EINVAL)
ASSERT_OK_ERRNO(-1);
full_test = false;
} else if (setresuid(UID_NOBODY, UID_NOBODY, UID_NOBODY) < 0) {
assert_se(ERRNO_IS_PRIVILEGE(errno));
/* If the nobody user does not exist (user namespace) we get EINVAL. */
if (!ERRNO_IS_PRIVILEGE(errno) && errno != EINVAL)
ASSERT_OK_ERRNO(-1);
full_test = false;
} else
full_test = true;
@ -730,61 +744,69 @@ TEST(setpriority_closest) {
errno = 0;
p = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0);
ASSERT_EQ(errno, 0);
/* It should always be possible to set our nice level to the current one */
assert_se(setpriority_closest(p) > 0);
ASSERT_OK_POSITIVE(setpriority_closest(p));
errno = 0;
q = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0 && p == q);
ASSERT_EQ(errno, 0);
ASSERT_EQ(p, q);
/* It should also be possible to set the nice level to one higher */
if (p < PRIO_MAX-1) {
assert_se(setpriority_closest(++p) > 0);
ASSERT_OK_POSITIVE(setpriority_closest(++p));
errno = 0;
q = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0 && p == q);
ASSERT_EQ(errno, 0);
ASSERT_EQ(p, q);
}
/* It should also be possible to set the nice level to two higher */
if (p < PRIO_MAX-1) {
assert_se(setpriority_closest(++p) > 0);
ASSERT_OK_POSITIVE(setpriority_closest(++p));
errno = 0;
q = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0 && p == q);
ASSERT_EQ(errno, 0);
ASSERT_EQ(p, q);
}
if (full_test) {
/* These two should work, given the RLIMIT_NICE we set above */
assert_se(setpriority_closest(-10) > 0);
ASSERT_OK_POSITIVE(setpriority_closest(-10));
errno = 0;
q = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0 && q == -10);
ASSERT_EQ(errno, 0);
ASSERT_EQ(q, -10);
assert_se(setpriority_closest(-9) > 0);
ASSERT_OK_POSITIVE(setpriority_closest(-9));
errno = 0;
q = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0 && q == -9);
ASSERT_EQ(errno, 0);
ASSERT_EQ(q, -9);
/* This should succeed but should be clamped to the limit */
assert_se(setpriority_closest(-11) == 0);
ASSERT_OK_ZERO(setpriority_closest(-11));
errno = 0;
q = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0 && q == -10);
ASSERT_EQ(errno, 0);
ASSERT_EQ(q, -10);
assert_se(setpriority_closest(-8) > 0);
ASSERT_OK_POSITIVE(setpriority_closest(-8));
errno = 0;
q = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0 && q == -8);
ASSERT_EQ(errno, 0);
ASSERT_EQ(q, -8);
/* This should succeed but should be clamped to the limit */
assert_se(setpriority_closest(-12) == 0);
ASSERT_OK_ZERO(setpriority_closest(-12));
errno = 0;
q = getpriority(PRIO_PROCESS, 0);
assert_se(errno == 0 && q == -10);
ASSERT_EQ(errno, 0);
ASSERT_EQ(q, -10);
}
_exit(EXIT_SUCCESS);
@ -795,10 +817,10 @@ TEST(get_process_ppid) {
uint64_t limit;
int r;
assert_se(get_process_ppid(1, NULL) == -EADDRNOTAVAIL);
ASSERT_ERROR(get_process_ppid(1, NULL), EADDRNOTAVAIL);
/* the process with the PID above the global limit definitely doesn't exist. Verify that */
assert_se(procfs_get_pid_max(&limit) >= 0);
ASSERT_OK(procfs_get_pid_max(&limit));
log_debug("kernel.pid_max = %"PRIu64, limit);
if (limit < INT_MAX) {
@ -817,10 +839,10 @@ TEST(get_process_ppid) {
break;
}
assert_se(r >= 0);
ASSERT_OK(r);
assert_se(pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c1) >= 0);
assert_se(pid_get_cmdline(ppid, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c2) >= 0);
ASSERT_OK(pid_get_cmdline(pid, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c1));
ASSERT_OK(pid_get_cmdline(ppid, SIZE_MAX, PROCESS_CMDLINE_COMM_FALLBACK, &c2));
log_info("Parent of " PID_FMT " (%s) is " PID_FMT " (%s).", pid, c1, ppid, c2);
@ -831,19 +853,20 @@ TEST(get_process_ppid) {
TEST(set_oom_score_adjust) {
int a, b, r;
assert_se(get_oom_score_adjust(&a) >= 0);
ASSERT_OK(get_oom_score_adjust(&a));
r = set_oom_score_adjust(OOM_SCORE_ADJ_MIN);
assert_se(r >= 0 || ERRNO_IS_PRIVILEGE(r));
if (!ERRNO_IS_PRIVILEGE(r))
ASSERT_OK(r);
if (r >= 0) {
assert_se(get_oom_score_adjust(&b) >= 0);
assert_se(b == OOM_SCORE_ADJ_MIN);
ASSERT_OK(get_oom_score_adjust(&b));
ASSERT_EQ(b, OOM_SCORE_ADJ_MIN);
}
assert_se(set_oom_score_adjust(a) >= 0);
assert_se(get_oom_score_adjust(&b) >= 0);
assert_se(b == a);
ASSERT_OK(set_oom_score_adjust(a));
ASSERT_OK(get_oom_score_adjust(&b));
ASSERT_EQ(b, a);
}
static void* dummy_thread(void *p) {
@ -851,10 +874,10 @@ static void* dummy_thread(void *p) {
char x;
/* let main thread know we are ready */
assert_se(write(fd, &(const char) { 'x' }, 1) == 1);
ASSERT_OK_EQ_ERRNO(write(fd, &(const char) { 'x' }, 1), 1);
/* wait for the main thread to tell us to shut down */
assert_se(read(fd, &x, 1) == 1);
ASSERT_OK_EQ_ERRNO(read(fd, &x, 1), 1);
return NULL;
}
@ -862,38 +885,42 @@ TEST(get_process_threads) {
int r;
/* Run this test in a child, so that we can guarantee there's exactly one thread around in the child */
r = safe_fork("(nthreads)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_REOPEN_LOG|FORK_WAIT|FORK_LOG, NULL);
assert_se(r >= 0);
r = safe_fork("(nthreads)", FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGTERM|FORK_WAIT|FORK_LOG, NULL);
ASSERT_OK(r);
if (r == 0) {
_cleanup_close_pair_ int pfd[2] = EBADF_PAIR, ppfd[2] = EBADF_PAIR;
pthread_t t, tt;
char x;
assert_se(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, pfd) >= 0);
assert_se(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, ppfd) >= 0);
ASSERT_OK_ERRNO(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, pfd));
ASSERT_OK_ERRNO(socketpair(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0, ppfd));
assert_se(get_process_threads(0) == 1);
assert_se(pthread_create(&t, NULL, &dummy_thread, FD_TO_PTR(pfd[0])) == 0);
assert_se(read(pfd[1], &x, 1) == 1);
assert_se(get_process_threads(0) == 2);
assert_se(pthread_create(&tt, NULL, &dummy_thread, FD_TO_PTR(ppfd[0])) == 0);
assert_se(read(ppfd[1], &x, 1) == 1);
assert_se(get_process_threads(0) == 3);
ASSERT_OK_EQ(get_process_threads(0), 1);
ASSERT_OK_ZERO_ERRNO(pthread_create(&t, NULL, &dummy_thread, FD_TO_PTR(pfd[0])));
ASSERT_OK_EQ_ERRNO(read(pfd[1], &x, 1), 1);
ASSERT_OK_EQ(get_process_threads(0), 2);
ASSERT_OK_ZERO_ERRNO(pthread_create(&tt, NULL, &dummy_thread, FD_TO_PTR(ppfd[0])));
ASSERT_OK_EQ_ERRNO(read(ppfd[1], &x, 1), 1);
ASSERT_OK_EQ(get_process_threads(0), 3);
assert_se(write(pfd[1], &(const char) { 'x' }, 1) == 1);
assert_se(pthread_join(t, NULL) == 0);
ASSERT_OK_EQ_ERRNO(write(pfd[1], &(const char) { 'x' }, 1), 1);
ASSERT_OK_ZERO_ERRNO(pthread_join(t, NULL));
/* the value reported via /proc/ is decreased asynchronously, and there appears to be no nice
* way to sync on it. Hence we do the weak >= 2 check, even though == 2 is what we'd actually
* like to check here */
assert_se(get_process_threads(0) >= 2);
r = get_process_threads(0);
ASSERT_OK(r);
ASSERT_GE(r, 2);
assert_se(write(ppfd[1], &(const char) { 'x' }, 1) == 1);
assert_se(pthread_join(tt, NULL) == 0);
ASSERT_OK_EQ_ERRNO(write(ppfd[1], &(const char) { 'x' }, 1), 1);
ASSERT_OK_ZERO_ERRNO(pthread_join(tt, NULL));
/* similar here */
assert_se(get_process_threads(0) >= 1);
r = get_process_threads(0);
ASSERT_OK(r);
ASSERT_GE(r, 1);
_exit(EXIT_SUCCESS);
}
@ -902,17 +929,17 @@ TEST(get_process_threads) {
TEST(is_reaper_process) {
int r;
r = safe_fork("(regular)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_WAIT, NULL);
assert_se(r >= 0);
r = safe_fork("(regular)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
ASSERT_OK(r);
if (r == 0) {
/* child */
assert_se(is_reaper_process() == 0);
ASSERT_OK_ZERO(is_reaper_process());
_exit(EXIT_SUCCESS);
}
r = safe_fork("(newpid)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_WAIT, NULL);
assert_se(r >= 0);
r = safe_fork("(newpid)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
ASSERT_OK(r);
if (r == 0) {
/* child */
@ -923,25 +950,25 @@ TEST(is_reaper_process) {
}
}
r = safe_fork("(newpid1)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_WAIT, NULL);
assert_se(r >= 0);
r = safe_fork("(newpid1)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
ASSERT_OK(r);
if (r == 0) {
/* grandchild, which is PID1 in a pidns */
assert_se(getpid_cached() == 1);
assert_se(is_reaper_process() > 0);
ASSERT_OK_EQ(getpid_cached(), 1);
ASSERT_OK_POSITIVE(is_reaper_process());
_exit(EXIT_SUCCESS);
}
_exit(EXIT_SUCCESS);
}
r = safe_fork("(subreaper)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_WAIT, NULL);
assert_se(r >= 0);
r = safe_fork("(subreaper)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG|FORK_WAIT, NULL);
ASSERT_OK(r);
if (r == 0) {
/* child */
assert_se(make_reaper_process(true) >= 0);
ASSERT_OK(make_reaper_process(true));
assert_se(is_reaper_process() > 0);
ASSERT_OK_POSITIVE(is_reaper_process());
_exit(EXIT_SUCCESS);
}
}
@ -949,22 +976,22 @@ TEST(is_reaper_process) {
TEST(pid_get_start_time) {
_cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
assert_se(pidref_set_self(&pidref) >= 0);
ASSERT_OK(pidref_set_self(&pidref));
usec_t start_time;
assert_se(pidref_get_start_time(&pidref, &start_time) >= 0);
ASSERT_OK(pidref_get_start_time(&pidref, &start_time));
log_info("our starttime: " USEC_FMT, start_time);
_cleanup_(pidref_done_sigkill_wait) PidRef child = PIDREF_NULL;
assert_se(pidref_safe_fork("(stub)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS, &child) >= 0);
ASSERT_OK(pidref_safe_fork("(stub)", FORK_RESET_SIGNALS|FORK_CLOSE_ALL_FDS|FORK_REOPEN_LOG, &child));
usec_t start_time2;
assert_se(pidref_get_start_time(&child, &start_time2) >= 0);
ASSERT_OK(pidref_get_start_time(&child, &start_time2));
log_info("child starttime: " USEC_FMT, start_time2);
assert_se(start_time2 >= start_time);
ASSERT_GE(start_time2, start_time);
}
static int intro(void) {

View File

@ -259,7 +259,7 @@ static int run(int argc, char *argv[]) {
if (r <= 0)
return r;
if (arg_graceful && tpm2_support() != TPM2_SUPPORT_FULL) {
if (arg_graceful && !tpm2_is_fully_supported()) {
log_notice("No complete TPM2 support detected, exiting gracefully.");
return EXIT_SUCCESS;
}

View File

@ -288,7 +288,7 @@ static int verb_info(int argc, char *argv[], void *userdata) {
pager_open(arg_pager_flags);
if (FLAGS_SET(arg_json_format_flags, SD_JSON_FORMAT_OFF)) {
static const struct sd_json_dispatch_field dispatch_table[] = {
static const sd_json_dispatch_field dispatch_table[] = {
{ "vendor", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(GetInfoData, vendor), SD_JSON_MANDATORY },
{ "product", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(GetInfoData, product), SD_JSON_MANDATORY },
{ "version", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(GetInfoData, version), SD_JSON_MANDATORY },
@ -380,12 +380,12 @@ static int verb_introspect(int argc, char *argv[], void *userdata) {
if (r < 0)
return r;
const struct sd_json_dispatch_field dispatch_table[] = {
{ "interfaces", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, PTR_TO_SIZE(&auto_interfaces), SD_JSON_MANDATORY },
static const sd_json_dispatch_field dispatch_table[] = {
{ "interfaces", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, 0, SD_JSON_MANDATORY },
{}
};
r = sd_json_dispatch(reply, dispatch_table, SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS, NULL);
r = sd_json_dispatch(reply, dispatch_table, SD_JSON_LOG|SD_JSON_ALLOW_EXTENSIONS, &auto_interfaces);
if (r < 0)
return r;
@ -412,7 +412,7 @@ static int verb_introspect(int argc, char *argv[], void *userdata) {
return r;
if (FLAGS_SET(arg_json_format_flags, SD_JSON_FORMAT_OFF) || list_methods) {
static const struct sd_json_dispatch_field dispatch_table[] = {
static const sd_json_dispatch_field dispatch_table[] = {
{ "description", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, 0, SD_JSON_MANDATORY },
{}
};

View File

@ -4,5 +4,6 @@ integration_tests += [
integration_test_template + {
'name' : fs.name(meson.current_source_dir()),
'storage': 'persistent',
'vm' : true,
},
]

View File

@ -21,6 +21,9 @@ at_exit() {
trap at_exit EXIT
systemctl unmask systemd-networkd.service
systemctl start systemd-networkd.service
export NETWORK_NAME="10-networkctl-test-$RANDOM.network"
export NETDEV_NAME="10-networkctl-test-$RANDOM.netdev"
export LINK_NAME="10-networkctl-test-$RANDOM.link"
@ -75,15 +78,6 @@ cmp "+4" "/etc/systemd/network/${NETWORK_NAME}.d/test.conf"
networkctl cat "$NETWORK_NAME" | grep '^# ' |
cmp - <(printf '%s\n' "# /etc/systemd/network/$NETWORK_NAME" "# /etc/systemd/network/${NETWORK_NAME}.d/test.conf")
networkctl edit --stdin --runtime "$NETDEV_NAME" <<EOF
[NetDev]
Name=test2
Kind=dummy
EOF
networkctl cat "$NETDEV_NAME" | grep -v '^# ' |
cmp - <(printf '%s\n' "[NetDev]" "Name=test2" "Kind=dummy")
cat >"/usr/lib/systemd/network/$LINK_NAME" <<EOF
[Match]
OriginalName=test2
@ -95,13 +89,23 @@ EOF
SYSTEMD_LOG_LEVEL=debug EDITOR='true' script -ec 'networkctl edit "$LINK_NAME"' /dev/null
cmp "/usr/lib/systemd/network/$LINK_NAME" "/etc/systemd/network/$LINK_NAME"
# Test links
systemctl unmask systemd-networkd
systemctl stop systemd-networkd
# The interface test2 does not exist, hence the below do not work.
(! networkctl cat @test2)
(! networkctl cat @test2:netdev)
(! networkctl cat @test2:link)
(! networkctl cat @test2:network)
systemctl start systemd-networkd
# create .netdev file at last, otherwise, the .link file will not be applied to the interface.
networkctl edit --stdin --runtime "$NETDEV_NAME" <<EOF
[NetDev]
Name=test2
Kind=dummy
EOF
networkctl cat "$NETDEV_NAME" | grep -v '^# ' |
cmp - <(printf '%s\n' "[NetDev]" "Name=test2" "Kind=dummy")
# wait for the interface being created and configured.
SYSTEMD_LOG_LEVEL=debug /usr/lib/systemd/systemd-networkd-wait-online -i test2:carrier --timeout 20
networkctl cat @test2:network | cmp - <(networkctl cat "$NETWORK_NAME")