]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-inhibit.c
dhcp6: reduce whitespace a bit
[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"
b1d4f8e1 18#include "user-util.h"
4f5dd394 19#include "util.h"
f8e2fb7b
LP
20
21Inhibitor* inhibitor_new(Manager *m, const char* id) {
22 Inhibitor *i;
23
24 assert(m);
25
26 i = new0(Inhibitor, 1);
27 if (!i)
28 return NULL;
29
30 i->state_file = strappend("/run/systemd/inhibit/", id);
6b430fdb
ZJS
31 if (!i->state_file)
32 return mfree(i);
f8e2fb7b 33
2b6bf07d 34 i->id = basename(i->state_file);
f8e2fb7b
LP
35
36 if (hashmap_put(m->inhibitors, i->id, i) < 0) {
37 free(i->state_file);
6b430fdb 38 return mfree(i);
f8e2fb7b
LP
39 }
40
41 i->manager = m;
42 i->fifo_fd = -1;
43
44 return i;
45}
46
47void inhibitor_free(Inhibitor *i) {
48 assert(i);
49
f8e2fb7b 50 hashmap_remove(i->manager->inhibitors, i->id);
cc377381 51
f8e2fb7b
LP
52 inhibitor_remove_fifo(i);
53
cc377381
LP
54 free(i->who);
55 free(i->why);
56
f8e2fb7b
LP
57 if (i->state_file) {
58 unlink(i->state_file);
59 free(i->state_file);
60 }
61
62 free(i);
63}
64
65int inhibitor_save(Inhibitor *i) {
cc377381
LP
66 _cleanup_free_ char *temp_path = NULL;
67 _cleanup_fclose_ FILE *f = NULL;
f8e2fb7b 68 int r;
f8e2fb7b
LP
69
70 assert(i);
71
37c1d5e9 72 r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0, MKDIR_WARN_MODE);
f8e2fb7b 73 if (r < 0)
dacd6cee 74 goto fail;
f8e2fb7b
LP
75
76 r = fopen_temporary(i->state_file, &f, &temp_path);
77 if (r < 0)
dacd6cee 78 goto fail;
f8e2fb7b
LP
79
80 fchmod(fileno(f), 0644);
81
82 fprintf(f,
83 "# This is private data. Do not parse.\n"
84 "WHAT=%s\n"
eecd1362 85 "MODE=%s\n"
90b2de37
ZJS
86 "UID="UID_FMT"\n"
87 "PID="PID_FMT"\n",
f8e2fb7b 88 inhibit_what_to_string(i->what),
eecd1362 89 inhibit_mode_to_string(i->mode),
90b2de37
ZJS
90 i->uid,
91 i->pid);
f8e2fb7b
LP
92
93 if (i->who) {
cc377381
LP
94 _cleanup_free_ char *cc = NULL;
95
f8e2fb7b 96 cc = cescape(i->who);
88231eb6 97 if (!cc) {
f8e2fb7b 98 r = -ENOMEM;
88231eb6
TA
99 goto fail;
100 }
101
102 fprintf(f, "WHO=%s\n", cc);
f8e2fb7b
LP
103 }
104
105 if (i->why) {
cc377381
LP
106 _cleanup_free_ char *cc = NULL;
107
f8e2fb7b 108 cc = cescape(i->why);
88231eb6 109 if (!cc) {
f8e2fb7b 110 r = -ENOMEM;
88231eb6
TA
111 goto fail;
112 }
113
114 fprintf(f, "WHY=%s\n", cc);
f8e2fb7b
LP
115 }
116
117 if (i->fifo_path)
118 fprintf(f, "FIFO=%s\n", i->fifo_path);
119
dacd6cee
LP
120 r = fflush_and_check(f);
121 if (r < 0)
122 goto fail;
f8e2fb7b 123
dacd6cee 124 if (rename(temp_path, i->state_file) < 0) {
f8e2fb7b 125 r = -errno;
dacd6cee 126 goto fail;
f8e2fb7b
LP
127 }
128
dacd6cee
LP
129 return 0;
130
131fail:
132 (void) unlink(i->state_file);
133
134 if (temp_path)
135 (void) unlink(temp_path);
f8e2fb7b 136
dacd6cee 137 return log_error_errno(r, "Failed to save inhibit data %s: %m", i->state_file);
f8e2fb7b
LP
138}
139
140int inhibitor_start(Inhibitor *i) {
141 assert(i);
142
143 if (i->started)
144 return 0;
145
c7b5eb98
LP
146 dual_timestamp_get(&i->since);
147
de0671ee 148 log_debug("Inhibitor %s (%s) pid="PID_FMT" uid="UID_FMT" mode=%s started.",
f8e2fb7b 149 strna(i->who), strna(i->why),
de0671ee 150 i->pid, i->uid,
eecd1362 151 inhibit_mode_to_string(i->mode));
f8e2fb7b
LP
152
153 inhibitor_save(i);
154
155 i->started = true;
156
cc377381 157 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited" : "DelayInhibited", NULL);
f8e2fb7b
LP
158
159 return 0;
160}
161
162int inhibitor_stop(Inhibitor *i) {
163 assert(i);
164
165 if (i->started)
de0671ee 166 log_debug("Inhibitor %s (%s) pid="PID_FMT" uid="UID_FMT" mode=%s stopped.",
f8e2fb7b 167 strna(i->who), strna(i->why),
de0671ee 168 i->pid, i->uid,
eecd1362 169 inhibit_mode_to_string(i->mode));
f8e2fb7b
LP
170
171 if (i->state_file)
172 unlink(i->state_file);
173
174 i->started = false;
175
cc377381 176 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited" : "DelayInhibited", NULL);
f8e2fb7b
LP
177
178 return 0;
179}
180
181int inhibitor_load(Inhibitor *i) {
cc377381
LP
182
183 _cleanup_free_ char
f8e2fb7b
LP
184 *what = NULL,
185 *uid = NULL,
186 *pid = NULL,
187 *who = NULL,
eecd1362
LP
188 *why = NULL,
189 *mode = NULL;
f8e2fb7b 190
cc377381
LP
191 InhibitWhat w;
192 InhibitMode mm;
193 char *cc;
194 int r;
195
1a5a177e 196 r = parse_env_file(NULL, i->state_file, NEWLINE,
f8e2fb7b
LP
197 "WHAT", &what,
198 "UID", &uid,
199 "PID", &pid,
200 "WHO", &who,
201 "WHY", &why,
eecd1362 202 "MODE", &mode,
f8e2fb7b
LP
203 "FIFO", &i->fifo_path,
204 NULL);
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);