1 /* SPDX-License-Identifier: LGPL-2.1+ */
10 #include "alloc-util.h"
15 #include "format-util.h"
17 #include "logind-dbus.h"
18 #include "logind-inhibit.h"
20 #include "parse-util.h"
21 #include "path-util.h"
22 #include "string-table.h"
23 #include "string-util.h"
24 #include "tmpfile-util.h"
25 #include "user-util.h"
28 static void inhibitor_remove_fifo(Inhibitor
*i
);
30 int inhibitor_new(Inhibitor
**ret
, Manager
*m
, const char* id
) {
31 _cleanup_(inhibitor_freep
) Inhibitor
*i
= NULL
;
38 i
= new(Inhibitor
, 1);
44 .what
= _INHIBIT_WHAT_INVALID
,
45 .mode
= _INHIBIT_MODE_INVALID
,
50 i
->state_file
= path_join("/run/systemd/inhibit", id
);
54 i
->id
= basename(i
->state_file
);
56 r
= hashmap_put(m
->inhibitors
, i
->id
, i
);
64 Inhibitor
* inhibitor_free(Inhibitor
*i
) {
72 sd_event_source_unref(i
->event_source
);
73 safe_close(i
->fifo_fd
);
75 hashmap_remove(i
->manager
->inhibitors
, i
->id
);
77 /* Note that we don't remove neither the state file nor the fifo path here, since we want both to
78 * survive daemon restarts */
85 static int inhibitor_save(Inhibitor
*i
) {
86 _cleanup_free_
char *temp_path
= NULL
;
87 _cleanup_fclose_
FILE *f
= NULL
;
92 r
= mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0, MKDIR_WARN_MODE
);
96 r
= fopen_temporary(i
->state_file
, &f
, &temp_path
);
100 (void) fchmod(fileno(f
), 0644);
103 "# This is private data. Do not parse.\n"
108 inhibit_what_to_string(i
->what
),
109 inhibit_mode_to_string(i
->mode
),
114 _cleanup_free_
char *cc
= NULL
;
116 cc
= cescape(i
->who
);
122 fprintf(f
, "WHO=%s\n", cc
);
126 _cleanup_free_
char *cc
= NULL
;
128 cc
= cescape(i
->why
);
134 fprintf(f
, "WHY=%s\n", cc
);
138 fprintf(f
, "FIFO=%s\n", i
->fifo_path
);
140 r
= fflush_and_check(f
);
144 if (rename(temp_path
, i
->state_file
) < 0) {
152 (void) unlink(i
->state_file
);
155 (void) unlink(temp_path
);
157 return log_error_errno(r
, "Failed to save inhibit data %s: %m", i
->state_file
);
160 static int bus_manager_send_inhibited_change(Inhibitor
*i
) {
161 const char *property
;
165 property
= i
->mode
== INHIBIT_BLOCK
? "BlockInhibited" : "DelayInhibited";
167 return manager_send_changed(i
->manager
, property
, NULL
);
170 int inhibitor_start(Inhibitor
*i
) {
176 dual_timestamp_get(&i
->since
);
178 log_debug("Inhibitor %s (%s) pid="PID_FMT
" uid="UID_FMT
" mode=%s started.",
179 strna(i
->who
), strna(i
->why
),
181 inhibit_mode_to_string(i
->mode
));
187 bus_manager_send_inhibited_change(i
);
192 void inhibitor_stop(Inhibitor
*i
) {
196 log_debug("Inhibitor %s (%s) pid="PID_FMT
" uid="UID_FMT
" mode=%s stopped.",
197 strna(i
->who
), strna(i
->why
),
199 inhibit_mode_to_string(i
->mode
));
201 inhibitor_remove_fifo(i
);
204 (void) unlink(i
->state_file
);
208 bus_manager_send_inhibited_change(i
);
211 int inhibitor_load(Inhibitor
*i
) {
226 r
= parse_env_file(NULL
, i
->state_file
,
233 "FIFO", &i
->fifo_path
);
235 return log_error_errno(r
, "Failed to read %s: %m", i
->state_file
);
237 w
= what
? inhibit_what_from_string(what
) : 0;
241 mm
= mode
? inhibit_mode_from_string(mode
) : INHIBIT_BLOCK
;
246 r
= parse_uid(uid
, &i
->uid
);
248 log_debug_errno(r
, "Failed to parse UID of inhibitor: %s", uid
);
252 r
= parse_pid(pid
, &i
->pid
);
254 log_debug_errno(r
, "Failed to parse PID of inhibitor: %s", pid
);
258 r
= cunescape(who
, 0, &cc
);
262 free_and_replace(i
->who
, cc
);
266 r
= cunescape(why
, 0, &cc
);
270 free_and_replace(i
->why
, cc
);
274 _cleanup_close_
int fd
= -1;
276 /* Let's re-open the FIFO on both sides, and close the writing side right away */
277 fd
= inhibitor_create_fifo(i
);
279 return log_error_errno(fd
, "Failed to reopen FIFO: %m");
285 static int inhibitor_dispatch_fifo(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
286 Inhibitor
*i
= userdata
;
289 assert(fd
== i
->fifo_fd
);
298 int inhibitor_create_fifo(Inhibitor
*i
) {
305 r
= mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0, MKDIR_WARN_MODE
);
309 i
->fifo_path
= strjoin("/run/systemd/inhibit/", i
->id
, ".ref");
313 if (mkfifo(i
->fifo_path
, 0600) < 0 && errno
!= EEXIST
)
317 /* Open reading side */
318 if (i
->fifo_fd
< 0) {
319 i
->fifo_fd
= open(i
->fifo_path
, O_RDONLY
|O_CLOEXEC
|O_NONBLOCK
);
324 if (!i
->event_source
) {
325 r
= sd_event_add_io(i
->manager
->event
, &i
->event_source
, i
->fifo_fd
, 0, inhibitor_dispatch_fifo
, i
);
329 r
= sd_event_source_set_priority(i
->event_source
, SD_EVENT_PRIORITY_IDLE
-10);
333 (void) sd_event_source_set_description(i
->event_source
, "inhibitor-ref");
336 /* Open writing side */
337 r
= open(i
->fifo_path
, O_WRONLY
|O_CLOEXEC
|O_NONBLOCK
);
344 static void inhibitor_remove_fifo(Inhibitor
*i
) {
347 i
->event_source
= sd_event_source_unref(i
->event_source
);
348 i
->fifo_fd
= safe_close(i
->fifo_fd
);
351 (void) unlink(i
->fifo_path
);
352 i
->fifo_path
= mfree(i
->fifo_path
);
356 bool inhibitor_is_orphan(Inhibitor
*i
) {
368 if (pipe_eof(i
->fifo_fd
) != 0)
374 InhibitWhat
manager_inhibit_what(Manager
*m
, InhibitMode mm
) {
377 InhibitWhat what
= 0;
381 HASHMAP_FOREACH(i
, m
->inhibitors
, j
)
382 if (i
->mode
== mm
&& i
->started
)
388 static int pid_is_active(Manager
*m
, pid_t pid
) {
392 /* Get client session. This is not what you are looking for these days.
394 r
= manager_get_session_by_pid(m
, pid
, &s
);
398 /* If there's no session assigned to it, then it's globally
399 * active on all ttys */
403 return session_is_active(s
);
406 bool manager_is_inhibited(
410 dual_timestamp
*since
,
411 bool ignore_inactive
,
414 Inhibitor
**offending
) {
418 struct dual_timestamp ts
= DUAL_TIMESTAMP_NULL
;
419 bool inhibited
= false;
422 assert(w
> 0 && w
< _INHIBIT_WHAT_MAX
);
424 HASHMAP_FOREACH(i
, m
->inhibitors
, j
) {
434 if (ignore_inactive
&& pid_is_active(m
, i
->pid
) <= 0)
437 if (ignore_uid
&& i
->uid
== uid
)
441 i
->since
.monotonic
< ts
.monotonic
)
456 const char *inhibit_what_to_string(InhibitWhat w
) {
457 static thread_local
char buffer
[97];
460 if (w
< 0 || w
>= _INHIBIT_WHAT_MAX
)
464 if (w
& INHIBIT_SHUTDOWN
)
465 p
= stpcpy(p
, "shutdown:");
466 if (w
& INHIBIT_SLEEP
)
467 p
= stpcpy(p
, "sleep:");
468 if (w
& INHIBIT_IDLE
)
469 p
= stpcpy(p
, "idle:");
470 if (w
& INHIBIT_HANDLE_POWER_KEY
)
471 p
= stpcpy(p
, "handle-power-key:");
472 if (w
& INHIBIT_HANDLE_SUSPEND_KEY
)
473 p
= stpcpy(p
, "handle-suspend-key:");
474 if (w
& INHIBIT_HANDLE_HIBERNATE_KEY
)
475 p
= stpcpy(p
, "handle-hibernate-key:");
476 if (w
& INHIBIT_HANDLE_LID_SWITCH
)
477 p
= stpcpy(p
, "handle-lid-switch:");
487 InhibitWhat
inhibit_what_from_string(const char *s
) {
488 InhibitWhat what
= 0;
489 const char *word
, *state
;
492 FOREACH_WORD_SEPARATOR(word
, l
, s
, ":", state
) {
493 if (l
== 8 && strneq(word
, "shutdown", l
))
494 what
|= INHIBIT_SHUTDOWN
;
495 else if (l
== 5 && strneq(word
, "sleep", l
))
496 what
|= INHIBIT_SLEEP
;
497 else if (l
== 4 && strneq(word
, "idle", l
))
498 what
|= INHIBIT_IDLE
;
499 else if (l
== 16 && strneq(word
, "handle-power-key", l
))
500 what
|= INHIBIT_HANDLE_POWER_KEY
;
501 else if (l
== 18 && strneq(word
, "handle-suspend-key", l
))
502 what
|= INHIBIT_HANDLE_SUSPEND_KEY
;
503 else if (l
== 20 && strneq(word
, "handle-hibernate-key", l
))
504 what
|= INHIBIT_HANDLE_HIBERNATE_KEY
;
505 else if (l
== 17 && strneq(word
, "handle-lid-switch", l
))
506 what
|= INHIBIT_HANDLE_LID_SWITCH
;
508 return _INHIBIT_WHAT_INVALID
;
514 static const char* const inhibit_mode_table
[_INHIBIT_MODE_MAX
] = {
515 [INHIBIT_BLOCK
] = "block",
516 [INHIBIT_DELAY
] = "delay"
519 DEFINE_STRING_TABLE_LOOKUP(inhibit_mode
, InhibitMode
);