2 This file is part of systemd.
4 Copyright 2012 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 #include "alloc-util.h"
29 #include "formats-util.h"
30 #include "logind-inhibit.h"
32 #include "parse-util.h"
33 #include "string-table.h"
34 #include "string-util.h"
35 #include "user-util.h"
38 Inhibitor
* inhibitor_new(Manager
*m
, const char* id
) {
43 i
= new0(Inhibitor
, 1);
47 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) {
64 void inhibitor_free(Inhibitor
*i
) {
67 hashmap_remove(i
->manager
->inhibitors
, i
->id
);
69 inhibitor_remove_fifo(i
);
75 unlink(i
->state_file
);
82 int inhibitor_save(Inhibitor
*i
) {
83 _cleanup_free_
char *temp_path
= NULL
;
84 _cleanup_fclose_
FILE *f
= NULL
;
89 r
= mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0);
93 r
= fopen_temporary(i
->state_file
, &f
, &temp_path
);
97 fchmod(fileno(f
), 0644);
100 "# This is private data. Do not parse.\n"
105 inhibit_what_to_string(i
->what
),
106 inhibit_mode_to_string(i
->mode
),
111 _cleanup_free_
char *cc
= NULL
;
113 cc
= cescape(i
->who
);
119 fprintf(f
, "WHO=%s\n", cc
);
123 _cleanup_free_
char *cc
= NULL
;
125 cc
= cescape(i
->why
);
131 fprintf(f
, "WHY=%s\n", cc
);
135 fprintf(f
, "FIFO=%s\n", i
->fifo_path
);
137 r
= fflush_and_check(f
);
141 if (rename(temp_path
, i
->state_file
) < 0) {
149 (void) unlink(i
->state_file
);
152 (void) unlink(temp_path
);
154 return log_error_errno(r
, "Failed to save inhibit data %s: %m", i
->state_file
);
157 int inhibitor_start(Inhibitor
*i
) {
163 dual_timestamp_get(&i
->since
);
165 log_debug("Inhibitor %s (%s) pid="PID_FMT
" uid="UID_FMT
" mode=%s started.",
166 strna(i
->who
), strna(i
->why
),
168 inhibit_mode_to_string(i
->mode
));
174 manager_send_changed(i
->manager
, i
->mode
== INHIBIT_BLOCK
? "BlockInhibited" : "DelayInhibited", NULL
);
179 int inhibitor_stop(Inhibitor
*i
) {
183 log_debug("Inhibitor %s (%s) pid="PID_FMT
" uid="UID_FMT
" mode=%s stopped.",
184 strna(i
->who
), strna(i
->why
),
186 inhibit_mode_to_string(i
->mode
));
189 unlink(i
->state_file
);
193 manager_send_changed(i
->manager
, i
->mode
== INHIBIT_BLOCK
? "BlockInhibited" : "DelayInhibited", NULL
);
198 int inhibitor_load(Inhibitor
*i
) {
213 r
= parse_env_file(i
->state_file
, NEWLINE
,
220 "FIFO", &i
->fifo_path
,
225 w
= what
? inhibit_what_from_string(what
) : 0;
229 mm
= mode
? inhibit_mode_from_string(mode
) : INHIBIT_BLOCK
;
234 r
= parse_uid(uid
, &i
->uid
);
240 r
= parse_pid(pid
, &i
->pid
);
246 r
= cunescape(who
, 0, &cc
);
255 r
= cunescape(why
, 0, &cc
);
266 fd
= inhibitor_create_fifo(i
);
273 static int inhibitor_dispatch_fifo(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
274 Inhibitor
*i
= userdata
;
277 assert(fd
== i
->fifo_fd
);
286 int inhibitor_create_fifo(Inhibitor
*i
) {
293 r
= mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0);
297 i
->fifo_path
= strjoin("/run/systemd/inhibit/", i
->id
, ".ref", NULL
);
301 if (mkfifo(i
->fifo_path
, 0600) < 0 && errno
!= EEXIST
)
305 /* Open reading side */
306 if (i
->fifo_fd
< 0) {
307 i
->fifo_fd
= open(i
->fifo_path
, O_RDONLY
|O_CLOEXEC
|O_NDELAY
);
312 if (!i
->event_source
) {
313 r
= sd_event_add_io(i
->manager
->event
, &i
->event_source
, i
->fifo_fd
, 0, inhibitor_dispatch_fifo
, i
);
317 r
= sd_event_source_set_priority(i
->event_source
, SD_EVENT_PRIORITY_IDLE
-10);
322 /* Open writing side */
323 r
= open(i
->fifo_path
, O_WRONLY
|O_CLOEXEC
|O_NDELAY
);
330 void inhibitor_remove_fifo(Inhibitor
*i
) {
333 i
->event_source
= sd_event_source_unref(i
->event_source
);
334 i
->fifo_fd
= safe_close(i
->fifo_fd
);
337 unlink(i
->fifo_path
);
338 i
->fifo_path
= mfree(i
->fifo_path
);
342 InhibitWhat
manager_inhibit_what(Manager
*m
, InhibitMode mm
) {
345 InhibitWhat what
= 0;
349 HASHMAP_FOREACH(i
, m
->inhibitors
, j
)
356 static int pid_is_active(Manager
*m
, pid_t pid
) {
360 r
= manager_get_session_by_pid(m
, pid
, &s
);
364 /* If there's no session assigned to it, then it's globally
365 * active on all ttys */
369 return session_is_active(s
);
372 bool manager_is_inhibited(
376 dual_timestamp
*since
,
377 bool ignore_inactive
,
380 Inhibitor
**offending
) {
384 struct dual_timestamp ts
= DUAL_TIMESTAMP_NULL
;
385 bool inhibited
= false;
388 assert(w
> 0 && w
< _INHIBIT_WHAT_MAX
);
390 HASHMAP_FOREACH(i
, m
->inhibitors
, j
) {
397 if (ignore_inactive
&& pid_is_active(m
, i
->pid
) <= 0)
400 if (ignore_uid
&& i
->uid
== uid
)
404 i
->since
.monotonic
< ts
.monotonic
)
419 const char *inhibit_what_to_string(InhibitWhat w
) {
420 static thread_local
char buffer
[97];
423 if (w
< 0 || w
>= _INHIBIT_WHAT_MAX
)
427 if (w
& INHIBIT_SHUTDOWN
)
428 p
= stpcpy(p
, "shutdown:");
429 if (w
& INHIBIT_SLEEP
)
430 p
= stpcpy(p
, "sleep:");
431 if (w
& INHIBIT_IDLE
)
432 p
= stpcpy(p
, "idle:");
433 if (w
& INHIBIT_HANDLE_POWER_KEY
)
434 p
= stpcpy(p
, "handle-power-key:");
435 if (w
& INHIBIT_HANDLE_SUSPEND_KEY
)
436 p
= stpcpy(p
, "handle-suspend-key:");
437 if (w
& INHIBIT_HANDLE_HIBERNATE_KEY
)
438 p
= stpcpy(p
, "handle-hibernate-key:");
439 if (w
& INHIBIT_HANDLE_LID_SWITCH
)
440 p
= stpcpy(p
, "handle-lid-switch:");
450 InhibitWhat
inhibit_what_from_string(const char *s
) {
451 InhibitWhat what
= 0;
452 const char *word
, *state
;
455 FOREACH_WORD_SEPARATOR(word
, l
, s
, ":", state
) {
456 if (l
== 8 && strneq(word
, "shutdown", l
))
457 what
|= INHIBIT_SHUTDOWN
;
458 else if (l
== 5 && strneq(word
, "sleep", l
))
459 what
|= INHIBIT_SLEEP
;
460 else if (l
== 4 && strneq(word
, "idle", l
))
461 what
|= INHIBIT_IDLE
;
462 else if (l
== 16 && strneq(word
, "handle-power-key", l
))
463 what
|= INHIBIT_HANDLE_POWER_KEY
;
464 else if (l
== 18 && strneq(word
, "handle-suspend-key", l
))
465 what
|= INHIBIT_HANDLE_SUSPEND_KEY
;
466 else if (l
== 20 && strneq(word
, "handle-hibernate-key", l
))
467 what
|= INHIBIT_HANDLE_HIBERNATE_KEY
;
468 else if (l
== 17 && strneq(word
, "handle-lid-switch", l
))
469 what
|= INHIBIT_HANDLE_LID_SWITCH
;
471 return _INHIBIT_WHAT_INVALID
;
477 static const char* const inhibit_mode_table
[_INHIBIT_MODE_MAX
] = {
478 [INHIBIT_BLOCK
] = "block",
479 [INHIBIT_DELAY
] = "delay"
482 DEFINE_STRING_TABLE_LOOKUP(inhibit_mode
, InhibitMode
);