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 "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
);
54 i
->id
= basename(i
->state_file
);
56 if (hashmap_put(m
->inhibitors
, i
->id
, i
) < 0) {
68 void inhibitor_free(Inhibitor
*i
) {
71 hashmap_remove(i
->manager
->inhibitors
, i
->id
);
73 inhibitor_remove_fifo(i
);
79 unlink(i
->state_file
);
86 int inhibitor_save(Inhibitor
*i
) {
87 _cleanup_free_
char *temp_path
= NULL
;
88 _cleanup_fclose_
FILE *f
= NULL
;
93 r
= mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0);
97 r
= fopen_temporary(i
->state_file
, &f
, &temp_path
);
101 fchmod(fileno(f
), 0644);
104 "# This is private data. Do not parse.\n"
109 inhibit_what_to_string(i
->what
),
110 inhibit_mode_to_string(i
->mode
),
115 _cleanup_free_
char *cc
= NULL
;
117 cc
= cescape(i
->who
);
123 fprintf(f
, "WHO=%s\n", cc
);
127 _cleanup_free_
char *cc
= NULL
;
129 cc
= cescape(i
->why
);
135 fprintf(f
, "WHY=%s\n", cc
);
139 fprintf(f
, "FIFO=%s\n", i
->fifo_path
);
141 r
= fflush_and_check(f
);
145 if (rename(temp_path
, i
->state_file
) < 0) {
153 (void) unlink(i
->state_file
);
156 (void) unlink(temp_path
);
158 return log_error_errno(r
, "Failed to save inhibit data %s: %m", i
->state_file
);
161 int inhibitor_start(Inhibitor
*i
) {
167 dual_timestamp_get(&i
->since
);
169 log_debug("Inhibitor %s (%s) pid="PID_FMT
" uid="UID_FMT
" mode=%s started.",
170 strna(i
->who
), strna(i
->why
),
172 inhibit_mode_to_string(i
->mode
));
178 manager_send_changed(i
->manager
, i
->mode
== INHIBIT_BLOCK
? "BlockInhibited" : "DelayInhibited", NULL
);
183 int inhibitor_stop(Inhibitor
*i
) {
187 log_debug("Inhibitor %s (%s) pid="PID_FMT
" uid="UID_FMT
" mode=%s stopped.",
188 strna(i
->who
), strna(i
->why
),
190 inhibit_mode_to_string(i
->mode
));
193 unlink(i
->state_file
);
197 manager_send_changed(i
->manager
, i
->mode
== INHIBIT_BLOCK
? "BlockInhibited" : "DelayInhibited", NULL
);
202 int inhibitor_load(Inhibitor
*i
) {
217 r
= parse_env_file(i
->state_file
, NEWLINE
,
224 "FIFO", &i
->fifo_path
,
229 w
= what
? inhibit_what_from_string(what
) : 0;
233 mm
= mode
? inhibit_mode_from_string(mode
) : INHIBIT_BLOCK
;
238 r
= parse_uid(uid
, &i
->uid
);
244 r
= parse_pid(pid
, &i
->pid
);
250 r
= cunescape(who
, 0, &cc
);
259 r
= cunescape(why
, 0, &cc
);
270 fd
= inhibitor_create_fifo(i
);
277 static int inhibitor_dispatch_fifo(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
278 Inhibitor
*i
= userdata
;
281 assert(fd
== i
->fifo_fd
);
290 int inhibitor_create_fifo(Inhibitor
*i
) {
297 r
= mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0);
301 i
->fifo_path
= strjoin("/run/systemd/inhibit/", i
->id
, ".ref", NULL
);
305 if (mkfifo(i
->fifo_path
, 0600) < 0 && errno
!= EEXIST
)
309 /* Open reading side */
310 if (i
->fifo_fd
< 0) {
311 i
->fifo_fd
= open(i
->fifo_path
, O_RDONLY
|O_CLOEXEC
|O_NDELAY
);
316 if (!i
->event_source
) {
317 r
= sd_event_add_io(i
->manager
->event
, &i
->event_source
, i
->fifo_fd
, 0, inhibitor_dispatch_fifo
, i
);
321 r
= sd_event_source_set_priority(i
->event_source
, SD_EVENT_PRIORITY_IDLE
);
326 /* Open writing side */
327 r
= open(i
->fifo_path
, O_WRONLY
|O_CLOEXEC
|O_NDELAY
);
334 void inhibitor_remove_fifo(Inhibitor
*i
) {
337 i
->event_source
= sd_event_source_unref(i
->event_source
);
338 i
->fifo_fd
= safe_close(i
->fifo_fd
);
341 unlink(i
->fifo_path
);
342 i
->fifo_path
= mfree(i
->fifo_path
);
346 InhibitWhat
manager_inhibit_what(Manager
*m
, InhibitMode mm
) {
349 InhibitWhat what
= 0;
353 HASHMAP_FOREACH(i
, m
->inhibitors
, j
)
360 static int pid_is_active(Manager
*m
, pid_t pid
) {
364 r
= manager_get_session_by_pid(m
, pid
, &s
);
368 /* If there's no session assigned to it, then it's globally
369 * active on all ttys */
373 return session_is_active(s
);
376 bool manager_is_inhibited(
380 dual_timestamp
*since
,
381 bool ignore_inactive
,
384 Inhibitor
**offending
) {
388 struct dual_timestamp ts
= DUAL_TIMESTAMP_NULL
;
389 bool inhibited
= false;
392 assert(w
> 0 && w
< _INHIBIT_WHAT_MAX
);
394 HASHMAP_FOREACH(i
, m
->inhibitors
, j
) {
401 if (ignore_inactive
&& pid_is_active(m
, i
->pid
) <= 0)
404 if (ignore_uid
&& i
->uid
== uid
)
408 i
->since
.monotonic
< ts
.monotonic
)
423 const char *inhibit_what_to_string(InhibitWhat w
) {
424 static thread_local
char buffer
[97];
427 if (w
< 0 || w
>= _INHIBIT_WHAT_MAX
)
431 if (w
& INHIBIT_SHUTDOWN
)
432 p
= stpcpy(p
, "shutdown:");
433 if (w
& INHIBIT_SLEEP
)
434 p
= stpcpy(p
, "sleep:");
435 if (w
& INHIBIT_IDLE
)
436 p
= stpcpy(p
, "idle:");
437 if (w
& INHIBIT_HANDLE_POWER_KEY
)
438 p
= stpcpy(p
, "handle-power-key:");
439 if (w
& INHIBIT_HANDLE_SUSPEND_KEY
)
440 p
= stpcpy(p
, "handle-suspend-key:");
441 if (w
& INHIBIT_HANDLE_HIBERNATE_KEY
)
442 p
= stpcpy(p
, "handle-hibernate-key:");
443 if (w
& INHIBIT_HANDLE_LID_SWITCH
)
444 p
= stpcpy(p
, "handle-lid-switch:");
454 InhibitWhat
inhibit_what_from_string(const char *s
) {
455 InhibitWhat what
= 0;
456 const char *word
, *state
;
459 FOREACH_WORD_SEPARATOR(word
, l
, s
, ":", state
) {
460 if (l
== 8 && strneq(word
, "shutdown", l
))
461 what
|= INHIBIT_SHUTDOWN
;
462 else if (l
== 5 && strneq(word
, "sleep", l
))
463 what
|= INHIBIT_SLEEP
;
464 else if (l
== 4 && strneq(word
, "idle", l
))
465 what
|= INHIBIT_IDLE
;
466 else if (l
== 16 && strneq(word
, "handle-power-key", l
))
467 what
|= INHIBIT_HANDLE_POWER_KEY
;
468 else if (l
== 18 && strneq(word
, "handle-suspend-key", l
))
469 what
|= INHIBIT_HANDLE_SUSPEND_KEY
;
470 else if (l
== 20 && strneq(word
, "handle-hibernate-key", l
))
471 what
|= INHIBIT_HANDLE_HIBERNATE_KEY
;
472 else if (l
== 17 && strneq(word
, "handle-lid-switch", l
))
473 what
|= INHIBIT_HANDLE_LID_SWITCH
;
475 return _INHIBIT_WHAT_INVALID
;
481 static const char* const inhibit_mode_table
[_INHIBIT_MODE_MAX
] = {
482 [INHIBIT_BLOCK
] = "block",
483 [INHIBIT_DELAY
] = "delay"
486 DEFINE_STRING_TABLE_LOOKUP(inhibit_mode
, InhibitMode
);