1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
30 #include "formats-util.h"
31 #include "logind-inhibit.h"
33 #include "string-util.h"
36 Inhibitor
* inhibitor_new(Manager
*m
, const char* id
) {
41 i
= new0(Inhibitor
, 1);
45 i
->state_file
= strappend("/run/systemd/inhibit/", id
);
51 i
->id
= basename(i
->state_file
);
53 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);
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);
298 i
->fifo_path
= strjoin("/run/systemd/inhibit/", i
->id
, ".ref", NULL
);
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
);
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
)
357 static int pid_is_active(Manager
*m
, pid_t pid
) {
361 r
= manager_get_session_by_pid(m
, pid
, &s
);
365 /* If there's no session assigned to it, then it's globally
366 * active on all ttys */
370 return session_is_active(s
);
373 bool manager_is_inhibited(
377 dual_timestamp
*since
,
378 bool ignore_inactive
,
381 Inhibitor
**offending
) {
385 struct dual_timestamp ts
= DUAL_TIMESTAMP_NULL
;
386 bool inhibited
= false;
389 assert(w
> 0 && w
< _INHIBIT_WHAT_MAX
);
391 HASHMAP_FOREACH(i
, m
->inhibitors
, j
) {
398 if (ignore_inactive
&& pid_is_active(m
, i
->pid
) <= 0)
401 if (ignore_uid
&& i
->uid
== uid
)
405 i
->since
.monotonic
< ts
.monotonic
)
420 const char *inhibit_what_to_string(InhibitWhat w
) {
421 static thread_local
char buffer
[97];
424 if (w
< 0 || w
>= _INHIBIT_WHAT_MAX
)
428 if (w
& INHIBIT_SHUTDOWN
)
429 p
= stpcpy(p
, "shutdown:");
430 if (w
& INHIBIT_SLEEP
)
431 p
= stpcpy(p
, "sleep:");
432 if (w
& INHIBIT_IDLE
)
433 p
= stpcpy(p
, "idle:");
434 if (w
& INHIBIT_HANDLE_POWER_KEY
)
435 p
= stpcpy(p
, "handle-power-key:");
436 if (w
& INHIBIT_HANDLE_SUSPEND_KEY
)
437 p
= stpcpy(p
, "handle-suspend-key:");
438 if (w
& INHIBIT_HANDLE_HIBERNATE_KEY
)
439 p
= stpcpy(p
, "handle-hibernate-key:");
440 if (w
& INHIBIT_HANDLE_LID_SWITCH
)
441 p
= stpcpy(p
, "handle-lid-switch:");
451 InhibitWhat
inhibit_what_from_string(const char *s
) {
452 InhibitWhat what
= 0;
453 const char *word
, *state
;
456 FOREACH_WORD_SEPARATOR(word
, l
, s
, ":", state
) {
457 if (l
== 8 && strneq(word
, "shutdown", l
))
458 what
|= INHIBIT_SHUTDOWN
;
459 else if (l
== 5 && strneq(word
, "sleep", l
))
460 what
|= INHIBIT_SLEEP
;
461 else if (l
== 4 && strneq(word
, "idle", l
))
462 what
|= INHIBIT_IDLE
;
463 else if (l
== 16 && strneq(word
, "handle-power-key", l
))
464 what
|= INHIBIT_HANDLE_POWER_KEY
;
465 else if (l
== 18 && strneq(word
, "handle-suspend-key", l
))
466 what
|= INHIBIT_HANDLE_SUSPEND_KEY
;
467 else if (l
== 20 && strneq(word
, "handle-hibernate-key", l
))
468 what
|= INHIBIT_HANDLE_HIBERNATE_KEY
;
469 else if (l
== 17 && strneq(word
, "handle-lid-switch", l
))
470 what
|= INHIBIT_HANDLE_LID_SWITCH
;
472 return _INHIBIT_WHAT_INVALID
;
478 static const char* const inhibit_mode_table
[_INHIBIT_MODE_MAX
] = {
479 [INHIBIT_BLOCK
] = "block",
480 [INHIBIT_DELAY
] = "delay"
483 DEFINE_STRING_TABLE_LOOKUP(inhibit_mode
, InhibitMode
);