1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2012 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include "alloc-util.h"
30 #include "format-util.h"
31 #include "logind-inhibit.h"
33 #include "parse-util.h"
34 #include "string-table.h"
35 #include "string-util.h"
36 #include "user-util.h"
39 Inhibitor
* inhibitor_new(Manager
*m
, const char* id
) {
44 i
= new0(Inhibitor
, 1);
48 i
->state_file
= strappend("/run/systemd/inhibit/", id
);
52 i
->id
= basename(i
->state_file
);
54 if (hashmap_put(m
->inhibitors
, i
->id
, i
) < 0) {
65 void inhibitor_free(Inhibitor
*i
) {
68 hashmap_remove(i
->manager
->inhibitors
, i
->id
);
70 inhibitor_remove_fifo(i
);
76 unlink(i
->state_file
);
83 int inhibitor_save(Inhibitor
*i
) {
84 _cleanup_free_
char *temp_path
= NULL
;
85 _cleanup_fclose_
FILE *f
= NULL
;
90 r
= mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0, false);
94 r
= fopen_temporary(i
->state_file
, &f
, &temp_path
);
98 fchmod(fileno(f
), 0644);
101 "# This is private data. Do not parse.\n"
106 inhibit_what_to_string(i
->what
),
107 inhibit_mode_to_string(i
->mode
),
112 _cleanup_free_
char *cc
= NULL
;
114 cc
= cescape(i
->who
);
120 fprintf(f
, "WHO=%s\n", cc
);
124 _cleanup_free_
char *cc
= NULL
;
126 cc
= cescape(i
->why
);
132 fprintf(f
, "WHY=%s\n", cc
);
136 fprintf(f
, "FIFO=%s\n", i
->fifo_path
);
138 r
= fflush_and_check(f
);
142 if (rename(temp_path
, i
->state_file
) < 0) {
150 (void) unlink(i
->state_file
);
153 (void) unlink(temp_path
);
155 return log_error_errno(r
, "Failed to save inhibit data %s: %m", i
->state_file
);
158 int inhibitor_start(Inhibitor
*i
) {
164 dual_timestamp_get(&i
->since
);
166 log_debug("Inhibitor %s (%s) pid="PID_FMT
" uid="UID_FMT
" mode=%s started.",
167 strna(i
->who
), strna(i
->why
),
169 inhibit_mode_to_string(i
->mode
));
175 manager_send_changed(i
->manager
, i
->mode
== INHIBIT_BLOCK
? "BlockInhibited" : "DelayInhibited", NULL
);
180 int inhibitor_stop(Inhibitor
*i
) {
184 log_debug("Inhibitor %s (%s) pid="PID_FMT
" uid="UID_FMT
" mode=%s stopped.",
185 strna(i
->who
), strna(i
->why
),
187 inhibit_mode_to_string(i
->mode
));
190 unlink(i
->state_file
);
194 manager_send_changed(i
->manager
, i
->mode
== INHIBIT_BLOCK
? "BlockInhibited" : "DelayInhibited", NULL
);
199 int inhibitor_load(Inhibitor
*i
) {
214 r
= parse_env_file(i
->state_file
, NEWLINE
,
221 "FIFO", &i
->fifo_path
,
226 w
= what
? inhibit_what_from_string(what
) : 0;
230 mm
= mode
? inhibit_mode_from_string(mode
) : INHIBIT_BLOCK
;
235 r
= parse_uid(uid
, &i
->uid
);
241 r
= parse_pid(pid
, &i
->pid
);
247 r
= cunescape(who
, 0, &cc
);
256 r
= cunescape(why
, 0, &cc
);
267 fd
= inhibitor_create_fifo(i
);
274 static int inhibitor_dispatch_fifo(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
275 Inhibitor
*i
= userdata
;
278 assert(fd
== i
->fifo_fd
);
287 int inhibitor_create_fifo(Inhibitor
*i
) {
294 r
= mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0, false);
298 i
->fifo_path
= strjoin("/run/systemd/inhibit/", i
->id
, ".ref");
302 if (mkfifo(i
->fifo_path
, 0600) < 0 && errno
!= EEXIST
)
306 /* Open reading side */
307 if (i
->fifo_fd
< 0) {
308 i
->fifo_fd
= open(i
->fifo_path
, O_RDONLY
|O_CLOEXEC
|O_NDELAY
);
313 if (!i
->event_source
) {
314 r
= sd_event_add_io(i
->manager
->event
, &i
->event_source
, i
->fifo_fd
, 0, inhibitor_dispatch_fifo
, i
);
318 r
= sd_event_source_set_priority(i
->event_source
, SD_EVENT_PRIORITY_IDLE
-10);
323 /* Open writing side */
324 r
= open(i
->fifo_path
, O_WRONLY
|O_CLOEXEC
|O_NDELAY
);
331 void inhibitor_remove_fifo(Inhibitor
*i
) {
334 i
->event_source
= sd_event_source_unref(i
->event_source
);
335 i
->fifo_fd
= safe_close(i
->fifo_fd
);
338 unlink(i
->fifo_path
);
339 i
->fifo_path
= mfree(i
->fifo_path
);
343 InhibitWhat
manager_inhibit_what(Manager
*m
, InhibitMode mm
) {
346 InhibitWhat what
= 0;
350 HASHMAP_FOREACH(i
, m
->inhibitors
, j
)
351 if (i
->mode
== mm
&& i
->started
)
357 static int pid_is_active(Manager
*m
, pid_t pid
) {
361 /* Get client session. This is not what you are looking for these days.
363 r
= manager_get_session_by_pid(m
, pid
, &s
);
367 /* If there's no session assigned to it, then it's globally
368 * active on all ttys */
372 return session_is_active(s
);
375 bool manager_is_inhibited(
379 dual_timestamp
*since
,
380 bool ignore_inactive
,
383 Inhibitor
**offending
) {
387 struct dual_timestamp ts
= DUAL_TIMESTAMP_NULL
;
388 bool inhibited
= false;
391 assert(w
> 0 && w
< _INHIBIT_WHAT_MAX
);
393 HASHMAP_FOREACH(i
, m
->inhibitors
, j
) {
403 if (ignore_inactive
&& pid_is_active(m
, i
->pid
) <= 0)
406 if (ignore_uid
&& i
->uid
== uid
)
410 i
->since
.monotonic
< ts
.monotonic
)
425 const char *inhibit_what_to_string(InhibitWhat w
) {
426 static thread_local
char buffer
[97];
429 if (w
< 0 || w
>= _INHIBIT_WHAT_MAX
)
433 if (w
& INHIBIT_SHUTDOWN
)
434 p
= stpcpy(p
, "shutdown:");
435 if (w
& INHIBIT_SLEEP
)
436 p
= stpcpy(p
, "sleep:");
437 if (w
& INHIBIT_IDLE
)
438 p
= stpcpy(p
, "idle:");
439 if (w
& INHIBIT_HANDLE_POWER_KEY
)
440 p
= stpcpy(p
, "handle-power-key:");
441 if (w
& INHIBIT_HANDLE_SUSPEND_KEY
)
442 p
= stpcpy(p
, "handle-suspend-key:");
443 if (w
& INHIBIT_HANDLE_HIBERNATE_KEY
)
444 p
= stpcpy(p
, "handle-hibernate-key:");
445 if (w
& INHIBIT_HANDLE_LID_SWITCH
)
446 p
= stpcpy(p
, "handle-lid-switch:");
456 InhibitWhat
inhibit_what_from_string(const char *s
) {
457 InhibitWhat what
= 0;
458 const char *word
, *state
;
461 FOREACH_WORD_SEPARATOR(word
, l
, s
, ":", state
) {
462 if (l
== 8 && strneq(word
, "shutdown", l
))
463 what
|= INHIBIT_SHUTDOWN
;
464 else if (l
== 5 && strneq(word
, "sleep", l
))
465 what
|= INHIBIT_SLEEP
;
466 else if (l
== 4 && strneq(word
, "idle", l
))
467 what
|= INHIBIT_IDLE
;
468 else if (l
== 16 && strneq(word
, "handle-power-key", l
))
469 what
|= INHIBIT_HANDLE_POWER_KEY
;
470 else if (l
== 18 && strneq(word
, "handle-suspend-key", l
))
471 what
|= INHIBIT_HANDLE_SUSPEND_KEY
;
472 else if (l
== 20 && strneq(word
, "handle-hibernate-key", l
))
473 what
|= INHIBIT_HANDLE_HIBERNATE_KEY
;
474 else if (l
== 17 && strneq(word
, "handle-lid-switch", l
))
475 what
|= INHIBIT_HANDLE_LID_SWITCH
;
477 return _INHIBIT_WHAT_INVALID
;
483 static const char* const inhibit_mode_table
[_INHIBIT_MODE_MAX
] = {
484 [INHIBIT_BLOCK
] = "block",
485 [INHIBIT_DELAY
] = "delay"
488 DEFINE_STRING_TABLE_LOOKUP(inhibit_mode
, InhibitMode
);