logind/systemctl: introduce SetWallMessage and --message
authorJan Synacek <jsynacek@redhat.com>
Mon, 24 Aug 2015 12:54:22 +0000 (14:54 +0200)
committerJan Synacek <jsynacek@redhat.com>
Tue, 25 Aug 2015 11:52:44 +0000 (13:52 +0200)
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.)
...

man/systemctl.xml
src/login/logind-dbus.c
src/login/org.freedesktop.login1.conf
src/login/org.freedesktop.login1.policy.in
src/systemctl/systemctl.c

index 0b5282b..20d1437 100644 (file)
       </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>
 
         <listitem>
index 992a9f5..5b2b36b 100644 (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),
index d8deb7b..1662d4c 100644 (file)
 
                 <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"/>
 
                 <allow send_destination="org.freedesktop.login1"
index 83e7183..23326bb 100644 (file)
                         <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">
                         <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">
                 </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>
index 1a9dbad..3cb5f61 100644 (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);
                 }