]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/login/logind-inhibit.c
mkdir: append _label to all mkdir() calls that explicitly set the selinux context
[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
LP
32#include "logind-inhibit.h"
33
34Inhibitor* inhibitor_new(Manager *m, const char* id) {
35 Inhibitor *i;
36
37 assert(m);
38
39 i = new0(Inhibitor, 1);
40 if (!i)
41 return NULL;
42
43 i->state_file = strappend("/run/systemd/inhibit/", id);
44 if (!i->state_file) {
45 free(i);
46 return NULL;
47 }
48
9eb977db 49 i->id = path_get_file_name(i->state_file);
f8e2fb7b
LP
50
51 if (hashmap_put(m->inhibitors, i->id, i) < 0) {
52 free(i->state_file);
53 free(i);
54 return NULL;
55 }
56
57 i->manager = m;
58 i->fifo_fd = -1;
59
60 return i;
61}
62
63void inhibitor_free(Inhibitor *i) {
64 assert(i);
65
66 free(i->who);
67 free(i->why);
68
69 hashmap_remove(i->manager->inhibitors, i->id);
70 inhibitor_remove_fifo(i);
71
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) {
81 char *temp_path, *cc;
82 int r;
83 FILE *f;
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) {
109 cc = cescape(i->who);
110 if (!cc)
111 r = -ENOMEM;
112 else {
113 fprintf(f, "WHO=%s\n", cc);
114 free(cc);
115 }
116 }
117
118 if (i->why) {
119 cc = cescape(i->why);
120 if (!cc)
121 r = -ENOMEM;
122 else {
123 fprintf(f, "WHY=%s\n", cc);
124 free(cc);
125 }
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
139 fclose(f);
140 free(temp_path);
141
142finish:
143 if (r < 0)
144 log_error("Failed to save inhibit data for %s: %s", i->id, strerror(-r));
145
146 return r;
147}
148
149int inhibitor_start(Inhibitor *i) {
150 assert(i);
151
152 if (i->started)
153 return 0;
154
c7b5eb98
LP
155 dual_timestamp_get(&i->since);
156
eecd1362 157 log_debug("Inhibitor %s (%s) pid=%lu uid=%lu mode=%s started.",
f8e2fb7b 158 strna(i->who), strna(i->why),
eecd1362
LP
159 (unsigned long) i->pid, (unsigned long) i->uid,
160 inhibit_mode_to_string(i->mode));
f8e2fb7b
LP
161
162 inhibitor_save(i);
163
164 i->started = true;
165
d889a206 166 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited\0" : "DelayInhibited\0");
f8e2fb7b
LP
167
168 return 0;
169}
170
171int inhibitor_stop(Inhibitor *i) {
172 assert(i);
173
174 if (i->started)
eecd1362 175 log_debug("Inhibitor %s (%s) pid=%lu uid=%lu mode=%s stopped.",
f8e2fb7b 176 strna(i->who), strna(i->why),
eecd1362
LP
177 (unsigned long) i->pid, (unsigned long) i->uid,
178 inhibit_mode_to_string(i->mode));
f8e2fb7b
LP
179
180 if (i->state_file)
181 unlink(i->state_file);
182
183 i->started = false;
184
d889a206 185 manager_send_changed(i->manager, i->mode == INHIBIT_BLOCK ? "BlockInhibited\0" : "DelayInhibited\0");
f8e2fb7b
LP
186
187 return 0;
188}
189
190int inhibitor_load(Inhibitor *i) {
191 InhibitWhat w;
eecd1362 192 InhibitMode mm;
f8e2fb7b
LP
193 int r;
194 char *cc,
195 *what = NULL,
196 *uid = NULL,
197 *pid = NULL,
198 *who = NULL,
eecd1362
LP
199 *why = NULL,
200 *mode = NULL;
f8e2fb7b
LP
201
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)
212 goto finish;
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
222 if (uid)
223 parse_uid(uid, &i->uid);
224
225 if (pid)
226 parse_pid(pid, &i->pid);
f8e2fb7b
LP
227
228 if (who) {
229 cc = cunescape(who);
230 if (!cc) {
231 r = -ENOMEM;
232 goto finish;
233 }
234
235 free(i->who);
236 i->who = cc;
237 }
238
239 if (why) {
240 cc = cunescape(why);
241 if (!cc) {
242 r = -ENOMEM;
243 goto finish;
244 }
245
246 free(i->why);
247 i->why = cc;
248 }
249
250 if (i->fifo_path) {
251 int fd;
252
253 fd = inhibitor_create_fifo(i);
254 if (fd >= 0)
255 close_nointr_nofail(fd);
256 }
257
258finish:
259 free(what);
260 free(uid);
261 free(pid);
262 free(who);
263 free(why);
264
265 return r;
266}
267
268int inhibitor_create_fifo(Inhibitor *i) {
269 int r;
270
271 assert(i);
272
273 /* Create FIFO */
274 if (!i->fifo_path) {
d2e54fae 275 r = mkdir_safe_label("/run/systemd/inhibit", 0755, 0, 0);
f8e2fb7b
LP
276 if (r < 0)
277 return r;
278
279 if (asprintf(&i->fifo_path, "/run/systemd/inhibit/%s.ref", i->id) < 0)
280 return -ENOMEM;
281
282 if (mkfifo(i->fifo_path, 0600) < 0 && errno != EEXIST)
283 return -errno;
284 }
285
286 /* Open reading side */
287 if (i->fifo_fd < 0) {
288 struct epoll_event ev;
289
290 i->fifo_fd = open(i->fifo_path, O_RDONLY|O_CLOEXEC|O_NDELAY);
291 if (i->fifo_fd < 0)
292 return -errno;
293
294 r = hashmap_put(i->manager->inhibitor_fds, INT_TO_PTR(i->fifo_fd + 1), i);
295 if (r < 0)
296 return r;
297
298 zero(ev);
299 ev.events = 0;
069cfc85 300 ev.data.u32 = FD_OTHER_BASE + i->fifo_fd;
f8e2fb7b
LP
301
302 if (epoll_ctl(i->manager->epoll_fd, EPOLL_CTL_ADD, i->fifo_fd, &ev) < 0)
303 return -errno;
304 }
305
306 /* Open writing side */
307 r = open(i->fifo_path, O_WRONLY|O_CLOEXEC|O_NDELAY);
308 if (r < 0)
309 return -errno;
310
311 return r;
312}
313
314void inhibitor_remove_fifo(Inhibitor *i) {
315 assert(i);
316
317 if (i->fifo_fd >= 0) {
318 assert_se(hashmap_remove(i->manager->inhibitor_fds, INT_TO_PTR(i->fifo_fd + 1)) == i);
319 assert_se(epoll_ctl(i->manager->epoll_fd, EPOLL_CTL_DEL, i->fifo_fd, NULL) == 0);
320 close_nointr_nofail(i->fifo_fd);
321 i->fifo_fd = -1;
322 }
323
324 if (i->fifo_path) {
325 unlink(i->fifo_path);
326 free(i->fifo_path);
327 i->fifo_path = NULL;
328 }
329}
330
eecd1362 331InhibitWhat manager_inhibit_what(Manager *m, InhibitMode mm) {
f8e2fb7b
LP
332 Inhibitor *i;
333 Iterator j;
334 InhibitWhat what = 0;
335
336 assert(m);
337
338 HASHMAP_FOREACH(i, m->inhibitor_fds, j)
eecd1362
LP
339 if (i->mode == mm)
340 what |= i->what;
f8e2fb7b
LP
341
342 return what;
343}
344
eecd1362 345bool manager_is_inhibited(Manager *m, InhibitWhat w, InhibitMode mm, dual_timestamp *since) {
c7b5eb98
LP
346 Inhibitor *i;
347 Iterator j;
348 struct dual_timestamp ts = { 0, 0 };
349 bool inhibited = false;
350
351 assert(m);
352 assert(w > 0 && w < _INHIBIT_WHAT_MAX);
353
354 HASHMAP_FOREACH(i, m->inhibitor_fds, j) {
355 if (!(i->what & w))
356 continue;
357
eecd1362
LP
358 if (i->mode != mm)
359 continue;
360
c7b5eb98
LP
361 if (!inhibited ||
362 i->since.monotonic < ts.monotonic)
363 ts = i->since;
364
365 inhibited = true;
366 }
367
368 if (since)
369 *since = ts;
370
371 return inhibited;
372}
373
f8e2fb7b
LP
374const char *inhibit_what_to_string(InhibitWhat w) {
375
376 static const char* const table[_INHIBIT_WHAT_MAX] = {
377 [0] = "",
378 [INHIBIT_SHUTDOWN] = "shutdown",
4943c1c9 379 [INHIBIT_SLEEP] = "sleep",
f8e2fb7b 380 [INHIBIT_IDLE] = "idle",
4943c1c9 381 [INHIBIT_SHUTDOWN|INHIBIT_SLEEP] = "shutdown:sleep",
f8e2fb7b 382 [INHIBIT_SHUTDOWN|INHIBIT_IDLE] = "shutdown:idle",
4943c1c9
LP
383 [INHIBIT_SHUTDOWN|INHIBIT_SLEEP|INHIBIT_IDLE] = "shutdown:sleep:idle",
384 [INHIBIT_SLEEP|INHIBIT_IDLE] = "sleep:idle"
f8e2fb7b
LP
385 };
386
387 if (w < 0 || w >= _INHIBIT_WHAT_MAX)
388 return NULL;
389
390 return table[w];
391}
392
393InhibitWhat inhibit_what_from_string(const char *s) {
394 InhibitWhat what = 0;
395 char *w, *state;
396 size_t l;
397
398 FOREACH_WORD_SEPARATOR(w, l, s, ":", state) {
399 if (l == 8 && strncmp(w, "shutdown", l) == 0)
400 what |= INHIBIT_SHUTDOWN;
4943c1c9
LP
401 else if (l == 5 && strncmp(w, "sleep", l) == 0)
402 what |= INHIBIT_SLEEP;
f8e2fb7b
LP
403 else if (l == 4 && strncmp(w, "idle", l) == 0)
404 what |= INHIBIT_IDLE;
405 else
406 return _INHIBIT_WHAT_INVALID;
407 }
408
409 return what;
410
411}
eecd1362
LP
412
413static const char* const inhibit_mode_table[_INHIBIT_MODE_MAX] = {
414 [INHIBIT_BLOCK] = "block",
415 [INHIBIT_DELAY] = "delay"
416};
417
418DEFINE_STRING_TABLE_LOOKUP(inhibit_mode, InhibitMode);