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