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