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