mirror of
https://github.com/systemd/systemd.git
synced 2026-11-06 05:17:24 +00:00
udevadm-wait: send notification (#44550)
This commit is contained in:
5 files changed
+100
-6
No files matched your search
@@ -1178,6 +1178,19 @@
|
||||
<xi:include href="version-info.xml" xpointer="v251"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--notify</option></term>
|
||||
<listitem>
|
||||
<para>When specified, udevadm notifies the calling service manager with a
|
||||
<literal>READY=1</literal> message when it is ready to wait for devices to be initialized (or
|
||||
added when <option>--initialized=no</option>, or removed when <option>--removed</option>), and
|
||||
notifies with a <literal>STOPPING=1</literal> message when all devices are initialized. This may
|
||||
be useful when the command is called in a service with <varname>Type=notify</varname>.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v263"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect2>
|
||||
|
||||
|
||||
@@ -105,7 +105,7 @@ _udevadm() {
|
||||
[VERIFY_ARG]='-N --resolve-names --root'
|
||||
[CAT_STANDALONE]='--tldr --config'
|
||||
[CAT_ARG]='--root'
|
||||
[WAIT]='-t --timeout --initialized=no --removed --settle'
|
||||
[WAIT]='-t --timeout --initialized=no --removed --settle --notify'
|
||||
[LOCK]='-t --timeout -d --device -b --backing -p --print'
|
||||
)
|
||||
|
||||
|
||||
@@ -151,6 +151,7 @@ _udevadm_wait(){
|
||||
'--initialized=[Wait for devices being initialized by systemd-udevd.]:boolean:(yes no)' \
|
||||
'--removed[Wait for devices being removed.]' \
|
||||
'--settle[Also wait for udev queue being empty.]' \
|
||||
'--notify[Send notifications to service manager.]' \
|
||||
'*::devpath:_files -W /dev'
|
||||
}
|
||||
|
||||
|
||||
+37
-2
@@ -7,6 +7,7 @@
|
||||
#include "sd-json.h"
|
||||
|
||||
#include "build.h"
|
||||
#include "daemon-util.h"
|
||||
#include "device-monitor-private.h"
|
||||
#include "device-util.h"
|
||||
#include "event-util.h"
|
||||
@@ -15,6 +16,7 @@
|
||||
#include "parse-util.h"
|
||||
#include "path-util.h"
|
||||
#include "static-destruct.h"
|
||||
#include "stdio-util.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
@@ -35,6 +37,7 @@ static WaitUntil arg_wait_until = WAIT_UNTIL_INITIALIZED;
|
||||
static usec_t arg_timeout_usec = USEC_INFINITY;
|
||||
static bool arg_removed = false;
|
||||
static bool arg_settle = false;
|
||||
static bool arg_notify = false;
|
||||
static char **arg_devices = NULL;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_devices, strv_freep);
|
||||
@@ -340,6 +343,10 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
arg_settle = true;
|
||||
break;
|
||||
|
||||
OPTION_LONG("notify", NULL, "Send notifications to service manager"):
|
||||
arg_notify = true;
|
||||
break;
|
||||
|
||||
OPTION_COMMON_INTROSPECT_CLI:
|
||||
return introspect_cli(SD_JSON_FORMAT_OFF);
|
||||
}
|
||||
@@ -380,9 +387,31 @@ int verb_wait_main(int argc, char *argv[], uintptr_t _data, void *userdata) {
|
||||
"Specified path \"%s\" does not start with \"/dev/\" or \"/sys/\".", *p);
|
||||
}
|
||||
|
||||
_cleanup_free_ char *notify_message_start = NULL, *notify_message_stop = NULL, *notify_message_fail = NULL;
|
||||
if (arg_notify) {
|
||||
notify_message_start = asprintf_safe(
|
||||
"READY=1\n"
|
||||
"STATUS=Waiting for devices to be %s...",
|
||||
wait_until_to_string(arg_wait_until));
|
||||
notify_message_stop = asprintf_safe(
|
||||
"STOPPING=1\n"
|
||||
"STATUS=All devices are %s.",
|
||||
wait_until_to_string(arg_wait_until));
|
||||
notify_message_fail = asprintf_safe(
|
||||
"STATUS=Failed to wait for devices to be %s.",
|
||||
wait_until_to_string(arg_wait_until));
|
||||
if (!notify_message_start || !notify_message_stop || !notify_message_fail)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
/* Check before configuring event sources, as devices may be already initialized. */
|
||||
if (check())
|
||||
if (check()) {
|
||||
if (arg_notify) {
|
||||
(void) sd_notify(/* unset_environment= */ false, notify_message_start);
|
||||
(void) sd_notify(/* unset_environment= */ false, notify_message_stop);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_event_default(&event);
|
||||
if (r < 0)
|
||||
@@ -423,9 +452,13 @@ int verb_wait_main(int argc, char *argv[], uintptr_t _data, void *userdata) {
|
||||
return log_error_errno(r, "Failed to set up periodic timer: %m");
|
||||
}
|
||||
|
||||
_unused_ _cleanup_(notify_on_cleanup) const char *notify_message = NULL;
|
||||
if (arg_notify)
|
||||
notify_message = notify_start(notify_message_start, notify_message_fail);
|
||||
|
||||
/* Check before entering the event loop, as devices may be initialized during setting up event sources. */
|
||||
if (check())
|
||||
return 0;
|
||||
goto success;
|
||||
|
||||
r = sd_event_loop(event);
|
||||
if (r == -ETIMEDOUT)
|
||||
@@ -434,5 +467,7 @@ int verb_wait_main(int argc, char *argv[], uintptr_t _data, void *userdata) {
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Event loop failed: %m");
|
||||
|
||||
success:
|
||||
notify_message = notify_message_stop;
|
||||
return 0;
|
||||
}
|
||||
@@ -4,15 +4,60 @@ set -ex
|
||||
set -o pipefail
|
||||
|
||||
IFNAME=test-udev-aaa
|
||||
UNIT_ADD="TEST-17-UDEV-database-wait-add.service"
|
||||
UNIT_DEL="TEST-17-UDEV-database-wait-del.service"
|
||||
WORKDIR="$(mktemp -d)"
|
||||
|
||||
# shellcheck disable=SC2329
|
||||
at_exit() {
|
||||
set +e
|
||||
|
||||
systemctl stop "$UNIT_ADD" "$UNIT_DEL"
|
||||
systemctl reset-failed "$UNIT_ADD" "$UNIT_DEL"
|
||||
ip link del "$IFNAME"
|
||||
rm -rf "$WORKDIR"
|
||||
}
|
||||
trap at_exit EXIT
|
||||
|
||||
cat >"$WORKDIR/marker.sh" <<'EOF'
|
||||
#!/usr/bin/env bash
|
||||
[[ "$SERVICE_RESULT" == success ]] || exit 0
|
||||
touch "$1"
|
||||
EOF
|
||||
chmod +x "$WORKDIR/marker.sh"
|
||||
|
||||
start_wait() {
|
||||
local unit="$1"
|
||||
shift
|
||||
|
||||
systemd-run --unit="$unit" \
|
||||
--service-type=notify \
|
||||
--property="ExecStopPost=$WORKDIR/marker.sh $WORKDIR/$unit" \
|
||||
udevadm wait --timeout=10 --notify "$@"
|
||||
}
|
||||
|
||||
finish_wait() {
|
||||
local unit="$1"
|
||||
|
||||
# shellcheck disable=SC2016
|
||||
timeout 30 bash -c 'until [[ -e "$1" ]] || systemctl is-failed --quiet "$2"; do sleep 0.1; done' _ "$WORKDIR/$unit" "$unit"
|
||||
|
||||
[[ -e "$WORKDIR/$unit" ]]
|
||||
}
|
||||
|
||||
# Start watching before the interface is created, so that the creation cannot be missed.
|
||||
start_wait "$UNIT_ADD" "/sys/class/net/$IFNAME"
|
||||
ip link add "$IFNAME" type dummy
|
||||
IFINDEX=$(ip -json link show "$IFNAME" | jq '.[].ifindex')
|
||||
udevadm wait --timeout=10 "/sys/class/net/$IFNAME"
|
||||
finish_wait "$UNIT_ADD"
|
||||
# Check if the database file is created.
|
||||
[[ -e "/run/udev/data/n$IFINDEX" ]]
|
||||
|
||||
# Start watching before the interface is removed, so that the removal cannot be missed.
|
||||
start_wait "$UNIT_DEL" --removed --settle "/sys/class/net/$IFNAME"
|
||||
ip link del "$IFNAME"
|
||||
udevadm wait --timeout=10 --removed --settle "/sys/class/net/$IFNAME"
|
||||
# CHeck if the database file is removed.
|
||||
finish_wait "$UNIT_DEL"
|
||||
# Check if the database file is removed.
|
||||
[[ ! -e "/run/udev/data/n$IFINDEX" ]]
|
||||
|
||||
unshare --mount --propagation private bash -eux <<'EOF'
|
||||
|
||||
Reference in new issue
Block a user