LCOV - code coverage report
Current view: top level - login - logind-inhibit.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 1 243 0.4 %
Date: 2015-07-29 18:47:03 Functions: 2 16 12.5 %

          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);

Generated by: LCOV version 1.11