logind/systemctl: introduce SetWallMessage and --message

Enable unprivileged users to set wall message on a shutdown
operation. When the message is set via the --message option,
it is logged together with the default shutdown message.

$ systemctl reboot --message "Applied kernel updates."

$ journalctl -b -1
...
systemd-logind[27]: System is rebooting. (Applied kernel updates.)
...
This commit is contained in:
Jan Synacek 2015-08-24 14:54:22 +02:00
parent 72aa2c2a20
commit 9ef15026c0
5 changed files with 130 additions and 45 deletions

View file

@ -473,6 +473,18 @@
</listitem>
</varlistentry>
<varlistentry>
<term><option>--message=</option></term>
<listitem>
<para>When used with <command>halt</command>,
<command>poweroff</command>, <command>reboot</command> or
<command>kexec</command>, set a short message explaining the reason
for the operation. The message will be logged together with the
default shutdown message.</para>
</listitem>
</varlistentry>
<varlistentry>
<term><option>--now</option></term>

View file

@ -1339,7 +1339,8 @@ static int bus_manager_log_shutdown(
InhibitWhat w,
const char *unit_name) {
const char *p, *q;
const char *p;
const char *q;
assert(m);
assert(unit_name);
@ -1364,6 +1365,9 @@ static int bus_manager_log_shutdown(
q = NULL;
}
if (m->wall_message)
p = strjoina(p, " (", m->wall_message, ")", NULL);
return log_struct(LOG_NOTICE,
LOG_MESSAGE_ID(SD_MESSAGE_SHUTDOWN),
p,
@ -2282,6 +2286,44 @@ static int method_can_reboot_to_firmware_setup(
return sd_bus_reply_method_return(message, "s", result);
}
static int method_set_wall_message(
sd_bus_message *message,
void *userdata,
sd_bus_error *error) {
int r;
Manager *m = userdata;
char *wall_message;
bool enable_wall_messages;
assert(message);
assert(m);
r = sd_bus_message_read(message, "sb", &wall_message, &enable_wall_messages);
if (r < 0)
return r;
r = bus_verify_polkit_async(message,
CAP_SYS_ADMIN,
"org.freedesktop.login1.set-wall-message",
false,
UID_INVALID,
&m->polkit_registry,
error);
if (r < 0)
return r;
if (r == 0)
return 1; /* Will call us back */
r = free_and_strdup(&m->wall_message, wall_message);
if (r < 0)
return log_oom();
m->enable_wall_messages = enable_wall_messages;
return sd_bus_reply_method_return(message, NULL);
}
static int method_inhibit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
_cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
const char *who, *why, *what, *mode;
@ -2463,6 +2505,7 @@ const sd_bus_vtable manager_vtable[] = {
SD_BUS_METHOD("Inhibit", "ssss", "h", method_inhibit, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("CanRebootToFirmwareSetup", NULL, "s", method_can_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetRebootToFirmwareSetup", "b", NULL, method_set_reboot_to_firmware_setup, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("SetWallMessage", "sb", NULL, method_set_wall_message, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_SIGNAL("SessionNew", "so", 0),
SD_BUS_SIGNAL("SessionRemoved", "so", 0),

View file

@ -180,6 +180,10 @@
send_interface="org.freedesktop.login1.Manager"
send_member="SetRebootToFirmwareSetup"/>
<allow send_destination="org.freedesktop.login1"
send_interface="org.freedesktop.login1.Manager"
send_member="SetWallMessage"/>
<allow send_destination="org.freedesktop.login1"
send_interface="org.freedesktop.login1.Manager"
send_member="AttachDevice"/>

View file

@ -150,6 +150,7 @@
<allow_inactive>auth_admin_keep</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.set-wall-message</annotate>
</action>
<action id="org.freedesktop.login1.power-off-multiple-sessions">
@ -182,6 +183,7 @@
<allow_inactive>auth_admin_keep</allow_inactive>
<allow_active>yes</allow_active>
</defaults>
<annotate key="org.freedesktop.policykit.imply">org.freedesktop.login1.set-wall-message</annotate>
</action>
<action id="org.freedesktop.login1.reboot-multiple-sessions">
@ -300,4 +302,14 @@
</defaults>
</action>
<action id="org.freedesktop.login1.set-wall-message">
<_description>Set a wall message</_description>
<_message>Authentication is required to set a wall message</_message>
<defaults>
<allow_any>auth_admin_keep</allow_any>
<allow_inactive>auth_admin_keep</allow_inactive>
<allow_active>auth_admin_keep</allow_active>
</defaults>
</action>
</policyconfig>

View file

@ -2794,6 +2794,33 @@ static int reboot_with_logind(sd_bus *bus, enum action a) {
return -EINVAL;
}
if (!strv_isempty(arg_wall)) {
_cleanup_free_ char *m;
m = strv_join(arg_wall, " ");
if (!m)
return log_oom();
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"SetWallMessage",
&error,
NULL,
"sb",
m,
!arg_no_wall);
if (r < 0) {
log_warning_errno(r, "Failed to set wall message, ignoring: %s",
bus_error_message(&error, r));
sd_bus_error_free(&error);
}
}
r = sd_bus_call_method(
bus,
"org.freedesktop.login1",
@ -6260,6 +6287,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
ARG_PRESET_MODE,
ARG_FIRMWARE_SETUP,
ARG_NOW,
ARG_MESSAGE,
};
static const struct option options[] = {
@ -6304,6 +6332,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
{ "preset-mode", required_argument, NULL, ARG_PRESET_MODE },
{ "firmware-setup", no_argument, NULL, ARG_FIRMWARE_SETUP },
{ "now", no_argument, NULL, ARG_NOW },
{ "message", required_argument, NULL, ARG_MESSAGE },
{}
};
@ -6588,6 +6617,11 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
arg_now = true;
break;
case ARG_MESSAGE:
if (strv_extend(&arg_wall, optarg) < 0)
return log_oom();
break;
case '?':
return -EINVAL;
@ -7356,30 +7390,20 @@ static int halt_main(sd_bus *bus) {
if (!m)
return log_oom();
r = sd_bus_set_property(
b,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"WallMessage",
&error,
"s", m);
if (r < 0) {
log_warning_errno(r, "Failed to set WallMessage property in logind: %s",
bus_error_message(&error, r));
sd_bus_error_free(&error);
}
r = sd_bus_call_method(
b,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"SetWallMessage",
&error,
NULL,
"sb",
m,
!arg_no_wall);
r = sd_bus_set_property(
b,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"EnableWallMessages",
&error,
"b", !arg_no_wall);
if (r < 0) {
log_warning_errno(r, "Failed to set EnableWallMessages property in logind: %s",
log_warning_errno(r, "Failed to set wall message, ignoring: %s",
bus_error_message(&error, r));
sd_bus_error_free(&error);
}
@ -7537,30 +7561,20 @@ int main(int argc, char*argv[]) {
}
}
r = sd_bus_set_property(
b,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"WallMessage",
&error,
"s", arg_wall);
if (r < 0) {
log_warning_errno(r, "Failed to set WallMessage property in logind: %s",
bus_error_message(&error, r));
sd_bus_error_free(&error);
}
r = sd_bus_call_method(
b,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"SetWallMessage",
&error,
NULL,
"sb",
m,
!arg_no_wall);
r = sd_bus_set_property(
b,
"org.freedesktop.login1",
"/org/freedesktop/login1",
"org.freedesktop.login1.Manager",
"EnableWallMessages",
&error,
"b", !arg_no_wall);
if (r < 0) {
log_warning_errno(r, "Failed to set EnableWallMessages property in logind: %s",
log_warning_errno(r, "Failed to set wall message, ignoring: %s",
bus_error_message(&error, r));
sd_bus_error_free(&error);
}