]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-inhibit.c
honor SELinux labels, when creating and writing config files
[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>
24#include <sys/epoll.h>
25#include <string.h>
26#include <errno.h>
27#include <unistd.h>
28
29#include "util.h"
30#include "mkdir.h"
9eb977db 31#include "path-util.h"
f8e2fb7b 32#include "logind-inhibit.h"
a5c32cff 33#include "fileio.h"
f8e2fb7b
LP
34
35Inhibitor* inhibitor_new(Manager *m, const char* id) {
36 Inhibitor *i;
37
38 assert(m);
39
40 i = new0(Inhibitor, 1);
41 if (!i)
42 return NULL;
43
44 i->state_file = strappend("/run/systemd/inhibit/", id);
45 if (!i->state_file) {
46 free(i);
47 return NULL;
48 }
49
9eb977db 50 i->id = path_get_file_name(i->state_file);
f8e2fb7b
LP
51
52 if (hashmap_put(m->inhibitors, i->id, i) < 0) {
53 free(i->state_file);
54 free(i);
55 return NULL;
56 }
57
58 i->manager = m;
59 i->fifo_fd = -1;
60
61 return i;
62}
63
64void inhibitor_free(Inhibitor *i) {
65 assert(i);
66
67 free(i->who);
68 free(i->why);
69
70 hashmap_remove(i->manager->inhibitors, i->id);
71 inhibitor_remove_fifo(i);
72
73 if (i->state_file) {
74 unlink(i->state_file);
75 free(i->state_file);
76 }
77
78 free(i);
79}
80
81int inhibitor_save(Inhibitor *i) {
82 char *temp_path, *cc;
83 int r;
84 FILE *f;
85
86 assert(i);
87
d2e54fae 88 r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0);
f8e2fb7b
LP
89 if (r < 0)
90 goto finish;
91
92 r = fopen_temporary(i->state_file, &f, &temp_path);
93 if (r < 0)
94 goto finish;
95
96 fchmod(fileno(f), 0644);
97
98 fprintf(f,
99 "# This is private data. Do not parse.\n"
100 "WHAT=%s\n"
eecd1362 101 "MODE=%s\n"
f8e2fb7b
LP
102 "UID=%lu\n"
103 "PID=%lu\n",
104 inhibit_what_to_string(i->what),
eecd1362 105 inhibit_mode_to_string(i->mode),
f8e2fb7b
LP
106 (unsigned long) i->uid,
107 (unsigned long) i->pid);
108
109 if (i->who) {
110 cc = cescape(i->who);
111 if (!cc)
112 r = -ENOMEM;
113 else {
114 fprintf(f, "WHO=%s\n", cc);
115 free(cc);
116 }
117 }
118
119 if (i->why) {
120 cc = cescape(i->why);
121 if (!cc)
122 r = -ENOMEM;
123 else {
124 fprintf(f, "WHY=%s\n", cc);
125 free(cc);
126 }
127 }
128
129 if (i->fifo_path)
130 fprintf(f, "FIFO=%s\n", i->fifo_path);
131
132 fflush(f);
133
134 if (ferror(f) || rename(temp_path, i->state_file) < 0) {
135 r = -errno;
136 unlink(i->state_file);
137 unlink(temp_path);
138 }
139
140 fclose(f);
141 free(temp_path);
142
143finish:
144 if (r < 0)
145 log_error("Failed to save inhibit data for %s: %s", i->id, strerror(-r));
146
147 return r;
148}
149
150int inhibitor_start(Inhibitor *i) {
151 assert(i);
152
153 if (i->started)
154 return 0;
155
c7b5eb98
LP
156 dual_timestamp_get(&i->since);
157
eecd1362 158 log_debug("Inhibitor %s (%s) pid=%lu uid=%lu mode=%s started.",
f8e2fb7b 159 strna(i->who), strna(i->why),
eecd1362
LP
160 (unsigned long) i->pid, (unsigned long) i->uid,
161 inhibit_mode_to_string(i->mode));
f8e2fb7b
LP
162
163 inhibitor_save(i);
164
165 i->started = true;
166
d889a206 167 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited\0" : "DelayInhibited\0");
f8e2fb7b
LP
168
169 return 0;
170}
171
172int inhibitor_stop(Inhibitor *i) {
173 assert(i);
174
175 if (i->started)
eecd1362 176 log_debug("Inhibitor %s (%s) pid=%lu uid=%lu mode=%s stopped.",
f8e2fb7b 177 strna(i->who), strna(i->why),
eecd1362
LP
178 (unsigned long) i->pid, (unsigned long) i->uid,
179 inhibit_mode_to_string(i->mode));
f8e2fb7b
LP
180
181 if (i->state_file)
182 unlink(i->state_file);
183
184 i->started = false;
185
d889a206 186 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited\0" : "DelayInhibited\0");
f8e2fb7b
LP
187
188 return 0;
189}
190
191int inhibitor_load(Inhibitor *i) {
192 InhibitWhat w;
eecd1362 193 InhibitMode mm;
f8e2fb7b
LP
194 int r;
195 char *cc,
196 *what = NULL,
197 *uid = NULL,
198 *pid = NULL,
199 *who = NULL,
eecd1362
LP
200 *why = NULL,
201 *mode = NULL;
f8e2fb7b
LP
202
203 r = parse_env_file(i->state_file, NEWLINE,
204 "WHAT", &what,
205 "UID", &uid,
206 "PID", &pid,
207 "WHO", &who,
208 "WHY", &why,
eecd1362 209 "MODE", &mode,
f8e2fb7b
LP
210 "FIFO", &i->fifo_path,
211 NULL);
212 if (r < 0)
213 goto finish;
214
eecd1362 215 w = what ? inhibit_what_from_string(what) : 0;
f8e2fb7b
LP
216 if (w >= 0)
217 i->what = w;
218
eecd1362
LP
219 mm = mode ? inhibit_mode_from_string(mode) : INHIBIT_BLOCK;
220 if (mm >= 0)
221 i->mode = mm;
222
a34faf57
LN
223 if (uid) {
224 r = parse_uid(uid, &i->uid);
225 if (r < 0)
226 goto finish;
227 }
eecd1362 228
a34faf57
LN
229 if (pid) {
230 r = parse_pid(pid, &i->pid);
231 if (r < 0)
232 goto finish;
233 }
f8e2fb7b
LP
234
235 if (who) {
236 cc = cunescape(who);
237 if (!cc) {
238 r = -ENOMEM;
239 goto finish;
240 }
241
242 free(i->who);
243 i->who = cc;
244 }
245
246 if (why) {
247 cc = cunescape(why);
248 if (!cc) {
249 r = -ENOMEM;
250 goto finish;
251 }
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);
261 if (fd >= 0)
262 close_nointr_nofail(fd);
263 }
264
265finish:
266 free(what);
267 free(uid);
268 free(pid);
269 free(who);
270 free(why);
271
272 return r;
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
286 if (asprintf(&i->fifo_path, "/run/systemd/inhibit/%s.ref", i->id) < 0)
287 return -ENOMEM;
288
289 if (mkfifo(i->fifo_path, 0600) < 0 && errno != EEXIST)
290 return -errno;
291 }
292
293 /* Open reading side */
294 if (i->fifo_fd < 0) {
295 struct epoll_event ev;
296
297 i->fifo_fd = open(i->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
298 if (i->fifo_fd < 0)
299 return -errno;
300
301 r = hashmap_put(i->manager->inhibitor_fds, INT_TO_PTR(i->fifo_fd + 1), i);
302 if (r < 0)
303 return r;
304
305 zero(ev);
306 ev.events = 0;
069cfc85 307 ev.data.u32 = FD_OTHER_BASE + i->fifo_fd;
f8e2fb7b
LP
308
309 if (epoll_ctl(i->manager->epoll_fd, EPOLL_CTL_ADD, i->fifo_fd, &ev) < 0)
310 return -errno;
311 }
312
313 /* Open writing side */
314 r = open(i->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
315 if (r < 0)
316 return -errno;
317
318 return r;
319}
320
321void inhibitor_remove_fifo(Inhibitor *i) {
322 assert(i);
323
324 if (i->fifo_fd >= 0) {
325 assert_se(hashmap_remove(i->manager->inhibitor_fds, INT_TO_PTR(i->fifo_fd + 1)) == i);
326 assert_se(epoll_ctl(i->manager->epoll_fd, EPOLL_CTL_DEL, i->fifo_fd, NULL) == 0);
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
345 HASHMAP_FOREACH(i, m->inhibitor_fds, 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);
357 if (r <= 0)
358 return r;
359
360 return session_is_active(s);
361}
362
363bool manager_is_inhibited(
364 Manager *m,
365 InhibitWhat w,
366 InhibitMode mm,
367 dual_timestamp *since,
409133be
LP
368 bool ignore_inactive,
369 bool ignore_uid,
370 uid_t uid) {
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
380 HASHMAP_FOREACH(i, m->inhibitor_fds, j) {
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;
398 }
399
400 if (since)
401 *since = ts;
402
403 return inhibited;
404}
405
f8e2fb7b 406const char *inhibit_what_to_string(InhibitWhat w) {
8e7fd6ad 407 static __thread char buffer[97];
beaafb2e 408 char *p;
f8e2fb7b
LP
409
410 if (w < 0 || w >= _INHIBIT_WHAT_MAX)
411 return NULL;
412
beaafb2e
LP
413 p = buffer;
414 if (w & INHIBIT_SHUTDOWN)
415 p = stpcpy(p, "shutdown:");
416 if (w & INHIBIT_SLEEP)
417 p = stpcpy(p, "sleep:");
418 if (w & INHIBIT_IDLE)
419 p = stpcpy(p, "idle:");
420 if (w & INHIBIT_HANDLE_POWER_KEY)
421 p = stpcpy(p, "handle-power-key:");
8e7fd6ad
LP
422 if (w & INHIBIT_HANDLE_SUSPEND_KEY)
423 p = stpcpy(p, "handle-suspend-key:");
424 if (w & INHIBIT_HANDLE_HIBERNATE_KEY)
425 p = stpcpy(p, "handle-hibernate-key:");
beaafb2e
LP
426 if (w & INHIBIT_HANDLE_LID_SWITCH)
427 p = stpcpy(p, "handle-lid-switch:");
428
429 if (p > buffer)
430 *(p-1) = 0;
431 else
432 *p = 0;
433
434 return buffer;
f8e2fb7b
LP
435}
436
437InhibitWhat inhibit_what_from_string(const char *s) {
438 InhibitWhat what = 0;
439 char *w, *state;
440 size_t l;
441
442 FOREACH_WORD_SEPARATOR(w, l, s, ":", state) {
641906e9 443 if (l == 8 && strneq(w, "shutdown", l))
f8e2fb7b 444 what |= INHIBIT_SHUTDOWN;
641906e9 445 else if (l == 5 && strneq(w, "sleep", l))
4943c1c9 446 what |= INHIBIT_SLEEP;
641906e9 447 else if (l == 4 && strneq(w, "idle", l))
f8e2fb7b 448 what |= INHIBIT_IDLE;
641906e9 449 else if (l == 16 && strneq(w, "handle-power-key", l))
beaafb2e 450 what |= INHIBIT_HANDLE_POWER_KEY;
641906e9 451 else if (l == 18 && strneq(w, "handle-suspend-key", l))
8e7fd6ad 452 what |= INHIBIT_HANDLE_SUSPEND_KEY;
641906e9 453 else if (l == 20 && strneq(w, "handle-hibernate-key", l))
8e7fd6ad 454 what |= INHIBIT_HANDLE_HIBERNATE_KEY;
641906e9 455 else if (l == 17 && strneq(w, "handle-lid-switch", l))
beaafb2e 456 what |= INHIBIT_HANDLE_LID_SWITCH;
f8e2fb7b
LP
457 else
458 return _INHIBIT_WHAT_INVALID;
459 }
460
461 return what;
f8e2fb7b 462}
eecd1362
LP
463
464static const char* const inhibit_mode_table[_INHIBIT_MODE_MAX] = {
465 [INHIBIT_BLOCK] = "block",
466 [INHIBIT_DELAY] = "delay"
467};
468
469DEFINE_STRING_TABLE_LOOKUP(inhibit_mode, InhibitMode);