SeatRemoved(s seat_id,
o object_path);
PrepareForShutdown(b start);
+ PrepareForShutdownWithMetadata(b start,
+ a{sv} metadata);
PrepareForSleep(b start);
properties:
@org.freedesktop.DBus.Property.EmitsChangedSignal("false")
<variablelist class="dbus-signal" generated="True" extra-ref="PrepareForShutdown"/>
+ <variablelist class="dbus-signal" generated="True" extra-ref="PrepareForShutdownWithMetadata"/>
+
<variablelist class="dbus-signal" generated="True" extra-ref="PrepareForSleep"/>
<variablelist class="dbus-property" generated="True" extra-ref="EnableWallMessages"/>
logs in or out, or a seat is added or removed. They each contain the ID of the object plus the object
path.</para>
- <para>The <function>PrepareForShutdown()</function> and <function>PrepareForSleep()</function> signals
- are sent right before (with the argument <literal>true</literal>) or after (with the argument
+ <para>The <function>PrepareForShutdown</function>,
+ <function>PrepareForShutdownWithMetadata</function>, and <function>PrepareForSleep</function>
+ signals are sent right before (with the argument <literal>true</literal>) or after (with the argument
<literal>false</literal>) the system goes down for reboot/poweroff and suspend/hibernate,
respectively. This may be used by applications to save data on disk, release memory, or do other jobs
that should be done shortly before shutdown/sleep, in conjunction with delay inhibitor locks. After
completion of this work they should release their inhibition locks in order to not delay the operation
any further. For more information see
- <ulink url="https://www.freedesktop.org/wiki/Software/systemd/inhibit">Inhibitor Locks</ulink>.
- </para>
+ <ulink url="https://www.freedesktop.org/wiki/Software/systemd/inhibit">Inhibitor Locks</ulink>. The
+ <function>PrepareForShutdownWithMetadata()</function> signal additionally sends a list of key/value
+ pair metadata fields. Currently it sends a <varname>type</varname> string which defines the type of
+ shutdown. The type can be one of <literal>power-off</literal>, <literal>reboot</literal>,
+ <literal>halt</literal>, <literal>kexec</literal> or <literal>soft-reboot</literal>. This signal is
+ sent first, followed by <function>PrepareForShutdown</function> (for backward compatibility).</para>
</refsect2>
<refsect2>
return r;
}
-static int send_prepare_for(Manager *m, InhibitWhat w, bool _active) {
- int active = _active;
+static int send_prepare_for(Manager *m, const HandleActionData *a, bool _active) {
+ int k = 0, r, active = _active;
assert(m);
- assert(IN_SET(w, INHIBIT_SHUTDOWN, INHIBIT_SLEEP));
-
- return sd_bus_emit_signal(m->bus,
- "/org/freedesktop/login1",
- "org.freedesktop.login1.Manager",
- w == INHIBIT_SHUTDOWN ? "PrepareForShutdown" : "PrepareForSleep",
- "b",
- active);
+ assert(a);
+ assert(IN_SET(a->inhibit_what, INHIBIT_SHUTDOWN, INHIBIT_SLEEP));
+
+ /* We need to send both old and new signal for backward compatibility. The newer one allows clients
+ * to know which type of reboot is going to happen, as they might be doing different actions (e.g.:
+ * on soft-reboot), and it is sent first, so that clients know that if they receive the old one
+ * first then they don't have to wait for the new one, as it means it's not supported. So, do not
+ * change the order here, as it is an API. */
+ if (a->inhibit_what == INHIBIT_SHUTDOWN) {
+ k = sd_bus_emit_signal(m->bus,
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ "PrepareForShutdownWithMetadata",
+ "ba{sv}",
+ active,
+ 1,
+ "type",
+ "s",
+ handle_action_to_string(a->handle));
+ if (k < 0)
+ log_debug_errno(k, "Failed to emit PrepareForShutdownWithMetadata(): %m");
+ }
+
+ r = sd_bus_emit_signal(m->bus,
+ "/org/freedesktop/login1",
+ "org.freedesktop.login1.Manager",
+ a->inhibit_what == INHIBIT_SHUTDOWN ? "PrepareForShutdown" : "PrepareForSleep",
+ "b",
+ active);
+ if (r < 0)
+ log_debug_errno(r, "Failed to emit PrepareForShutdown(): %m");
+
+ return RET_GATHER(k, r);
}
static int execute_shutdown_or_sleep(
error:
/* Tell people that they now may take a lock again */
- (void) send_prepare_for(m, a->inhibit_what, false);
+ (void) send_prepare_for(m, a, false);
return r;
}
a->target, load_state);
/* Tell everybody to prepare for shutdown/sleep */
- (void) send_prepare_for(m, a->inhibit_what, true);
+ (void) send_prepare_for(m, a, true);
delayed =
m->inhibit_delay_max > 0 &&
SD_BUS_SIGNAL_WITH_ARGS("PrepareForShutdown",
SD_BUS_ARGS("b", start),
0),
+ SD_BUS_SIGNAL_WITH_ARGS("PrepareForShutdownWithMetadata",
+ SD_BUS_ARGS("b", start, "a{sv}", metadata),
+ 0),
SD_BUS_SIGNAL_WITH_ARGS("PrepareForSleep",
SD_BUS_ARGS("b", start),
0),
log_info("Operation '%s' finished.", inhibit_what_to_string(m->delayed_action->inhibit_what));
/* Tell people that they now may take a lock again */
- (void) send_prepare_for(m, m->delayed_action->inhibit_what, false);
+ (void) send_prepare_for(m, m->delayed_action, false);
m->action_job = mfree(m->action_job);
m->delayed_action = NULL;
read -r x <&3
test "$x" = "wuffwuff"
+ # Check that we got a PrepareForShutdownWithMetadata signal with the right type
+ test "$(jq .payload.data[1].type.data </run/testsuite82.signal)" = "\"soft-reboot\""
+
# Upload another entry
T="/dev/shm/fdstore.$RANDOM"
echo "miaumiau" >"$T"
systemd-run -p Type=notify -p DefaultDependencies=no -p IgnoreOnIsolate=yes --unit=testsuite-82-survive.service "$T"
systemd-run -p Type=exec -p DefaultDependencies=no -p IgnoreOnIsolate=yes --unit=testsuite-82-nosurvive.service sleep infinity
+ # Check that we can set up an inhibitor, and that busctl monitor sees the
+ # PrepareForShutdownWithMetadata signal and that it says 'soft-reboot'.
+ systemd-run --unit busctl.service --property StandardOutput=file:/run/testsuite82.signal \
+ busctl monitor --json=pretty --match 'sender=org.freedesktop.login1,path=/org/freedesktop/login1,interface=org.freedesktop.login1.Manager,member=PrepareForShutdownWithMetadata,type=signal'
+ systemd-run --unit inhibit.service \
+ systemd-inhibit --what=shutdown --who=test --why=test --mode=delay \
+ sleep infinity
+
# Now issue the soft reboot. We should be right back soon.
touch /run/testsuite82.touch
- systemctl --no-block soft-reboot
+ systemctl --no-block --check-inhibitors=yes soft-reboot
# Now block until the soft-boot killing spree kills us
exec sleep infinity