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