zstd
Packages=
+ gdb
libidn2
qrencode
+ strace
+
+[Host]
+QemuHeadless=yes
zstd
Packages=
+ gdb
+ libidn2-0
libqrencode4
locales
- libidn2-0
+ strace
+
+[Host]
+QemuHeadless=yes
zstd
Packages=
+ gdb
# libfido2 + libzstd can be dropped once the Fedora RPM gets a dependency on them
libfido2
libzstd
# procps-ng provides a set of useful utilies (ps, free, etc)
procps-ng
+ strace
BuildDirectory=mkosi.builddir
Cache=mkosi.cache
+
+[Host]
+QemuHeadless=yes
timezone
Packages=
+ gdb
# brought in via meson->python3
libp11-kit0
# --bootable=no
libqrencode4
libseccomp2
pam
+ strace
util-linux
+
+[Host]
+QemuHeadless=yes
zstd
Packages=
+ gdb
+ libidn2-0
libqrencode4
locales
- libidn2-0
+ strace
+
+[Host]
+QemuHeadless=yes
KEYBOARD_KEY_f1=f20
KEYBOARD_KEY_f2=f21
+# MSI Modern series
+evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMicro-StarInternational*:pnModern*:*
+ KEYBOARD_KEY_f1=f20 # Fn+F5 micmute
+ KEYBOARD_KEY_76=f21 # Fn+F4 touchpad, becomes meta+ctrl+toggle
+ KEYBOARD_KEY_91=prog1 # Fn+F7 Creation Center, sometime F7
+ KEYBOARD_KEY_f2=prog2 # Fn+F12 screen rotation
+ KEYBOARD_KEY_97=unknown # lid close
+ KEYBOARD_KEY_98=unknown # lid open
+ #Fn+PrntScr sends meta+shif+s
+
###########################################################
# MSI
###########################################################
<refsect1>
<title>Synthetic Records</title>
- <para><command>systemd-resolved</command> synthetizes DNS resource records (RRs) for the following
+ <para><command>systemd-resolved</command> synthesizes DNS resource records (RRs) for the following
cases:</para>
<itemizedlist>
<listitem><para>Single-label names are resolved using LLMNR on all local interfaces where LLMNR is
enabled. Lookups for IPv4 addresses are only sent via LLMNR on IPv4, and lookups for IPv6 addresses are
- only sent via LLMNR on IPv6. Note that lookups for single-label synthetized names are not routed to
+ only sent via LLMNR on IPv6. Note that lookups for single-label synthesized names are not routed to
LLMNR, MulticastDNS or unicast DNS.</para></listitem>
- <listitem><para>Queries for the address records (A and AAAA) of single-label non-synthetized names are
+ <listitem><para>Queries for the address records (A and AAAA) of single-label non-synthesized names are
resolved via unicast DNS using search domains. For any interface which defines search domains, such
look-ups are routed to that interface, suffixed with each of the search domains defined on that
interface in turn. When global search domains are defined, such look-ups are routed to all interfaces,
determined based on the configured DNS domains for a link: if there's a route-only domain other than
<literal>~.</literal>, it defaults to false, otherwise to true.</para>
- <para>Effectively this means: in order to support single-label non-synthetized names, define appropriate
+ <para>Effectively this means: in order to support single-label non-synthesized names, define appropriate
search domains. In order to preferably route all DNS queries not explicitly matched by routing domain
configuration to a specific link, configure a <literal>~.</literal> route-only domain on it. This will
ensure that other links will not be considered for these queries (unless they too carry such a routing
for mount dependencies here. For example, you should not set
<varname>After=network-online.target</varname> or similar on network
filesystems. Doing so may result in an ordering cycle.</para>
+
+ <para>Note that automount support on Linux is privileged, automount units are hence only available in the
+ system service manager (and root's user service manager), but not in unprivileged user's service
+ manager.</para>
</refsect1>
<refsect1>
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>. Note that swap
units cannot be templated, nor is possible to add multiple names to a swap unit by creating additional symlinks to
it.</para>
+
+ <para>Note that swap support on Linux is privileged, swap units are hence only available in the system
+ service manager (and root's user service manager), but not in unprivileged user's service manager.</para>
</refsect1>
<refsect1>
want_qrencode = get_option('qrencode')
if want_qrencode != 'false' and not skip_deps
libqrencode = dependency('libqrencode',
+ version : '>= 4',
required : want_qrencode == 'true')
have = libqrencode.found()
else
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
+#include <sys/types.h>
+
+#include "macro.h"
+
int asynchronous_job(void* (*func)(void *p), void *arg);
int asynchronous_sync(pid_t *ret_pid);
int asynchronous_close(int fd);
+
+DEFINE_TRIVIAL_CLEANUP_FUNC(int, asynchronous_close);
return mfree(cache);
}
+
+int set_strjoin(Set *s, const char *separator, char **ret) {
+ size_t separator_len, allocated = 0, len = 0;
+ _cleanup_free_ char *str = NULL;
+ const char *value;
+ bool first = true;
+
+ assert(ret);
+
+ separator_len = strlen_ptr(separator);
+
+ SET_FOREACH(value, s) {
+ size_t l = strlen_ptr(value);
+
+ if (l == 0)
+ continue;
+
+ if (!GREEDY_REALLOC(str, allocated, len + l + (first ? 0 : separator_len) + 1))
+ return -ENOMEM;
+
+ if (separator_len > 0 && !first) {
+ memcpy(str + len, separator, separator_len);
+ len += separator_len;
+ }
+
+ memcpy(str + len, value, l);
+ len += l;
+ first = false;
+ }
+ if (str)
+ str[len] = '\0';
+
+ *ret = TAKE_PTR(str);
+ return 0;
+}
static bool syslog_is_stream = false;
-static bool show_color = false;
+static int show_color = -1; /* tristate */
static bool show_location = false;
static bool show_time = false;
static bool show_tid = false;
iovec[n++] = IOVEC_MAKE_STRING(prefix);
}
- if (show_time) {
- if (format_timestamp(header_time, sizeof(header_time), now(CLOCK_REALTIME))) {
- iovec[n++] = IOVEC_MAKE_STRING(header_time);
- iovec[n++] = IOVEC_MAKE_STRING(" ");
- }
+ if (show_time &&
+ format_timestamp(header_time, sizeof(header_time), now(CLOCK_REALTIME))) {
+ iovec[n++] = IOVEC_MAKE_STRING(header_time);
+ iovec[n++] = IOVEC_MAKE_STRING(" ");
}
if (show_tid) {
iovec[n++] = IOVEC_MAKE_STRING(tid_string);
}
- if (show_color)
+ if (log_get_show_color())
get_log_colors(LOG_PRI(level), &on, &off, NULL);
if (show_location) {
const char *lon = "", *loff = "";
- if (show_color) {
+ if (log_get_show_color()) {
lon = ANSI_HIGHLIGHT_YELLOW4;
loff = ANSI_NORMAL;
}
}
bool log_get_show_color(void) {
- return show_color;
+ return show_color > 0; /* Defaults to false. */
}
void log_show_location(bool b) {
void log_setup_cli(void) {
/* Sets up logging the way it is most appropriate for running a program as a CLI utility. */
- log_show_color(true);
+ log_set_target(LOG_TARGET_AUTO);
log_parse_environment_cli();
(void) log_open();
+ if (log_on_console() && show_color < 0)
+ log_show_color(true);
}
#define ERRNO_VALUE(val) (abs(val) & 255)
void log_set_target(LogTarget target);
+
void log_set_max_level_realm(LogRealm realm, int level);
+
#define log_set_max_level(level) \
log_set_max_level_realm(LOG_REALM, (level))
+static inline void log_set_max_level_all_realms(int level) {
+ for (LogRealm realm = 0; realm < _LOG_REALM_MAX; realm++)
+ log_set_max_level_realm(realm, level);
+}
+
void log_set_facility(int facility);
int log_set_target_from_string(const char *e);
#define _cleanup_set_free_ _cleanup_(set_freep)
#define _cleanup_set_free_free_ _cleanup_(set_free_freep)
+
+int set_strjoin(Set *s, const char *separator, char **ret);
*/
e = getenv("container");
if (!e)
- goto check_sched;
+ goto none;
if (isempty(e)) {
r = VIRTUALIZATION_NONE;
goto finish;
if (r < 0) /* This only works if we have CAP_SYS_PTRACE, hence let's better ignore failures here */
log_debug_errno(r, "Failed to read $container of PID 1, ignoring: %m");
- /* Interestingly /proc/1/sched actually shows the host's PID for what we see as PID 1. If the PID
- * shown there is not 1, we know we are in a PID namespace and hence a container. */
- check_sched:
- r = read_one_line_file("/proc/1/sched", &m);
- if (r >= 0) {
- const char *t;
-
- t = strrchr(m, '(');
- if (!t)
- return -EIO;
-
- if (!startswith(t, "(1,")) {
- r = VIRTUALIZATION_CONTAINER_OTHER;
- goto finish;
- }
- } else if (r != -ENOENT)
- return r;
-
+none:
/* If that didn't work, give up, assume no container manager. */
r = VIRTUALIZATION_NONE;
goto finish;
xsprintf(buf, "%" PRIu64 "\n", weight);
(void) set_attribute_and_warn(u, "blkio", "blkio.weight", buf);
+ /* FIXME: drop this when distro kernels properly support BFQ through "blkio.weight"
+ * See also: https://github.com/systemd/systemd/pull/13335 */
+ xsprintf(buf, "%" PRIu64 "\n", weight);
+ (void) set_attribute_and_warn(u, "blkio", "blkio.bfq.weight", buf);
+
if (has_io) {
CGroupIODeviceWeight *w;
return 0;
}
+static int cg_v1_errno_to_log_level(int r) {
+ return r == -EROFS ? LOG_DEBUG : LOG_WARNING;
+}
+
static int unit_update_cgroup(
Unit *u,
CGroupMask target_mask,
* We perform migration also with whole slices for cases when users don't care about leave
* granularity. Since delegated_mask is subset of target mask, we won't trim slice subtree containing
* delegated units.
+ *
+ * If we're in an nspawn container and using legacy cgroups, the controller hierarchies are mounted
+ * read-only into the container. We skip migration/trim in this scenario since it would fail
+ * regardless with noisy "Read-only filesystem" warnings.
*/
if (cg_all_unified() == 0) {
r = cg_migrate_v1_controllers(u->manager->cgroup_supported, migrate_mask, u->cgroup_path, migrate_callback, u);
if (r < 0)
- log_unit_warning_errno(u, r, "Failed to migrate controller cgroups from %s, ignoring: %m", u->cgroup_path);
+ log_unit_full_errno(
+ u,
+ cg_v1_errno_to_log_level(r),
+ r,
+ "Failed to migrate controller cgroups from %s, ignoring: %m",
+ u->cgroup_path);
is_root_slice = unit_has_name(u, SPECIAL_ROOT_SLICE);
r = cg_trim_v1_controllers(u->manager->cgroup_supported, ~target_mask, u->cgroup_path, !is_root_slice);
if (r < 0)
- log_unit_warning_errno(u, r, "Failed to delete controller cgroups %s, ignoring: %m", u->cgroup_path);
+ log_unit_full_errno(
+ u,
+ cg_v1_errno_to_log_level(r),
+ r,
+ "Failed to delete controller cgroups %s, ignoring: %m",
+ u->cgroup_path);
}
/* Set attributes */
usec_t wait_usec, watchdog_usec;
watchdog_usec = manager_get_watchdog(m, WATCHDOG_RUNTIME);
- if (timestamp_is_set(watchdog_usec))
+ if (m->runtime_watchdog_running)
(void) watchdog_ping();
+ else if (timestamp_is_set(watchdog_usec))
+ manager_retry_runtime_watchdog(m);
if (!ratelimit_below(&rl)) {
/* Yay, something is going seriously wrong, pause a little */
if (t == WATCHDOG_RUNTIME)
if (!timestamp_is_set(m->watchdog_overridden[WATCHDOG_RUNTIME])) {
- if (timestamp_is_set(timeout))
+ if (timestamp_is_set(timeout)) {
r = watchdog_set_timeout(&timeout);
- else
+
+ if (r >= 0)
+ m->runtime_watchdog_running = true;
+ } else {
watchdog_close(true);
+ m->runtime_watchdog_running = false;
+ }
}
- if (r >= 0)
- m->watchdog[t] = timeout;
+ m->watchdog[t] = timeout;
}
int manager_override_watchdog(Manager *m, WatchdogType t, usec_t timeout) {
usec_t *p;
p = timestamp_is_set(timeout) ? &timeout : &m->watchdog[t];
- if (timestamp_is_set(*p))
+ if (timestamp_is_set(*p)) {
r = watchdog_set_timeout(p);
- else
+
+ if (r >= 0)
+ m->runtime_watchdog_running = true;
+ } else {
watchdog_close(true);
+ m->runtime_watchdog_running = false;
+ }
}
- if (r >= 0)
- m->watchdog_overridden[t] = timeout;
+ m->watchdog_overridden[t] = timeout;
return 0;
}
+void manager_retry_runtime_watchdog(Manager *m) {
+ int r = 0;
+
+ assert(m);
+
+ if (timestamp_is_set(m->watchdog_overridden[WATCHDOG_RUNTIME]))
+ r = watchdog_set_timeout(&m->watchdog_overridden[WATCHDOG_RUNTIME]);
+ else
+ r = watchdog_set_timeout(&m->watchdog[WATCHDOG_RUNTIME]);
+
+ if (r >= 0)
+ m->runtime_watchdog_running = true;
+}
+
static void manager_deserialize_uid_refs_one_internal(
Manager *m,
Hashmap** uid_refs,
usec_t watchdog[_WATCHDOG_TYPE_MAX];
usec_t watchdog_overridden[_WATCHDOG_TYPE_MAX];
+ bool runtime_watchdog_running; /* Whether the runtime HW watchdog was started, so we know if we still need to get the real timeout from the hardware */
+
dual_timestamp timestamps[_MANAGER_TIMESTAMP_MAX];
/* Data specific to the device subsystem */
usec_t manager_get_watchdog(Manager *m, WatchdogType t);
void manager_set_watchdog(Manager *m, WatchdogType t, usec_t timeout);
int manager_override_watchdog(Manager *m, WatchdogType t, usec_t timeout);
+void manager_retry_runtime_watchdog(Manager *m);
const char* oom_policy_to_string(OOMPolicy i) _const_;
OOMPolicy oom_policy_from_string(const char *s) _pure_;
for (const char *p = value;;) {
_cleanup_free_ char *word = NULL;
- r = extract_first_word(&p, &word, NULL, 0);
+ /* udev rules may set escaped strings, and sd-device does not modify the input
+ * strings. So, it is also necessary to keep the strings received through
+ * sd-device-monitor. */
+ r = extract_first_word(&p, &word, NULL, EXTRACT_RETAIN_ESCAPE);
if (r < 0)
return r;
if (r == 0)
return v;
}
-static char *join_string_set(Set *s) {
- size_t ret_allocated = 0, ret_len;
- _cleanup_free_ char *ret = NULL;
- const char *tag;
-
- if (!GREEDY_REALLOC(ret, ret_allocated, 2))
- return NULL;
-
- strcpy(ret, ":");
- ret_len = 1;
-
- SET_FOREACH(tag, s) {
- char *e;
-
- if (!GREEDY_REALLOC(ret, ret_allocated, ret_len + strlen(tag) + 2))
- return NULL;
-
- e = stpcpy(stpcpy(ret + ret_len, tag), ":");
- ret_len = e - ret;
- }
-
- return TAKE_PTR(ret);
-}
-
int device_properties_prepare(sd_device *device) {
int r;
if (device->property_devlinks_outdated) {
_cleanup_free_ char *devlinks = NULL;
- size_t devlinks_allocated = 0, devlinks_len = 0;
- const char *devlink;
-
- for (devlink = sd_device_get_devlink_first(device); devlink; devlink = sd_device_get_devlink_next(device)) {
- char *e;
- if (!GREEDY_REALLOC(devlinks, devlinks_allocated, devlinks_len + strlen(devlink) + 2))
- return -ENOMEM;
- if (devlinks_len > 0)
- stpcpy(devlinks + devlinks_len++, " ");
- e = stpcpy(devlinks + devlinks_len, devlink);
- devlinks_len = e - devlinks;
- }
-
- r = device_add_property_internal(device, "DEVLINKS", devlinks);
+ r = set_strjoin(device->devlinks, " ", &devlinks);
if (r < 0)
return r;
+ if (!isempty(devlinks)) {
+ r = device_add_property_internal(device, "DEVLINKS", devlinks);
+ if (r < 0)
+ return r;
+ }
+
device->property_devlinks_outdated = false;
}
if (device->property_tags_outdated) {
_cleanup_free_ char *tags = NULL;
- tags = join_string_set(device->all_tags);
- if (!tags)
- return -ENOMEM;
+ r = set_strjoin(device->all_tags, ":", &tags);
+ if (r < 0)
+ return r;
- if (!streq(tags, ":")) {
+ if (!isempty(tags)) {
r = device_add_property_internal(device, "TAGS", tags);
if (r < 0)
return r;
}
- free(tags);
- tags = join_string_set(device->current_tags);
- if (!tags)
- return -ENOMEM;
+ tags = mfree(tags);
+ r = set_strjoin(device->current_tags, ":", &tags);
+ if (r < 0)
+ return r;
- if (!streq(tags, ":")) {
+ if (!isempty(tags)) {
r = device_add_property_internal(device, "CURRENT_TAGS", tags);
if (r < 0)
return r;
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "device-enumerator-private.h"
+#include "device-internal.h"
#include "device-private.h"
#include "device-util.h"
#include "hashmap.h"
+#include "nulstr-util.h"
#include "string-util.h"
#include "tests.h"
#include "time-util.h"
assert_se(n_new_dev <= 10);
}
+static void test_sd_device_new_from_nulstr(void) {
+ const char *devlinks =
+ "/dev/disk/by-partuuid/1290d63a-42cc-4c71-b87c-xxxxxxxxxxxx\0"
+ "/dev/disk/by-path/pci-0000:00:0f.0-scsi-0:0:0:0-part3\0"
+ "/dev/disk/by-label/Arch\\x20Linux\0"
+ "/dev/disk/by-uuid/a07b87e5-4af5-4a59-bde9-yyyyyyyyyyyy\0"
+ "/dev/disk/by-partlabel/Arch\\x20Linux\0"
+ "\0";
+
+ _cleanup_(sd_device_unrefp) sd_device *device = NULL, *from_nulstr = NULL;
+ _cleanup_free_ uint8_t *nulstr_copy = NULL;
+ const char *devlink;
+ const uint8_t *nulstr;
+ size_t len;
+
+ log_info("/* %s */", __func__);
+
+ assert_se(sd_device_new_from_syspath(&device, "/sys/class/net/lo") >= 0);
+
+ /* Yeah, of course, setting devlink to the loopback interface is nonsense. But this is just a
+ * test for generating and parsing nulstr. For issue #17772. */
+ NULSTR_FOREACH(devlink, devlinks) {
+ log_device_info(device, "setting devlink: %s", devlink);
+ assert_se(device_add_devlink(device, devlink) >= 0);
+ assert_se(set_contains(device->devlinks, devlink));
+ }
+
+ /* These properties are necessary for device_new_from_nulstr(). See device_verify(). */
+ assert_se(device_add_property_internal(device, "SEQNUM", "1") >= 0);
+ assert_se(device_add_property_internal(device, "ACTION", "change") >= 0);
+
+ assert_se(device_get_properties_nulstr(device, &nulstr, &len) >= 0);
+ assert_se(nulstr_copy = newdup(uint8_t, nulstr, len));
+ assert_se(device_new_from_nulstr(&from_nulstr, nulstr_copy, len) >= 0);
+
+ NULSTR_FOREACH(devlink, devlinks) {
+ log_device_info(from_nulstr, "checking devlink: %s", devlink);
+ assert_se(set_contains(from_nulstr->devlinks, devlink));
+ }
+}
+
int main(int argc, char **argv) {
test_setup_logging(LOG_INFO);
test_sd_device_enumerator_subsystems();
test_sd_device_enumerator_filter_subsystem();
+ test_sd_device_new_from_nulstr();
+
return 0;
}
#include "sd-messages.h"
#include "alloc-util.h"
+#include "async.h"
#include "fd-util.h"
#include "logind-button.h"
#include "missing_input.h"
#include "string-util.h"
#include "util.h"
-#include "async.h"
#define CONST_MAX5(a, b, c, d, e) CONST_MAX(CONST_MAX(a, b), CONST_MAX(CONST_MAX(c, d), e))
sd_event_source_unref(b->io_event_source);
sd_event_source_unref(b->check_event_source);
- if (b->fd >= 0)
- /* If the device has been unplugged close() returns
- * ENODEV, let's ignore this, hence we don't use
- * safe_close() */
- (void) asynchronous_close(b->fd);
+ asynchronous_close(b->fd);
free(b->name);
free(b->seat);
}
int button_set_seat(Button *b, const char *sn) {
- char *s;
-
assert(b);
- assert(sn);
- s = strdup(sn);
- if (!s)
- return -ENOMEM;
-
- free(b->seat);
- b->seat = s;
-
- return 0;
+ return free_and_strdup(&b->seat, sn);
}
static void button_lid_switch_handle_action(Manager *manager, bool is_edge) {
}
int button_open(Button *b) {
- _cleanup_close_ int fd = -1;
+ _cleanup_(asynchronous_closep) int fd = -1;
const char *p;
char name[256];
int r;
assert(b);
- b->fd = safe_close(b->fd);
+ b->fd = asynchronous_close(b->fd);
p = strjoina("/dev/input/", b->name);
r = button_suitable(fd);
if (r < 0)
return log_warning_errno(r, "Failed to determine whether input device %s is relevant to us: %m", p);
- if (r == 0) {
- b->fd = TAKE_FD(fd);
+ if (r == 0)
return log_debug_errno(SYNTHETIC_ERRNO(EADDRNOTAVAIL),
"Device %s does not expose keys or switches relevant to us, ignoring.", p);
- }
-
+
if (ioctl(fd, EVIOCGNAME(sizeof name), name) < 0)
return log_error_errno(errno, "Failed to get input name for %s: %m", p);
* PID1 because 16MB of free space is required. */
#define TMPFS_LIMITS_RUN ",size=20%,nr_inodes=800k"
-/* The limit used for various nested tmpfs mounts, in paricular for guests started by systemd-nspawn.
+/* The limit used for various nested tmpfs mounts, in particular for guests started by systemd-nspawn.
* 10% of RAM (using 16GB of RAM as a baseline) translates to 400k inodes (assuming 4k each) and 25%
* translates to 1M inodes.
* (On the host, /tmp is configured through a .mount unit file.) */
#if HAVE_QRENCODE
#include <qrencode.h>
+#include "alloc-util.h"
#include "dlfcn-util.h"
#include "locale-util.h"
#include "terminal-util.h"
#define ANSI_WHITE_ON_BLACK "\033[40;37;1m"
+static void *qrcode_dl = NULL;
+
+static QRcode* (*sym_QRcode_encodeString)(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive) = NULL;
+static void (*sym_QRcode_free)(QRcode *qrcode) = NULL;
+
+int dlopen_qrencode(void) {
+ _cleanup_(dlclosep) void *dl = NULL;
+ int r;
+
+ if (qrcode_dl)
+ return 0; /* Already loaded */
+
+ dl = dlopen("libqrencode.so.4", RTLD_LAZY);
+ if (!dl)
+ return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
+ "libqrcode support is not installed: %s", dlerror());
+
+ r = dlsym_many_and_warn(
+ dl,
+ LOG_DEBUG,
+ DLSYM_ARG(QRcode_encodeString),
+ DLSYM_ARG(QRcode_free),
+ NULL);
+ if (r < 0)
+ return r;
+
+ /* Note that we never release the reference here, because there's no real reason to, after all this
+ * was traditionally a regular shared library dependency which lives forever too. */
+ qrcode_dl = TAKE_PTR(dl);
+ return 1;
+}
+
static void print_border(FILE *output, unsigned width) {
/* Four rows of border */
for (unsigned y = 0; y < 4; y += 2) {
}
int print_qrcode(FILE *out, const char *header, const char *string) {
- QRcode* (*sym_QRcode_encodeString)(const char *string, int version, QRecLevel level, QRencodeMode hint, int casesensitive);
- void (*sym_QRcode_free)(QRcode *qrcode);
- _cleanup_(dlclosep) void *dl = NULL;
QRcode* qr;
int r;
if (!is_locale_utf8() || !colors_enabled())
return -EOPNOTSUPP;
- dl = dlopen("libqrencode.so.4", RTLD_LAZY);
- if (!dl)
- return log_debug_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
- "QRCODE support is not installed: %s", dlerror());
-
- r = dlsym_many_and_warn(
- dl,
- LOG_DEBUG,
- DLSYM_ARG(QRcode_encodeString),
- DLSYM_ARG(QRcode_free),
- NULL);
+ r = dlopen_qrencode();
if (r < 0)
return r;
#include <errno.h>
#if HAVE_QRENCODE
+int dlopen_qrencode(void);
+
int print_qrcode(FILE *out, const char *header, const char *string);
#else
static inline int print_qrcode(FILE *out, const char *header, const char *string) {
libshared],
[]],
+ [['src/test/test-dlopen-so.c'],
+ [libshared],
+ []],
+
[['src/test/test-job-type.c'],
[libcore,
libshared],
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <dlfcn.h>
+#include <stdlib.h>
+
+#include "cryptsetup-util.h"
+#include "idn-util.h"
+#include "macro.h"
+#include "main-func.h"
+#include "pwquality-util.h"
+#include "qrcode-util.h"
+#include "tests.h"
+
+static int run(int argc, char **argv) {
+ test_setup_logging(LOG_DEBUG);
+
+ /* Try to load each of our weak library dependencies once. This is supposed to help finding cases
+ * where .so versions change and distributions update, but systemd doesn't have the new so names
+ * around yet. */
+
+#if HAVE_LIBIDN2 || HAVE_LIBIDN
+ assert_se(dlopen_idn() >= 0);
+#endif
+
+#if HAVE_LIBCRYPTSETUP
+ assert_se(dlopen_cryptsetup() >= 0);
+#endif
+
+#if HAVE_PWQUALITY
+ assert_se(dlopen_pwquality() >= 0);
+#endif
+
+#if HAVE_QRENCODE
+ assert_se(dlopen_qrencode() >= 0);
+#endif
+
+ return 0;
+}
+
+DEFINE_MAIN_FUNCTION(run);
assert_se(set_size(m) == 2);
}
+static void test_set_strjoin(void) {
+ _cleanup_set_free_ Set *m = NULL;
+ _cleanup_free_ char *joined = NULL;
+
+ assert_se(set_strjoin(m, NULL, &joined) >= 0);
+ assert_se(!joined);
+ assert_se(set_strjoin(m, "", &joined) >= 0);
+ assert_se(!joined);
+ assert_se(set_strjoin(m, " ", &joined) >= 0);
+ assert_se(!joined);
+ assert_se(set_strjoin(m, "xxx", &joined) >= 0);
+ assert_se(!joined);
+
+ assert_se(set_put_strdup(&m, "aaa") == 1);
+
+ assert_se(set_strjoin(m, NULL, &joined) >= 0);
+ assert_se(streq(joined, "aaa"));
+
+ joined = mfree(joined);
+ assert_se(set_strjoin(m, "", &joined) >= 0);
+ assert_se(streq(joined, "aaa"));
+
+ joined = mfree(joined);
+ assert_se(set_strjoin(m, " ", &joined) >= 0);
+ assert_se(streq(joined, "aaa"));
+
+ joined = mfree(joined);
+ assert_se(set_strjoin(m, "xxx", &joined) >= 0);
+ assert_se(streq(joined, "aaa"));
+
+ assert_se(set_put_strdup(&m, "bbb") == 1);
+ assert_se(set_put_strdup(&m, "aaa") == 0);
+
+ joined = mfree(joined);
+ assert_se(set_strjoin(m, NULL, &joined) >= 0);
+ assert_se(STR_IN_SET(joined, "aaabbb", "bbbaaa"));
+
+ joined = mfree(joined);
+ assert_se(set_strjoin(m, "", &joined) >= 0);
+ assert_se(STR_IN_SET(joined, "aaabbb", "bbbaaa"));
+
+ joined = mfree(joined);
+ assert_se(set_strjoin(m, " ", &joined) >= 0);
+ assert_se(STR_IN_SET(joined, "aaa bbb", "bbb aaa"));
+
+ joined = mfree(joined);
+ assert_se(set_strjoin(m, "xxx", &joined) >= 0);
+ assert_se(STR_IN_SET(joined, "aaaxxxbbb", "bbbxxxaaa"));
+}
+
int main(int argc, const char *argv[]) {
test_set_steal_first();
test_set_free_with_destructor();
test_set_ensure_allocated();
test_set_ensure_put();
test_set_ensure_consume();
+ test_set_strjoin();
return 0;
}
if (!filename)
return log_oom();
- if (!add && unlink(filename) == 0)
- (void) rmdir(dirname);
-
- if (add)
- do {
+ if (!add) {
+ if (unlink(filename) == 0)
+ (void) rmdir(dirname);
+ } else
+ for (;;) {
_cleanup_close_ int fd = -1;
r = mkdir_parents(filename, 0755);
if (!IN_SET(r, 0, -ENOENT))
- break;
+ return r;
+
fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444);
- if (fd < 0)
- r = -errno;
- } while (r == -ENOENT);
+ if (fd >= 0)
+ break;
+ if (errno != ENOENT)
+ return -errno;
+ }
/* If the database entry is not written yet we will just do one iteration and possibly wrong symlink
* will be fixed in the second invocation. */
switch (type) {
case UDEV_CTRL_SET_LOG_LEVEL:
log_debug("Received udev control message (SET_LOG_LEVEL), setting log_level=%i", value->intval);
- log_set_max_level_realm(LOG_REALM_UDEV, value->intval);
- log_set_max_level_realm(LOG_REALM_SYSTEMD, value->intval);
+ log_set_max_level_all_realms(value->intval);
manager_kill_workers(manager);
break;
case UDEV_CTRL_STOP_EXEC_QUEUE:
for i in $initdir{,/usr}/{sbin,bin}/* $initdir{,/usr}/lib/systemd/{,tests/{,manual/,unsafe/}}*; do
LD_LIBRARY_PATH="${LD_LIBRARY_PATH:+$LD_LIBRARY_PATH:}$(get_ldpath $i):$(get_ldpath $i)/src/udev" inst_libs $i
done
+
+ # A number of dependencies is now optional via dlopen, so the install
+ # script will not pick them up, since it looks at linkage.
+ for lib in libcryptsetup libidn libidn2 pwquality libqrencode; do
+ if pkg-config --exists ${lib}; then
+ path=$(pkg-config --variable=libdir ${lib})
+ if ! [[ ${lib} =~ ^lib ]]; then
+ lib="lib${lib}"
+ fi
+ inst_libs "${path}/${lib}.so"
+ inst_library "${path}/${lib}.so"
+ fi
+ done
}
cleanup_loopdev() {
set -ex
set -o pipefail
+function has_tag_internal() {
+ udevadm info /dev/null | sed -n '/E: '$1'=/ {s/E: '$1'=/:/; s/$/:/; p}' | grep -q ":$2:"
+}
+
+function has_tag() {
+ has_tag_internal TAGS $1
+}
+
+function has_current_tag() {
+ has_tag_internal CURRENT_TAGS $1
+}
+
mkdir -p /run/udev/rules.d/
! test -f /run/udev/tags/added/c1:3 &&
! test -f /run/udev/tags/changed/c1:3 &&
- udevadm info /dev/null | grep -q -v 'E: TAGS=.*:added:.*' &&
- udevadm info /dev/null | grep -q -v 'E: CURRENT_TAGS=.*:added:.*' &&
- udevadm info /dev/null | grep -q -v 'E: TAGS=.*:changed:.*' &&
- udevadm info /dev/null | grep -q -v 'E: CURRENT_TAGS=.*:changed:.*'
+ ! has_tag added &&
+ ! has_current_tag added &&
+ ! has_tag changed &&
+ ! has_current_tag changed
cat > /run/udev/rules.d/50-testsuite.rules <<EOF
ACTION=="add", SUBSYSTEM=="mem", KERNEL=="null", TAG+="added"
while : ; do
test -f /run/udev/tags/added/c1:3 &&
! test -f /run/udev/tags/changed/c1:3 &&
- udevadm info /dev/null | grep -q 'E: TAGS=.*:added:.*' &&
- udevadm info /dev/null | grep -q 'E: CURRENT_TAGS=.*:added:.*' &&
- udevadm info /dev/null | grep -q -v 'E: TAGS=.*:changed:.*' &&
- udevadm info /dev/null | grep -q -v 'E: CURRENT_TAGS=.*:changed:.*' &&
+ has_tag added &&
+ has_current_tag added &&
+ ! has_tag changed &&
+ ! has_current_tag changed &&
break
sleep .5
while : ; do
test -f /run/udev/tags/added/c1:3 &&
test -f /run/udev/tags/changed/c1:3 &&
- udevadm info /dev/null | grep -q 'E: TAGS=.*:added:.*' &&
- udevadm info /dev/null | grep -q -v 'E: CURRENT_TAGS=.*:added:.*' &&
- udevadm info /dev/null | grep -q 'E: TAGS=.*:changed:.*' &&
- udevadm info /dev/null | grep -q 'E: CURRENT_TAGS=.*:changed:.*' &&
+ has_tag added &&
+ ! has_current_tag added &&
+ has_tag changed &&
+ has_current_tag changed &&
break
sleep .5
while : ; do
test -f /run/udev/tags/added/c1:3 &&
test -f /run/udev/tags/changed/c1:3 &&
- udevadm info /dev/null | grep -q 'E: TAGS=.*:added:.*' &&
- udevadm info /dev/null | grep -q 'E: CURRENT_TAGS=.*:added:.*' &&
- udevadm info /dev/null | grep -q 'E: TAGS=.*:changed:.*' &&
- udevadm info /dev/null | grep -q -v 'E: CURRENT_TAGS=.*:changed:.*' &&
+ has_tag added &&
+ has_current_tag added &&
+ has_tag changed &&
+ ! has_current_tag changed &&
break
sleep .5
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_BROADCAST CAP_NET_RAW
DeviceAllow=char-* rw
ExecStart=!!@rootlibexecdir@/systemd-networkd
+ExecReload=networkctl reload
LockPersonality=yes
MemoryDenyWriteExecute=yes
NoNewPrivileges=yes