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/>.
29 #include "formats-util.h"
31 #include "string-util.h"
33 #include "logind-inhibit.h"
35 Inhibitor
* inhibitor_new(Manager
*m
, const char* id
) {
40 i
= new0(Inhibitor
, 1);
44 i
->state_file
= strappend("/run/systemd/inhibit/", id
);
50 i
->id
= basename(i
->state_file
);
52 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
);
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
);