]> git.proxmox.com Git - systemd.git/blame - src/login/logind-inhibit.c
bump version to 252.11-pve1
[systemd.git] / src / login / logind-inhibit.c
CommitLineData
a032b68d 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
663996b3
MS
2
3#include <errno.h>
4#include <fcntl.h>
bb4f798a
MB
5#include <sys/stat.h>
6#include <sys/types.h>
663996b3
MS
7#include <unistd.h>
8
db2df898 9#include "alloc-util.h"
6e866b33 10#include "env-file.h"
a032b68d 11#include "errno-list.h"
ea0999c9 12#include "errno-util.h"
db2df898
MP
13#include "escape.h"
14#include "fd-util.h"
663996b3 15#include "fileio.h"
2897b343 16#include "format-util.h"
f2dec872
BR
17#include "io-util.h"
18#include "logind-dbus.h"
db2df898 19#include "logind-inhibit.h"
ecfb185f 20#include "missing_threads.h"
ea0999c9 21#include "mkdir-label.h"
db2df898 22#include "parse-util.h"
f2dec872 23#include "path-util.h"
db2df898
MP
24#include "string-table.h"
25#include "string-util.h"
6e866b33 26#include "tmpfile-util.h"
db2df898
MP
27#include "user-util.h"
28#include "util.h"
663996b3 29
f2dec872
BR
30static void inhibitor_remove_fifo(Inhibitor *i);
31
32int inhibitor_new(Inhibitor **ret, Manager *m, const char* id) {
33 _cleanup_(inhibitor_freep) Inhibitor *i = NULL;
34 int r;
663996b3 35
f2dec872 36 assert(ret);
663996b3 37 assert(m);
f2dec872 38 assert(id);
663996b3 39
f2dec872 40 i = new(Inhibitor, 1);
663996b3 41 if (!i)
f2dec872
BR
42 return -ENOMEM;
43
44 *i = (Inhibitor) {
45 .manager = m,
46 .what = _INHIBIT_WHAT_INVALID,
47 .mode = _INHIBIT_MODE_INVALID,
48 .uid = UID_INVALID,
49 .fifo_fd = -1,
50 };
663996b3 51
f2dec872 52 i->state_file = path_join("/run/systemd/inhibit", id);
8a584da2 53 if (!i->state_file)
f2dec872 54 return -ENOMEM;
663996b3 55
60f067b4 56 i->id = basename(i->state_file);
663996b3 57
f2dec872
BR
58 r = hashmap_put(m->inhibitors, i->id, i);
59 if (r < 0)
60 return r;
663996b3 61
f2dec872
BR
62 *ret = TAKE_PTR(i);
63 return 0;
663996b3
MS
64}
65
f2dec872 66Inhibitor* inhibitor_free(Inhibitor *i) {
60f067b4 67
f2dec872
BR
68 if (!i)
69 return NULL;
663996b3 70
60f067b4
JS
71 free(i->who);
72 free(i->why);
73
f2dec872
BR
74 sd_event_source_unref(i->event_source);
75 safe_close(i->fifo_fd);
663996b3 76
812752cc
MB
77 hashmap_remove(i->manager->inhibitors, i->id);
78
f2dec872
BR
79 /* Note that we don't remove neither the state file nor the fifo path here, since we want both to
80 * survive daemon restarts */
81 free(i->state_file);
82 free(i->fifo_path);
83
f2dec872 84 return mfree(i);
663996b3
MS
85}
86
f2dec872 87static int inhibitor_save(Inhibitor *i) {
60f067b4
JS
88 _cleanup_free_ char *temp_path = NULL;
89 _cleanup_fclose_ FILE *f = NULL;
663996b3 90 int r;
663996b3
MS
91
92 assert(i);
93
b012e921 94 r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0, MKDIR_WARN_MODE);
663996b3 95 if (r < 0)
5fd56512 96 goto fail;
663996b3
MS
97
98 r = fopen_temporary(i->state_file, &f, &temp_path);
99 if (r < 0)
5fd56512 100 goto fail;
663996b3 101
f2dec872 102 (void) fchmod(fileno(f), 0644);
663996b3
MS
103
104 fprintf(f,
105 "# This is private data. Do not parse.\n"
106 "WHAT=%s\n"
107 "MODE=%s\n"
60f067b4
JS
108 "UID="UID_FMT"\n"
109 "PID="PID_FMT"\n",
663996b3
MS
110 inhibit_what_to_string(i->what),
111 inhibit_mode_to_string(i->mode),
60f067b4
JS
112 i->uid,
113 i->pid);
663996b3
MS
114
115 if (i->who) {
60f067b4
JS
116 _cleanup_free_ char *cc = NULL;
117
663996b3 118 cc = cescape(i->who);
13d276d0 119 if (!cc) {
663996b3 120 r = -ENOMEM;
13d276d0
MP
121 goto fail;
122 }
123
124 fprintf(f, "WHO=%s\n", cc);
663996b3
MS
125 }
126
127 if (i->why) {
60f067b4
JS
128 _cleanup_free_ char *cc = NULL;
129
663996b3 130 cc = cescape(i->why);
13d276d0 131 if (!cc) {
663996b3 132 r = -ENOMEM;
13d276d0
MP
133 goto fail;
134 }
135
136 fprintf(f, "WHY=%s\n", cc);
663996b3
MS
137 }
138
139 if (i->fifo_path)
140 fprintf(f, "FIFO=%s\n", i->fifo_path);
141
5fd56512
MP
142 r = fflush_and_check(f);
143 if (r < 0)
144 goto fail;
663996b3 145
5fd56512 146 if (rename(temp_path, i->state_file) < 0) {
663996b3 147 r = -errno;
5fd56512 148 goto fail;
663996b3
MS
149 }
150
5fd56512
MP
151 return 0;
152
153fail:
154 (void) unlink(i->state_file);
155
156 if (temp_path)
157 (void) unlink(temp_path);
663996b3 158
5fd56512 159 return log_error_errno(r, "Failed to save inhibit data %s: %m", i->state_file);
663996b3
MS
160}
161
f2dec872
BR
162static int bus_manager_send_inhibited_change(Inhibitor *i) {
163 const char *property;
164
165 assert(i);
166
167 property = i->mode == INHIBIT_BLOCK ? "BlockInhibited" : "DelayInhibited";
168
169 return manager_send_changed(i->manager, property, NULL);
170}
171
663996b3
MS
172int inhibitor_start(Inhibitor *i) {
173 assert(i);
174
175 if (i->started)
176 return 0;
177
178 dual_timestamp_get(&i->since);
179
60f067b4 180 log_debug("Inhibitor %s (%s) pid="PID_FMT" uid="UID_FMT" mode=%s started.",
663996b3 181 strna(i->who), strna(i->why),
60f067b4 182 i->pid, i->uid,
663996b3
MS
183 inhibit_mode_to_string(i->mode));
184
663996b3
MS
185 i->started = true;
186
f2dec872
BR
187 inhibitor_save(i);
188
189 bus_manager_send_inhibited_change(i);
663996b3
MS
190
191 return 0;
192}
193
f2dec872 194void inhibitor_stop(Inhibitor *i) {
663996b3
MS
195 assert(i);
196
197 if (i->started)
60f067b4 198 log_debug("Inhibitor %s (%s) pid="PID_FMT" uid="UID_FMT" mode=%s stopped.",
663996b3 199 strna(i->who), strna(i->why),
60f067b4 200 i->pid, i->uid,
663996b3
MS
201 inhibit_mode_to_string(i->mode));
202
f2dec872
BR
203 inhibitor_remove_fifo(i);
204
663996b3 205 if (i->state_file)
bb4f798a 206 (void) unlink(i->state_file);
663996b3
MS
207
208 i->started = false;
209
f2dec872 210 bus_manager_send_inhibited_change(i);
663996b3
MS
211}
212
213int inhibitor_load(Inhibitor *i) {
ea0999c9 214 _cleanup_free_ char *what = NULL, *uid = NULL, *pid = NULL, *who = NULL, *why = NULL, *mode = NULL;
60f067b4
JS
215 InhibitWhat w;
216 InhibitMode mm;
217 char *cc;
ea0999c9 218 ssize_t l;
60f067b4
JS
219 int r;
220
6e866b33 221 r = parse_env_file(NULL, i->state_file,
663996b3
MS
222 "WHAT", &what,
223 "UID", &uid,
224 "PID", &pid,
225 "WHO", &who,
226 "WHY", &why,
227 "MODE", &mode,
6e866b33 228 "FIFO", &i->fifo_path);
663996b3 229 if (r < 0)
f2dec872 230 return log_error_errno(r, "Failed to read %s: %m", i->state_file);
663996b3
MS
231
232 w = what ? inhibit_what_from_string(what) : 0;
233 if (w >= 0)
234 i->what = w;
235
236 mm = mode ? inhibit_mode_from_string(mode) : INHIBIT_BLOCK;
237 if (mm >= 0)
238 i->mode = mm;
239
240 if (uid) {
241 r = parse_uid(uid, &i->uid);
242 if (r < 0)
f2dec872 243 log_debug_errno(r, "Failed to parse UID of inhibitor: %s", uid);
663996b3
MS
244 }
245
246 if (pid) {
247 r = parse_pid(pid, &i->pid);
248 if (r < 0)
f2dec872 249 log_debug_errno(r, "Failed to parse PID of inhibitor: %s", pid);
663996b3
MS
250 }
251
252 if (who) {
ea0999c9
MB
253 l = cunescape(who, 0, &cc);
254 if (l < 0)
255 return log_debug_errno(l, "Failed to unescape \"who\" of inhibitor: %m");
663996b3 256
f2dec872 257 free_and_replace(i->who, cc);
663996b3
MS
258 }
259
260 if (why) {
ea0999c9
MB
261 l = cunescape(why, 0, &cc);
262 if (l < 0)
263 return log_debug_errno(l, "Failed to unescape \"why\" of inhibitor: %m");
663996b3 264
f2dec872 265 free_and_replace(i->why, cc);
663996b3
MS
266 }
267
268 if (i->fifo_path) {
f2dec872 269 _cleanup_close_ int fd = -1;
663996b3 270
f2dec872 271 /* Let's re-open the FIFO on both sides, and close the writing side right away */
663996b3 272 fd = inhibitor_create_fifo(i);
f2dec872
BR
273 if (fd < 0)
274 return log_error_errno(fd, "Failed to reopen FIFO: %m");
663996b3
MS
275 }
276
60f067b4
JS
277 return 0;
278}
663996b3 279
60f067b4 280static int inhibitor_dispatch_fifo(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
086111aa 281 Inhibitor *i = ASSERT_PTR(userdata);
60f067b4
JS
282
283 assert(s);
284 assert(fd == i->fifo_fd);
60f067b4
JS
285
286 inhibitor_stop(i);
287 inhibitor_free(i);
288
289 return 0;
663996b3
MS
290}
291
292int inhibitor_create_fifo(Inhibitor *i) {
293 int r;
294
295 assert(i);
296
297 /* Create FIFO */
298 if (!i->fifo_path) {
b012e921 299 r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0, MKDIR_WARN_MODE);
663996b3
MS
300 if (r < 0)
301 return r;
302
2897b343 303 i->fifo_path = strjoin("/run/systemd/inhibit/", i->id, ".ref");
60f067b4 304 if (!i->fifo_path)
663996b3
MS
305 return -ENOMEM;
306
307 if (mkfifo(i->fifo_path, 0600) < 0 && errno != EEXIST)
308 return -errno;
309 }
310
311 /* Open reading side */
312 if (i->fifo_fd < 0) {
1d42b86d 313 i->fifo_fd = open(i->fifo_path, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
663996b3
MS
314 if (i->fifo_fd < 0)
315 return -errno;
60f067b4 316 }
663996b3 317
60f067b4
JS
318 if (!i->event_source) {
319 r = sd_event_add_io(i->manager->event, &i->event_source, i->fifo_fd, 0, inhibitor_dispatch_fifo, i);
663996b3
MS
320 if (r < 0)
321 return r;
322
aa27b158 323 r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE-10);
60f067b4
JS
324 if (r < 0)
325 return r;
c5fca32e
MB
326
327 (void) sd_event_source_set_description(i->event_source, "inhibitor-ref");
663996b3
MS
328 }
329
330 /* Open writing side */
ea0999c9 331 return RET_NERRNO(open(i->fifo_path, O_WRONLY|O_CLOEXEC|O_NONBLOCK));
663996b3
MS
332}
333
f2dec872 334static void inhibitor_remove_fifo(Inhibitor *i) {
663996b3
MS
335 assert(i);
336
60f067b4
JS
337 i->event_source = sd_event_source_unref(i->event_source);
338 i->fifo_fd = safe_close(i->fifo_fd);
663996b3
MS
339
340 if (i->fifo_path) {
bb4f798a 341 (void) unlink(i->fifo_path);
6300502b 342 i->fifo_path = mfree(i->fifo_path);
663996b3
MS
343 }
344}
345
f2dec872
BR
346bool inhibitor_is_orphan(Inhibitor *i) {
347 assert(i);
348
349 if (!i->started)
350 return true;
351
352 if (!i->fifo_path)
353 return true;
354
355 if (i->fifo_fd < 0)
356 return true;
357
358 if (pipe_eof(i->fifo_fd) != 0)
359 return true;
360
361 return false;
362}
363
663996b3
MS
364InhibitWhat manager_inhibit_what(Manager *m, InhibitMode mm) {
365 Inhibitor *i;
663996b3
MS
366 InhibitWhat what = 0;
367
368 assert(m);
369
a032b68d 370 HASHMAP_FOREACH(i, m->inhibitors)
81c58355 371 if (i->mode == mm && i->started)
663996b3
MS
372 what |= i->what;
373
374 return what;
375}
376
377static int pid_is_active(Manager *m, pid_t pid) {
378 Session *s;
379 int r;
380
52ad194e
MB
381 /* Get client session. This is not what you are looking for these days.
382 * FIXME #6852 */
663996b3
MS
383 r = manager_get_session_by_pid(m, pid, &s);
384 if (r < 0)
385 return r;
386
387 /* If there's no session assigned to it, then it's globally
388 * active on all ttys */
389 if (r == 0)
390 return 1;
391
392 return session_is_active(s);
393}
394
395bool manager_is_inhibited(
396 Manager *m,
397 InhibitWhat w,
398 InhibitMode mm,
399 dual_timestamp *since,
400 bool ignore_inactive,
401 bool ignore_uid,
60f067b4
JS
402 uid_t uid,
403 Inhibitor **offending) {
663996b3
MS
404
405 Inhibitor *i;
86f210e9 406 struct dual_timestamp ts = DUAL_TIMESTAMP_NULL;
663996b3
MS
407 bool inhibited = false;
408
409 assert(m);
410 assert(w > 0 && w < _INHIBIT_WHAT_MAX);
411
a032b68d 412 HASHMAP_FOREACH(i, m->inhibitors) {
81c58355
MB
413 if (!i->started)
414 continue;
415
663996b3
MS
416 if (!(i->what & w))
417 continue;
418
419 if (i->mode != mm)
420 continue;
421
422 if (ignore_inactive && pid_is_active(m, i->pid) <= 0)
423 continue;
424
425 if (ignore_uid && i->uid == uid)
426 continue;
427
428 if (!inhibited ||
429 i->since.monotonic < ts.monotonic)
430 ts = i->since;
431
432 inhibited = true;
60f067b4
JS
433
434 if (offending)
435 *offending = i;
663996b3
MS
436 }
437
438 if (since)
439 *since = ts;
440
441 return inhibited;
442}
443
444const char *inhibit_what_to_string(InhibitWhat w) {
a032b68d
MB
445 static thread_local char buffer[STRLEN(
446 "shutdown:"
447 "sleep:"
448 "idle:"
449 "handle-power-key:"
450 "handle-suspend-key:"
451 "handle-hibernate-key:"
452 "handle-lid-switch:"
453 "handle-reboot-key")+1];
663996b3
MS
454 char *p;
455
456 if (w < 0 || w >= _INHIBIT_WHAT_MAX)
457 return NULL;
458
459 p = buffer;
460 if (w & INHIBIT_SHUTDOWN)
461 p = stpcpy(p, "shutdown:");
462 if (w & INHIBIT_SLEEP)
463 p = stpcpy(p, "sleep:");
464 if (w & INHIBIT_IDLE)
465 p = stpcpy(p, "idle:");
466 if (w & INHIBIT_HANDLE_POWER_KEY)
467 p = stpcpy(p, "handle-power-key:");
468 if (w & INHIBIT_HANDLE_SUSPEND_KEY)
469 p = stpcpy(p, "handle-suspend-key:");
470 if (w & INHIBIT_HANDLE_HIBERNATE_KEY)
471 p = stpcpy(p, "handle-hibernate-key:");
472 if (w & INHIBIT_HANDLE_LID_SWITCH)
473 p = stpcpy(p, "handle-lid-switch:");
a032b68d
MB
474 if (w & INHIBIT_HANDLE_REBOOT_KEY)
475 p = stpcpy(p, "handle-reboot-key:");
663996b3
MS
476
477 if (p > buffer)
478 *(p-1) = 0;
479 else
480 *p = 0;
481
482 return buffer;
483}
484
a032b68d 485int inhibit_what_from_string(const char *s) {
663996b3 486 InhibitWhat what = 0;
663996b3 487
a032b68d
MB
488 for (const char *p = s;;) {
489 _cleanup_free_ char *word = NULL;
490 int r;
491
492 /* A sanity check that our return values fit in an int */
493 assert_cc((int) _INHIBIT_WHAT_MAX == _INHIBIT_WHAT_MAX);
494
495 r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
496 if (r < 0)
497 return r;
498 if (r == 0)
499 return what;
500
501 if (streq(word, "shutdown"))
663996b3 502 what |= INHIBIT_SHUTDOWN;
a032b68d 503 else if (streq(word, "sleep"))
663996b3 504 what |= INHIBIT_SLEEP;
a032b68d 505 else if (streq(word, "idle"))
663996b3 506 what |= INHIBIT_IDLE;
a032b68d 507 else if (streq(word, "handle-power-key"))
663996b3 508 what |= INHIBIT_HANDLE_POWER_KEY;
a032b68d 509 else if (streq(word, "handle-suspend-key"))
663996b3 510 what |= INHIBIT_HANDLE_SUSPEND_KEY;
a032b68d 511 else if (streq(word, "handle-hibernate-key"))
663996b3 512 what |= INHIBIT_HANDLE_HIBERNATE_KEY;
a032b68d 513 else if (streq(word, "handle-lid-switch"))
663996b3 514 what |= INHIBIT_HANDLE_LID_SWITCH;
a032b68d
MB
515 else if (streq(word, "handle-reboot-key"))
516 what |= INHIBIT_HANDLE_REBOOT_KEY;
663996b3
MS
517 else
518 return _INHIBIT_WHAT_INVALID;
519 }
663996b3
MS
520}
521
522static const char* const inhibit_mode_table[_INHIBIT_MODE_MAX] = {
523 [INHIBIT_BLOCK] = "block",
524 [INHIBIT_DELAY] = "delay"
525};
526
527DEFINE_STRING_TABLE_LOOKUP(inhibit_mode, InhibitMode);