chiark / gitweb /
Fix service file to match installed elogind binary location
[elogind.git] / src / login / elogind-dbus.c
1 /***
2   This file is part of elogind.
3
4   Copyright 2017 Sven Eden
5
6   elogind is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as published by
8   the Free Software Foundation; either version 2.1 of the License, or
9   (at your option) any later version.
10
11   elogind is distributed in the hope that it will be useful, but
12   WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14   Lesser General Public License for more details.
15
16   You should have received a copy of the GNU Lesser General Public License
17   along with elogind; If not, see <http://www.gnu.org/licenses/>.
18 ***/
19
20
21 #include "bus-common-errors.h"
22 #include "bus-error.h"
23 #include "bus-util.h"
24 #include "elogind-dbus.h"
25 #include "fd-util.h"
26 #include "process-util.h"
27 #include "sd-messages.h"
28 #include "sleep.h"
29 #include "sleep-config.h"
30 #include "string-util.h"
31 #include "strv.h"
32 #include "update-utmp.h"
33 #include "user-util.h"
34
35
36 static int bus_manager_log_shutdown(
37                 Manager *m,
38                 InhibitWhat w,
39                 HandleAction action) {
40
41          const char *p, *q;
42
43          assert(m);
44
45          if (w != INHIBIT_SHUTDOWN)
46                  return 0;
47
48          switch (action) {
49          case HANDLE_POWEROFF:
50                  p = "MESSAGE=System is powering down.";
51                  q = "SHUTDOWN=power-off";
52                  break;
53          case HANDLE_HALT:
54                  p = "MESSAGE=System is halting.";
55                  q = "SHUTDOWN=halt";
56                  break;
57          case HANDLE_REBOOT:
58                  p = "MESSAGE=System is rebooting.";
59                  q = "SHUTDOWN=reboot";
60                  break;
61          case HANDLE_KEXEC:
62                  p = "MESSAGE=System is rebooting with kexec.";
63                  q = "SHUTDOWN=kexec";
64                  break;
65          default:
66                  p = "MESSAGE=System is shutting down.";
67                  q = NULL;
68          }
69
70         if (isempty(m->wall_message))
71                 p = strjoina(p, ".");
72         else
73                 p = strjoina(p, " (", m->wall_message, ").");
74
75         return log_struct(LOG_NOTICE,
76                           "MESSAGE_ID=" SD_MESSAGE_SHUTDOWN_STR,
77                           p,
78                           q,
79                           NULL);
80 }
81
82 /* elogind specific helper to make HALT and REBOOT possible. */
83 static int run_helper(const char *helper) {
84         int pid = fork();
85         if (pid < 0) {
86                 return log_error_errno(errno, "Failed to fork: %m");
87         }
88
89         if (pid == 0) {
90                 /* Child */
91
92                 close_all_fds(NULL, 0);
93
94                 execlp(helper, helper, NULL);
95                 log_error_errno(errno, "Failed to execute %s: %m", helper);
96                 _exit(EXIT_FAILURE);
97         }
98
99         return wait_for_terminate_and_warn(helper, pid, true);
100 }
101
102 /* elogind specific executor */
103 static int shutdown_or_sleep(Manager *m, HandleAction action) {
104
105         assert(m);
106
107         switch (action) {
108         case HANDLE_POWEROFF:
109                 return run_helper(HALT);
110         case HANDLE_REBOOT:
111                 return run_helper(REBOOT);
112         case HANDLE_HALT:
113                 return run_helper(HALT);
114         case HANDLE_KEXEC:
115                 return run_helper(KEXEC);
116         case HANDLE_SUSPEND:
117                 return do_sleep("suspend", m->suspend_mode, m->suspend_state);
118         case HANDLE_HIBERNATE:
119                 return do_sleep("hibernate", m->hibernate_mode, m->hibernate_state);
120         case HANDLE_HYBRID_SLEEP:
121                 return do_sleep("hybrid-sleep", m->hybrid_sleep_mode, m->hybrid_sleep_state);
122         default:
123                 return -EINVAL;
124         }
125 }
126
127 static int execute_shutdown_or_sleep(
128                 Manager *m,
129                 InhibitWhat w,
130                 HandleAction action,
131                 sd_bus_error *error) {
132
133         char** argv_utmp = NULL;
134         int r;
135
136         assert(m);
137         assert(w >= 0);
138         assert(w < _INHIBIT_WHAT_MAX);
139
140         bus_manager_log_shutdown(m, w, action);
141
142         if (IN_SET(action, HANDLE_HALT, HANDLE_POWEROFF, HANDLE_REBOOT)) {
143
144                 /* As we have no systemd update-utmp daemon running, we have to
145                  * set the relevant utmp/wtmp entries ourselves.
146                  */
147
148                 if (strv_extend(&argv_utmp, "elogind") < 0)
149                         return log_oom();
150
151                 if (HANDLE_REBOOT == action) {
152                         if (strv_extend(&argv_utmp, "reboot") < 0)
153                                 return log_oom();
154                 } else {
155                         if (strv_extend(&argv_utmp, "shutdown") < 0)
156                                 return log_oom();
157                 }
158
159                  /* This comes from our patched update-utmp/update-utmp.c */
160                 update_utmp(2, argv_utmp, m->bus);
161                 strv_free(argv_utmp);
162         }
163
164         /* Now perform the requested action */
165         r = shutdown_or_sleep(m, action);
166
167         /* no more pending actions, whether this failed or not */
168         m->pending_action = HANDLE_IGNORE;
169
170         /* As elogind can not rely on a systemd manager to call all
171          * sleeping processes to wake up, we have to tell them all
172          * by ourselves. */
173         if (w == INHIBIT_SLEEP) {
174                 send_prepare_for(m, w, false);
175                 m->action_what = 0;
176         } else
177                 m->action_what = w;
178
179         if (r < 0)
180                 return r;
181
182         /* Make sure the lid switch is ignored for a while */
183         manager_set_lid_switch_ignore(m, now(CLOCK_MONOTONIC) + m->holdoff_timeout_usec);
184
185         return 0;
186 }
187
188 int manager_dispatch_delayed(Manager *manager, bool timeout) {
189
190         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
191         Inhibitor *offending = NULL;
192         int r;
193
194         assert(manager);
195
196         if ( (0 == manager->action_what) || (HANDLE_IGNORE == manager->pending_action) )
197                 return 0;
198
199         if (manager_is_inhibited(manager, manager->action_what, INHIBIT_DELAY, NULL, false, false, 0, &offending)) {
200                 _cleanup_free_ char *comm = NULL, *u = NULL;
201
202                 if (!timeout)
203                         return 0;
204
205                 (void) get_process_comm(offending->pid, &comm);
206                 u = uid_to_name(offending->uid);
207
208                 log_notice("Delay lock is active (UID "UID_FMT"/%s, PID "PID_FMT"/%s) but inhibitor timeout is reached.",
209                            offending->uid, strna(u),
210                            offending->pid, strna(comm));
211         }
212
213         /* Actually do the operation */
214         r = execute_shutdown_or_sleep(manager, manager->action_what, manager->pending_action, &error);
215         if (r < 0) {
216                 log_warning("Failed to send delayed message: %s", bus_error_message(&error, r));
217
218                 manager->pending_action = HANDLE_IGNORE;
219                 manager->action_what    = 0;
220                 /* It is not a critical error for elogind if suspending fails */
221         }
222
223         return 1;
224 }
225
226 static int delay_shutdown_or_sleep(
227                 Manager *m,
228                 InhibitWhat w,
229                 HandleAction action) {
230
231         int r;
232         usec_t timeout_val;
233
234         assert(m);
235         assert(w >= 0);
236         assert(w < _INHIBIT_WHAT_MAX);
237
238         timeout_val = now(CLOCK_MONOTONIC) + m->inhibit_delay_max;
239
240         if (m->inhibit_timeout_source) {
241                 r = sd_event_source_set_time(m->inhibit_timeout_source, timeout_val);
242                 if (r < 0)
243                         return log_error_errno(r, "sd_event_source_set_time() failed: %m");
244
245                 r = sd_event_source_set_enabled(m->inhibit_timeout_source, SD_EVENT_ONESHOT);
246                 if (r < 0)
247                         return log_error_errno(r, "sd_event_source_set_enabled() failed: %m");
248         } else {
249                 r = sd_event_add_time(m->event, &m->inhibit_timeout_source, CLOCK_MONOTONIC,
250                                       timeout_val, 0, manager_inhibit_timeout_handler, m);
251                 if (r < 0)
252                         return r;
253         }
254
255         m->pending_action = action;
256         m->action_what = w;
257
258         return 0;
259 }
260
261 int bus_manager_shutdown_or_sleep_now_or_later(
262                 Manager *m,
263                 HandleAction action,
264                 InhibitWhat w,
265                 sd_bus_error *error) {
266
267         bool delayed;
268         int r;
269
270         assert(m);
271         assert(w >= 0);
272         assert(w <= _INHIBIT_WHAT_MAX);
273
274         /* Tell everybody to prepare for shutdown/sleep */
275         send_prepare_for(m, w, true);
276
277         delayed =
278                 m->inhibit_delay_max > 0 &&
279                 manager_is_inhibited(m, w, INHIBIT_DELAY, NULL, false, false, 0, NULL);
280
281         log_debug_elogind("%s called for %s (%sdelayed)", __FUNCTION__,
282                           handle_action_to_string(action),
283                           delayed ? "" : "NOT ");
284
285         if (delayed)
286                 /* Shutdown is delayed, keep in mind what we
287                  * want to do, and start a timeout */
288                 r = delay_shutdown_or_sleep(m, w, action);
289         else
290                 /* Shutdown is not delayed, execute it
291                  * immediately */
292                 r = execute_shutdown_or_sleep(m, w, action, error);
293
294         return r;
295 }
296
297 static int method_do_shutdown_or_sleep(
298                 Manager *m,
299                 sd_bus_message *message,
300                 HandleAction sleep_action,
301                 InhibitWhat w,
302                 const char *action,
303                 const char *action_multiple_sessions,
304                 const char *action_ignore_inhibit,
305                 const char *sleep_verb,
306                 sd_bus_error *error) {
307
308         int interactive, r;
309
310         assert(m);
311         assert(message);
312         assert(w >= 0);
313         assert(w <= _INHIBIT_WHAT_MAX);
314
315         r = sd_bus_message_read(message, "b", &interactive);
316         if (r < 0)
317                 return r;
318
319         log_debug_elogind("%s called with action '%s', sleep '%s' (%sinteractive)",
320                           __FUNCTION__, action, sleep_verb,
321                           interactive ? "" : "NOT ");
322
323         /* Don't allow multiple jobs being executed at the same time */
324         if (m->action_what)
325                 return sd_bus_error_setf(error, BUS_ERROR_OPERATION_IN_PROGRESS, "There's already a shutdown or sleep operation in progress");
326
327         if (sleep_verb) {
328                 r = can_sleep(m, sleep_verb);
329                 if (r < 0)
330                         return r;
331
332                 if (r == 0)
333                         return sd_bus_error_setf(error, BUS_ERROR_SLEEP_VERB_NOT_SUPPORTED, "Sleep verb not supported");
334         }
335
336         if (IN_SET(sleep_action, HANDLE_HALT, HANDLE_POWEROFF, HANDLE_REBOOT)) {
337                 r = verify_shutdown_creds(m, message, w, interactive, action, action_multiple_sessions,
338                                           action_ignore_inhibit, error);
339                 log_debug_elogind("verify_shutdown_creds() returned %d", r);
340                 if (r != 0)
341                         return r;
342         }
343
344         r = bus_manager_shutdown_or_sleep_now_or_later(m, sleep_action, w, error);
345         if (r < 0)
346                 return r;
347
348         return sd_bus_reply_method_return(message, NULL);
349 }
350
351 int method_poweroff(sd_bus_message *message, void *userdata, sd_bus_error *error) {
352         Manager *m = userdata;
353
354         log_debug_elogind("%s called", __FUNCTION__);
355
356         return method_do_shutdown_or_sleep(
357                         m, message,
358                         HANDLE_POWEROFF,
359                         INHIBIT_SHUTDOWN,
360                         "org.freedesktop.login1.power-off",
361                         "org.freedesktop.login1.power-off-multiple-sessions",
362                         "org.freedesktop.login1.power-off-ignore-inhibit",
363                         NULL,
364                         error);
365 }
366
367 int method_reboot(sd_bus_message *message, void *userdata, sd_bus_error *error) {
368         Manager *m = userdata;
369
370         log_debug_elogind("%s called", __FUNCTION__);
371
372         return method_do_shutdown_or_sleep(
373                         m, message,
374                         HANDLE_REBOOT,
375                         INHIBIT_SHUTDOWN,
376                         "org.freedesktop.login1.reboot",
377                         "org.freedesktop.login1.reboot-multiple-sessions",
378                         "org.freedesktop.login1.reboot-ignore-inhibit",
379                         NULL,
380                         error);
381 }
382
383 int method_suspend(sd_bus_message *message, void *userdata, sd_bus_error *error) {
384         Manager *m = userdata;
385
386         log_debug_elogind("%s called", __FUNCTION__);
387
388         return method_do_shutdown_or_sleep(
389                         m, message,
390                         HANDLE_SUSPEND,
391                         INHIBIT_SLEEP,
392                         "org.freedesktop.login1.suspend",
393                         "org.freedesktop.login1.suspend-multiple-sessions",
394                         "org.freedesktop.login1.suspend-ignore-inhibit",
395                         "suspend",
396                         error);
397 }
398
399 int manager_scheduled_shutdown_handler(
400                         sd_event_source *s,
401                         uint64_t usec,
402                         void *userdata) {
403
404         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
405         Manager *m = userdata;
406         HandleAction action;
407         int r;
408
409         assert(m);
410
411         if (isempty(m->scheduled_shutdown_type))
412                 return 0;
413
414         if (streq(m->scheduled_shutdown_type, "halt"))
415                 action = HANDLE_HALT;
416         else if (streq(m->scheduled_shutdown_type, "poweroff"))
417                 action = HANDLE_POWEROFF;
418         else
419                 action = HANDLE_REBOOT;
420
421         r = execute_shutdown_or_sleep(m, 0, action, &error);
422         if (r < 0)
423                 return log_error_errno(r, "Unable to execute transition to %s: %m", m->scheduled_shutdown_type);
424
425         return 0;
426 }
427
428 int method_hibernate(sd_bus_message *message, void *userdata, sd_bus_error *error) {
429         Manager *m = userdata;
430
431         log_debug_elogind("%s called", __FUNCTION__);
432
433         return method_do_shutdown_or_sleep(
434                         m, message,
435                         HANDLE_HIBERNATE,
436                         INHIBIT_SLEEP,
437                         "org.freedesktop.login1.hibernate",
438                         "org.freedesktop.login1.hibernate-multiple-sessions",
439                         "org.freedesktop.login1.hibernate-ignore-inhibit",
440                         "hibernate",
441                         error);
442 }
443
444 int method_hybrid_sleep(sd_bus_message *message, void *userdata, sd_bus_error *error) {
445         Manager *m = userdata;
446
447         log_debug_elogind("%s called", __FUNCTION__);
448
449         return method_do_shutdown_or_sleep(
450                         m, message,
451                         HANDLE_HYBRID_SLEEP,
452                         INHIBIT_SLEEP,
453                         "org.freedesktop.login1.hibernate",
454                         "org.freedesktop.login1.hibernate-multiple-sessions",
455                         "org.freedesktop.login1.hibernate-ignore-inhibit",
456                         "hybrid-sleep",
457                         error);
458 }