]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-inhibit.c
treewide: no need to negate errno for log_*_errno()
[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
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
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"
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
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)
da927ba9 141 log_error_errno(r, "Failed to save inhibit data %s: %m", i->state_file);
f8e2fb7b
LP
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
de0671ee 154 log_debug("Inhibitor %s (%s) pid="PID_FMT" uid="UID_FMT" mode=%s started.",
f8e2fb7b 155 strna(i->who), strna(i->why),
de0671ee 156 i->pid, i->uid,
eecd1362 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)
de0671ee 172 log_debug("Inhibitor %s (%s) pid="PID_FMT" uid="UID_FMT" mode=%s stopped.",
f8e2fb7b 173 strna(i->who), strna(i->why),
de0671ee 174 i->pid, i->uid,
eecd1362 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);
03e334a1 256 safe_close(fd);
f8e2fb7b
LP
257 }
258
cc377381
LP
259 return 0;
260}
f8e2fb7b 261
cc377381
LP
262static int inhibitor_dispatch_fifo(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
263 Inhibitor *i = userdata;
264
265 assert(s);
266 assert(fd == i->fifo_fd);
267 assert(i);
268
269 inhibitor_stop(i);
270 inhibitor_free(i);
271
272 return 0;
f8e2fb7b
LP
273}
274
275int inhibitor_create_fifo(Inhibitor *i) {
276 int r;
277
278 assert(i);
279
280 /* Create FIFO */
281 if (!i->fifo_path) {
d2e54fae 282 r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0);
f8e2fb7b
LP
283 if (r < 0)
284 return r;
285
cc377381
LP
286 i->fifo_path = strjoin("/run/systemd/inhibit/", i->id, ".ref", NULL);
287 if (!i->fifo_path)
f8e2fb7b
LP
288 return -ENOMEM;
289
290 if (mkfifo(i->fifo_path, 0600) < 0 && errno != EEXIST)
291 return -errno;
292 }
293
294 /* Open reading side */
295 if (i->fifo_fd < 0) {
f8e2fb7b
LP
296 i->fifo_fd = open(i->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
297 if (i->fifo_fd < 0)
298 return -errno;
cc377381 299 }
f8e2fb7b 300
cc377381 301 if (!i->event_source) {
151b9b96 302 r = sd_event_add_io(i->manager->event, &i->event_source, i->fifo_fd, 0, inhibitor_dispatch_fifo, i);
f8e2fb7b
LP
303 if (r < 0)
304 return r;
305
718db961 306 r = sd_event_source_set_priority(i->event_source, SD_EVENT_PRIORITY_IDLE);
cc377381
LP
307 if (r < 0)
308 return r;
f8e2fb7b
LP
309 }
310
311 /* Open writing side */
312 r = open(i->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
313 if (r < 0)
314 return -errno;
315
316 return r;
317}
318
319void inhibitor_remove_fifo(Inhibitor *i) {
320 assert(i);
321
03e334a1
LP
322 i->event_source = sd_event_source_unref(i->event_source);
323 i->fifo_fd = safe_close(i->fifo_fd);
f8e2fb7b
LP
324
325 if (i->fifo_path) {
326 unlink(i->fifo_path);
327 free(i->fifo_path);
328 i->fifo_path = NULL;
329 }
330}
331
eecd1362 332InhibitWhat manager_inhibit_what(Manager *m, InhibitMode mm) {
f8e2fb7b
LP
333 Inhibitor *i;
334 Iterator j;
335 InhibitWhat what = 0;
336
337 assert(m);
338
cc377381 339 HASHMAP_FOREACH(i, m->inhibitors, j)
eecd1362
LP
340 if (i->mode == mm)
341 what |= i->what;
f8e2fb7b
LP
342
343 return what;
344}
345
beaafb2e
LP
346static int pid_is_active(Manager *m, pid_t pid) {
347 Session *s;
348 int r;
349
350 r = manager_get_session_by_pid(m, pid, &s);
2c4f86c1 351 if (r < 0)
beaafb2e
LP
352 return r;
353
2c4f86c1
LP
354 /* If there's no session assigned to it, then it's globally
355 * active on all ttys */
356 if (r == 0)
357 return 1;
358
beaafb2e
LP
359 return session_is_active(s);
360}
361
362bool manager_is_inhibited(
363 Manager *m,
364 InhibitWhat w,
365 InhibitMode mm,
366 dual_timestamp *since,
409133be
LP
367 bool ignore_inactive,
368 bool ignore_uid,
85a428c6
LP
369 uid_t uid,
370 Inhibitor **offending) {
beaafb2e 371
c7b5eb98
LP
372 Inhibitor *i;
373 Iterator j;
374 struct dual_timestamp ts = { 0, 0 };
375 bool inhibited = false;
376
377 assert(m);
378 assert(w > 0 && w < _INHIBIT_WHAT_MAX);
379
cc377381 380 HASHMAP_FOREACH(i, m->inhibitors, j) {
c7b5eb98
LP
381 if (!(i->what & w))
382 continue;
383
eecd1362
LP
384 if (i->mode != mm)
385 continue;
386
409133be
LP
387 if (ignore_inactive && pid_is_active(m, i->pid) <= 0)
388 continue;
389
390 if (ignore_uid && i->uid == uid)
beaafb2e
LP
391 continue;
392
c7b5eb98
LP
393 if (!inhibited ||
394 i->since.monotonic < ts.monotonic)
395 ts = i->since;
396
397 inhibited = true;
85a428c6
LP
398
399 if (offending)
400 *offending = i;
c7b5eb98
LP
401 }
402
403 if (since)
404 *since = ts;
405
406 return inhibited;
407}
408
f8e2fb7b 409const char *inhibit_what_to_string(InhibitWhat w) {
ec202eae 410 static thread_local char buffer[97];
beaafb2e 411 char *p;
f8e2fb7b
LP
412
413 if (w < 0 || w >= _INHIBIT_WHAT_MAX)
414 return NULL;
415
beaafb2e
LP
416 p = buffer;
417 if (w & INHIBIT_SHUTDOWN)
418 p = stpcpy(p, "shutdown:");
419 if (w & INHIBIT_SLEEP)
420 p = stpcpy(p, "sleep:");
421 if (w & INHIBIT_IDLE)
422 p = stpcpy(p, "idle:");
423 if (w & INHIBIT_HANDLE_POWER_KEY)
424 p = stpcpy(p, "handle-power-key:");
8e7fd6ad
LP
425 if (w & INHIBIT_HANDLE_SUSPEND_KEY)
426 p = stpcpy(p, "handle-suspend-key:");
427 if (w & INHIBIT_HANDLE_HIBERNATE_KEY)
428 p = stpcpy(p, "handle-hibernate-key:");
beaafb2e
LP
429 if (w & INHIBIT_HANDLE_LID_SWITCH)
430 p = stpcpy(p, "handle-lid-switch:");
431
432 if (p > buffer)
433 *(p-1) = 0;
434 else
435 *p = 0;
436
437 return buffer;
f8e2fb7b
LP
438}
439
440InhibitWhat inhibit_what_from_string(const char *s) {
441 InhibitWhat what = 0;
a2a5291b 442 const char *word, *state;
f8e2fb7b
LP
443 size_t l;
444
a2a5291b
ZJS
445 FOREACH_WORD_SEPARATOR(word, l, s, ":", state) {
446 if (l == 8 && strneq(word, "shutdown", l))
f8e2fb7b 447 what |= INHIBIT_SHUTDOWN;
a2a5291b 448 else if (l == 5 && strneq(word, "sleep", l))
4943c1c9 449 what |= INHIBIT_SLEEP;
a2a5291b 450 else if (l == 4 && strneq(word, "idle", l))
f8e2fb7b 451 what |= INHIBIT_IDLE;
a2a5291b 452 else if (l == 16 && strneq(word, "handle-power-key", l))
beaafb2e 453 what |= INHIBIT_HANDLE_POWER_KEY;
a2a5291b 454 else if (l == 18 && strneq(word, "handle-suspend-key", l))
8e7fd6ad 455 what |= INHIBIT_HANDLE_SUSPEND_KEY;
a2a5291b 456 else if (l == 20 && strneq(word, "handle-hibernate-key", l))
8e7fd6ad 457 what |= INHIBIT_HANDLE_HIBERNATE_KEY;
a2a5291b 458 else if (l == 17 && strneq(word, "handle-lid-switch", l))
beaafb2e 459 what |= INHIBIT_HANDLE_LID_SWITCH;
f8e2fb7b
LP
460 else
461 return _INHIBIT_WHAT_INVALID;
462 }
463
464 return what;
f8e2fb7b 465}
eecd1362
LP
466
467static const char* const inhibit_mode_table[_INHIBIT_MODE_MAX] = {
468 [INHIBIT_BLOCK] = "block",
469 [INHIBIT_DELAY] = "delay"
470};
471
472DEFINE_STRING_TABLE_LOOKUP(inhibit_mode, InhibitMode);