]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-inhibit.c
Remove duplicate includes
[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"
9eb977db 29#include "path-util.h"
f8e2fb7b 30#include "logind-inhibit.h"
a5c32cff 31#include "fileio.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
9eb977db 48 i->id = path_get_file_name(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
LP
88 if (r < 0)
89 goto finish;
90
91 r = fopen_temporary(i->state_file, &f, &temp_path);
92 if (r < 0)
93 goto finish;
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"
f8e2fb7b
LP
101 "UID=%lu\n"
102 "PID=%lu\n",
103 inhibit_what_to_string(i->what),
eecd1362 104 inhibit_mode_to_string(i->mode),
f8e2fb7b
LP
105 (unsigned long) i->uid,
106 (unsigned long) i->pid);
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
131 fflush(f);
132
133 if (ferror(f) || rename(temp_path, i->state_file) < 0) {
134 r = -errno;
135 unlink(i->state_file);
136 unlink(temp_path);
137 }
138
f8e2fb7b
LP
139finish:
140 if (r < 0)
141 log_error("Failed to save inhibit data for %s: %s", i->id, strerror(-r));
142
143 return r;
144}
145
146int inhibitor_start(Inhibitor *i) {
147 assert(i);
148
149 if (i->started)
150 return 0;
151
c7b5eb98
LP
152 dual_timestamp_get(&i->since);
153
eecd1362 154 log_debug("Inhibitor %s (%s) pid=%lu uid=%lu mode=%s started.",
f8e2fb7b 155 strna(i->who), strna(i->why),
eecd1362
LP
156 (unsigned long) i->pid, (unsigned long) i->uid,
157 inhibit_mode_to_string(i->mode));
f8e2fb7b
LP
158
159 inhibitor_save(i);
160
161 i->started = true;
162
cc377381 163 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited" : "DelayInhibited", NULL);
f8e2fb7b
LP
164
165 return 0;
166}
167
168int inhibitor_stop(Inhibitor *i) {
169 assert(i);
170
171 if (i->started)
eecd1362 172 log_debug("Inhibitor %s (%s) pid=%lu uid=%lu mode=%s stopped.",
f8e2fb7b 173 strna(i->who), strna(i->why),
eecd1362
LP
174 (unsigned long) i->pid, (unsigned long) i->uid,
175 inhibit_mode_to_string(i->mode));
f8e2fb7b
LP
176
177 if (i->state_file)
178 unlink(i->state_file);
179
180 i->started = false;
181
cc377381 182 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited" : "DelayInhibited", NULL);
f8e2fb7b
LP
183
184 return 0;
185}
186
187int inhibitor_load(Inhibitor *i) {
cc377381
LP
188
189 _cleanup_free_ char
f8e2fb7b
LP
190 *what = NULL,
191 *uid = NULL,
192 *pid = NULL,
193 *who = NULL,
eecd1362
LP
194 *why = NULL,
195 *mode = NULL;
f8e2fb7b 196
cc377381
LP
197 InhibitWhat w;
198 InhibitMode mm;
199 char *cc;
200 int r;
201
f8e2fb7b
LP
202 r = parse_env_file(i->state_file, NEWLINE,
203 "WHAT", &what,
204 "UID", &uid,
205 "PID", &pid,
206 "WHO", &who,
207 "WHY", &why,
eecd1362 208 "MODE", &mode,
f8e2fb7b
LP
209 "FIFO", &i->fifo_path,
210 NULL);
211 if (r < 0)
cc377381 212 return r;
f8e2fb7b 213
eecd1362 214 w = what ? inhibit_what_from_string(what) : 0;
f8e2fb7b
LP
215 if (w >= 0)
216 i->what = w;
217
eecd1362
LP
218 mm = mode ? inhibit_mode_from_string(mode) : INHIBIT_BLOCK;
219 if (mm >= 0)
220 i->mode = mm;
221
a34faf57
LN
222 if (uid) {
223 r = parse_uid(uid, &i->uid);
224 if (r < 0)
cc377381 225 return r;
a34faf57 226 }
eecd1362 227
a34faf57
LN
228 if (pid) {
229 r = parse_pid(pid, &i->pid);
230 if (r < 0)
cc377381 231 return r;
a34faf57 232 }
f8e2fb7b
LP
233
234 if (who) {
235 cc = cunescape(who);
cc377381
LP
236 if (!cc)
237 return -ENOMEM;
f8e2fb7b
LP
238
239 free(i->who);
240 i->who = cc;
241 }
242
243 if (why) {
244 cc = cunescape(why);
cc377381
LP
245 if (!cc)
246 return -ENOMEM;
f8e2fb7b
LP
247
248 free(i->why);
249 i->why = cc;
250 }
251
252 if (i->fifo_path) {
253 int fd;
254
255 fd = inhibitor_create_fifo(i);
256 if (fd >= 0)
257 close_nointr_nofail(fd);
258 }
259
cc377381
LP
260 return 0;
261}
f8e2fb7b 262
cc377381
LP
263static int inhibitor_dispatch_fifo(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
264 Inhibitor *i = userdata;
265
266 assert(s);
267 assert(fd == i->fifo_fd);
268 assert(i);
269
270 inhibitor_stop(i);
271 inhibitor_free(i);
272
273 return 0;
f8e2fb7b
LP
274}
275
276int inhibitor_create_fifo(Inhibitor *i) {
277 int r;
278
279 assert(i);
280
281 /* Create FIFO */
282 if (!i->fifo_path) {
d2e54fae 283 r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0);
f8e2fb7b
LP
284 if (r < 0)
285 return r;
286
cc377381
LP
287 i->fifo_path = strjoin("/run/systemd/inhibit/", i->id, ".ref", NULL);
288 if (!i->fifo_path)
f8e2fb7b
LP
289 return -ENOMEM;
290
291 if (mkfifo(i->fifo_path, 0600) < 0 && errno != EEXIST)
292 return -errno;
293 }
294
295 /* Open reading side */
296 if (i->fifo_fd < 0) {
f8e2fb7b
LP
297 i->fifo_fd = open(i->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
298 if (i->fifo_fd < 0)
299 return -errno;
cc377381 300 }
f8e2fb7b 301
cc377381
LP
302 if (!i->event_source) {
303 r = sd_event_add_io(i->manager->event, i->fifo_fd, 0, inhibitor_dispatch_fifo, i, &i->event_source);
f8e2fb7b
LP
304 if (r < 0)
305 return r;
306
cc377381
LP
307 r = sd_event_source_set_priority(i->event_source, SD_PRIORITY_IDLE);
308 if (r < 0)
309 return r;
f8e2fb7b
LP
310 }
311
312 /* Open writing side */
313 r = open(i->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
314 if (r < 0)
315 return -errno;
316
317 return r;
318}
319
320void inhibitor_remove_fifo(Inhibitor *i) {
321 assert(i);
322
cc377381
LP
323 if (i->event_source)
324 i->event_source = sd_event_source_unref(i->event_source);
325
f8e2fb7b 326 if (i->fifo_fd >= 0) {
f8e2fb7b
LP
327 close_nointr_nofail(i->fifo_fd);
328 i->fifo_fd = -1;
329 }
330
331 if (i->fifo_path) {
332 unlink(i->fifo_path);
333 free(i->fifo_path);
334 i->fifo_path = NULL;
335 }
336}
337
eecd1362 338InhibitWhat manager_inhibit_what(Manager *m, InhibitMode mm) {
f8e2fb7b
LP
339 Inhibitor *i;
340 Iterator j;
341 InhibitWhat what = 0;
342
343 assert(m);
344
cc377381 345 HASHMAP_FOREACH(i, m->inhibitors, j)
eecd1362
LP
346 if (i->mode == mm)
347 what |= i->what;
f8e2fb7b
LP
348
349 return what;
350}
351
beaafb2e
LP
352static int pid_is_active(Manager *m, pid_t pid) {
353 Session *s;
354 int r;
355
356 r = manager_get_session_by_pid(m, pid, &s);
2c4f86c1 357 if (r < 0)
beaafb2e
LP
358 return r;
359
2c4f86c1
LP
360 /* If there's no session assigned to it, then it's globally
361 * active on all ttys */
362 if (r == 0)
363 return 1;
364
beaafb2e
LP
365 return session_is_active(s);
366}
367
368bool manager_is_inhibited(
369 Manager *m,
370 InhibitWhat w,
371 InhibitMode mm,
372 dual_timestamp *since,
409133be
LP
373 bool ignore_inactive,
374 bool ignore_uid,
375 uid_t uid) {
beaafb2e 376
c7b5eb98
LP
377 Inhibitor *i;
378 Iterator j;
379 struct dual_timestamp ts = { 0, 0 };
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;
403 }
404
405 if (since)
406 *since = ts;
407
408 return inhibited;
409}
410
f8e2fb7b 411const char *inhibit_what_to_string(InhibitWhat w) {
8e7fd6ad 412 static __thread char buffer[97];
beaafb2e 413 char *p;
f8e2fb7b
LP
414
415 if (w < 0 || w >= _INHIBIT_WHAT_MAX)
416 return NULL;
417
beaafb2e
LP
418 p = buffer;
419 if (w & INHIBIT_SHUTDOWN)
420 p = stpcpy(p, "shutdown:");
421 if (w & INHIBIT_SLEEP)
422 p = stpcpy(p, "sleep:");
423 if (w & INHIBIT_IDLE)
424 p = stpcpy(p, "idle:");
425 if (w & INHIBIT_HANDLE_POWER_KEY)
426 p = stpcpy(p, "handle-power-key:");
8e7fd6ad
LP
427 if (w & INHIBIT_HANDLE_SUSPEND_KEY)
428 p = stpcpy(p, "handle-suspend-key:");
429 if (w & INHIBIT_HANDLE_HIBERNATE_KEY)
430 p = stpcpy(p, "handle-hibernate-key:");
beaafb2e
LP
431 if (w & INHIBIT_HANDLE_LID_SWITCH)
432 p = stpcpy(p, "handle-lid-switch:");
433
434 if (p > buffer)
435 *(p-1) = 0;
436 else
437 *p = 0;
438
439 return buffer;
f8e2fb7b
LP
440}
441
442InhibitWhat inhibit_what_from_string(const char *s) {
443 InhibitWhat what = 0;
444 char *w, *state;
445 size_t l;
446
447 FOREACH_WORD_SEPARATOR(w, l, s, ":", state) {
641906e9 448 if (l == 8 && strneq(w, "shutdown", l))
f8e2fb7b 449 what |= INHIBIT_SHUTDOWN;
641906e9 450 else if (l == 5 && strneq(w, "sleep", l))
4943c1c9 451 what |= INHIBIT_SLEEP;
641906e9 452 else if (l == 4 && strneq(w, "idle", l))
f8e2fb7b 453 what |= INHIBIT_IDLE;
641906e9 454 else if (l == 16 && strneq(w, "handle-power-key", l))
beaafb2e 455 what |= INHIBIT_HANDLE_POWER_KEY;
641906e9 456 else if (l == 18 && strneq(w, "handle-suspend-key", l))
8e7fd6ad 457 what |= INHIBIT_HANDLE_SUSPEND_KEY;
641906e9 458 else if (l == 20 && strneq(w, "handle-hibernate-key", l))
8e7fd6ad 459 what |= INHIBIT_HANDLE_HIBERNATE_KEY;
641906e9 460 else if (l == 17 && strneq(w, "handle-lid-switch", l))
beaafb2e 461 what |= INHIBIT_HANDLE_LID_SWITCH;
f8e2fb7b
LP
462 else
463 return _INHIBIT_WHAT_INVALID;
464 }
465
466 return what;
f8e2fb7b 467}
eecd1362
LP
468
469static const char* const inhibit_mode_table[_INHIBIT_MODE_MAX] = {
470 [INHIBIT_BLOCK] = "block",
471 [INHIBIT_DELAY] = "delay"
472};
473
474DEFINE_STRING_TABLE_LOOKUP(inhibit_mode, InhibitMode);