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