LCOV - code coverage report
Current view: top level - login - logind-inhibit.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 1 268 0.4 %
Date: 2019-08-22 15:41:25 Functions: 2 18 11.1 %

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

Generated by: LCOV version 1.14