1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
9 #include "alloc-util.h"
11 #include "errno-list.h"
12 #include "errno-util.h"
16 #include "format-util.h"
19 #include "logind-dbus.h"
20 #include "logind-inhibit.h"
21 #include "missing_threads.h"
22 #include "mkdir-label.h"
23 #include "parse-util.h"
24 #include "path-util.h"
25 #include "string-table.h"
26 #include "string-util.h"
27 #include "tmpfile-util.h"
28 #include "user-util.h"
30 static void inhibitor_remove_fifo(Inhibitor
*i
);
32 int inhibitor_new(Manager
*m
, const char* id
, Inhibitor
**ret
) {
33 _cleanup_(inhibitor_freep
) Inhibitor
*i
= NULL
;
40 i
= new(Inhibitor
, 1);
47 .state_file
= path_join("/run/systemd/inhibit/", id
),
48 .what
= _INHIBIT_WHAT_INVALID
,
49 .mode
= _INHIBIT_MODE_INVALID
,
55 if (!i
->id
|| !i
->state_file
)
58 r
= hashmap_put(m
->inhibitors
, i
->id
, i
);
66 Inhibitor
* inhibitor_free(Inhibitor
*i
) {
74 sd_event_source_unref(i
->event_source
);
75 safe_close(i
->fifo_fd
);
77 hashmap_remove(i
->manager
->inhibitors
, i
->id
);
79 /* Note that we don't remove neither the state file nor the fifo path here, since we want both to
80 * survive daemon restarts */
90 static int inhibitor_save(Inhibitor
*i
) {
91 _cleanup_(unlink_and_freep
) char *temp_path
= NULL
;
92 _cleanup_fclose_
FILE *f
= NULL
;
97 r
= mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0, MKDIR_WARN_MODE
);
101 r
= fopen_temporary(i
->state_file
, &f
, &temp_path
);
105 (void) fchmod(fileno(f
), 0644);
108 "# This is private data. Do not parse.\n"
113 inhibit_what_to_string(i
->what
),
114 inhibit_mode_to_string(i
->mode
),
119 _cleanup_free_
char *cc
= NULL
;
121 cc
= cescape(i
->who
);
127 fprintf(f
, "WHO=%s\n", cc
);
131 _cleanup_free_
char *cc
= NULL
;
133 cc
= cescape(i
->why
);
139 fprintf(f
, "WHY=%s\n", cc
);
143 fprintf(f
, "FIFO=%s\n", i
->fifo_path
);
145 r
= fflush_and_check(f
);
149 if (rename(temp_path
, i
->state_file
) < 0) {
154 temp_path
= mfree(temp_path
);
158 (void) unlink(i
->state_file
);
160 return log_error_errno(r
, "Failed to save inhibit data %s: %m", i
->state_file
);
163 static int bus_manager_send_inhibited_change(Inhibitor
*i
) {
164 const char *property
;
168 property
= i
->mode
== INHIBIT_BLOCK
? "BlockInhibited" : "DelayInhibited";
170 return manager_send_changed(i
->manager
, property
, NULL
);
173 int inhibitor_start(Inhibitor
*i
) {
179 dual_timestamp_now(&i
->since
);
181 log_debug("Inhibitor %s (%s) pid="PID_FMT
" uid="UID_FMT
" mode=%s started.",
182 strna(i
->who
), strna(i
->why
),
184 inhibit_mode_to_string(i
->mode
));
190 bus_manager_send_inhibited_change(i
);
195 void inhibitor_stop(Inhibitor
*i
) {
199 log_debug("Inhibitor %s (%s) pid="PID_FMT
" uid="UID_FMT
" mode=%s stopped.",
200 strna(i
->who
), strna(i
->why
),
202 inhibit_mode_to_string(i
->mode
));
204 inhibitor_remove_fifo(i
);
207 (void) unlink(i
->state_file
);
211 bus_manager_send_inhibited_change(i
);
214 int inhibitor_load(Inhibitor
*i
) {
215 _cleanup_free_
char *what
= NULL
, *uid
= NULL
, *pid
= NULL
, *who
= NULL
, *why
= NULL
, *mode
= NULL
;
222 r
= parse_env_file(NULL
, i
->state_file
,
229 "FIFO", &i
->fifo_path
);
231 return log_error_errno(r
, "Failed to read %s: %m", i
->state_file
);
233 w
= what
? inhibit_what_from_string(what
) : 0;
237 mm
= mode
? inhibit_mode_from_string(mode
) : INHIBIT_BLOCK
;
242 r
= parse_uid(uid
, &i
->uid
);
244 log_debug_errno(r
, "Failed to parse UID of inhibitor: %s", uid
);
248 pidref_done(&i
->pid
);
249 r
= pidref_set_pidstr(&i
->pid
, pid
);
251 log_debug_errno(r
, "Failed to parse PID of inhibitor: %s", pid
);
255 l
= cunescape(who
, 0, &cc
);
257 return log_debug_errno(l
, "Failed to unescape \"who\" of inhibitor: %m");
259 free_and_replace(i
->who
, cc
);
263 l
= cunescape(why
, 0, &cc
);
265 return log_debug_errno(l
, "Failed to unescape \"why\" of inhibitor: %m");
267 free_and_replace(i
->why
, cc
);
271 _cleanup_close_
int fd
= -EBADF
;
273 /* Let's reopen the FIFO on both sides, and close the writing side right away */
274 fd
= inhibitor_create_fifo(i
);
276 return log_error_errno(fd
, "Failed to reopen FIFO: %m");
282 static int inhibitor_dispatch_fifo(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
283 Inhibitor
*i
= ASSERT_PTR(userdata
);
286 assert(fd
== i
->fifo_fd
);
294 int inhibitor_create_fifo(Inhibitor
*i
) {
301 r
= mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0, MKDIR_WARN_MODE
);
305 i
->fifo_path
= strjoin("/run/systemd/inhibit/", i
->id
, ".ref");
309 if (mkfifo(i
->fifo_path
, 0600) < 0 && errno
!= EEXIST
)
313 /* Open reading side */
314 if (i
->fifo_fd
< 0) {
315 i
->fifo_fd
= open(i
->fifo_path
, O_RDONLY
|O_CLOEXEC
|O_NONBLOCK
);
320 if (!i
->event_source
) {
321 r
= sd_event_add_io(i
->manager
->event
, &i
->event_source
, i
->fifo_fd
, 0, inhibitor_dispatch_fifo
, i
);
325 r
= sd_event_source_set_priority(i
->event_source
, SD_EVENT_PRIORITY_IDLE
-10);
329 (void) sd_event_source_set_description(i
->event_source
, "inhibitor-ref");
332 /* Open writing side */
333 return RET_NERRNO(open(i
->fifo_path
, O_WRONLY
|O_CLOEXEC
|O_NONBLOCK
));
336 static void inhibitor_remove_fifo(Inhibitor
*i
) {
339 i
->event_source
= sd_event_source_unref(i
->event_source
);
340 i
->fifo_fd
= safe_close(i
->fifo_fd
);
343 (void) unlink(i
->fifo_path
);
344 i
->fifo_path
= mfree(i
->fifo_path
);
348 bool inhibitor_is_orphan(Inhibitor
*i
) {
360 if (pipe_eof(i
->fifo_fd
) != 0)
366 InhibitWhat
manager_inhibit_what(Manager
*m
, InhibitMode mm
) {
368 InhibitWhat what
= 0;
372 HASHMAP_FOREACH(i
, m
->inhibitors
)
373 if (i
->mode
== mm
&& i
->started
)
379 static int pidref_is_active_session(Manager
*m
, const PidRef
*pid
) {
386 /* Get client session. This is not what you are looking for these days.
388 r
= manager_get_session_by_pidref(m
, pid
, &s
);
392 /* If there's no session assigned to it, then it's globally active on all ttys */
396 return session_is_active(s
);
399 bool manager_is_inhibited(
403 dual_timestamp
*since
,
404 bool ignore_inactive
,
407 Inhibitor
**offending
) {
410 struct dual_timestamp ts
= DUAL_TIMESTAMP_NULL
;
411 bool inhibited
= false;
415 assert(w
< _INHIBIT_WHAT_MAX
);
417 HASHMAP_FOREACH(i
, m
->inhibitors
) {
427 if (ignore_inactive
&& pidref_is_active_session(m
, &i
->pid
) <= 0)
430 if (ignore_uid
&& i
->uid
== uid
)
434 i
->since
.monotonic
< ts
.monotonic
)
449 const char *inhibit_what_to_string(InhibitWhat w
) {
450 static thread_local
char buffer
[STRLEN(
455 "handle-suspend-key:"
456 "handle-hibernate-key:"
458 "handle-reboot-key")+1];
461 if (!inhibit_what_is_valid(w
))
465 if (w
& INHIBIT_SHUTDOWN
)
466 p
= stpcpy(p
, "shutdown:");
467 if (w
& INHIBIT_SLEEP
)
468 p
= stpcpy(p
, "sleep:");
469 if (w
& INHIBIT_IDLE
)
470 p
= stpcpy(p
, "idle:");
471 if (w
& INHIBIT_HANDLE_POWER_KEY
)
472 p
= stpcpy(p
, "handle-power-key:");
473 if (w
& INHIBIT_HANDLE_SUSPEND_KEY
)
474 p
= stpcpy(p
, "handle-suspend-key:");
475 if (w
& INHIBIT_HANDLE_HIBERNATE_KEY
)
476 p
= stpcpy(p
, "handle-hibernate-key:");
477 if (w
& INHIBIT_HANDLE_LID_SWITCH
)
478 p
= stpcpy(p
, "handle-lid-switch:");
479 if (w
& INHIBIT_HANDLE_REBOOT_KEY
)
480 p
= stpcpy(p
, "handle-reboot-key:");
490 int inhibit_what_from_string(const char *s
) {
491 InhibitWhat what
= 0;
493 for (const char *p
= s
;;) {
494 _cleanup_free_
char *word
= NULL
;
497 /* A sanity check that our return values fit in an int */
498 assert_cc((int) _INHIBIT_WHAT_MAX
== _INHIBIT_WHAT_MAX
);
500 r
= extract_first_word(&p
, &word
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
506 if (streq(word
, "shutdown"))
507 what
|= INHIBIT_SHUTDOWN
;
508 else if (streq(word
, "sleep"))
509 what
|= INHIBIT_SLEEP
;
510 else if (streq(word
, "idle"))
511 what
|= INHIBIT_IDLE
;
512 else if (streq(word
, "handle-power-key"))
513 what
|= INHIBIT_HANDLE_POWER_KEY
;
514 else if (streq(word
, "handle-suspend-key"))
515 what
|= INHIBIT_HANDLE_SUSPEND_KEY
;
516 else if (streq(word
, "handle-hibernate-key"))
517 what
|= INHIBIT_HANDLE_HIBERNATE_KEY
;
518 else if (streq(word
, "handle-lid-switch"))
519 what
|= INHIBIT_HANDLE_LID_SWITCH
;
520 else if (streq(word
, "handle-reboot-key"))
521 what
|= INHIBIT_HANDLE_REBOOT_KEY
;
523 return _INHIBIT_WHAT_INVALID
;
527 static const char* const inhibit_mode_table
[_INHIBIT_MODE_MAX
] = {
528 [INHIBIT_BLOCK
] = "block",
529 [INHIBIT_DELAY
] = "delay"
532 DEFINE_STRING_TABLE_LOOKUP(inhibit_mode
, InhibitMode
);