LCOV - code coverage report
Current view: top level - login - logind-core.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 0 301 0.0 %
Date: 2015-07-29 18:47:03 Functions: 0 21 0.0 %

          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 2011 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 <sys/types.h>
      23             : #include <sys/ioctl.h>
      24             : #include <fcntl.h>
      25             : #include <pwd.h>
      26             : #include <linux/vt.h>
      27             : 
      28             : #include "strv.h"
      29             : #include "cgroup-util.h"
      30             : #include "bus-util.h"
      31             : #include "bus-error.h"
      32             : #include "udev-util.h"
      33             : #include "logind.h"
      34             : #include "terminal-util.h"
      35             : 
      36           0 : int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device) {
      37             :         Device *d;
      38             : 
      39           0 :         assert(m);
      40           0 :         assert(sysfs);
      41             : 
      42           0 :         d = hashmap_get(m->devices, sysfs);
      43           0 :         if (d)
      44             :                 /* we support adding master-flags, but not removing them */
      45           0 :                 d->master = d->master || master;
      46             :         else {
      47           0 :                 d = device_new(m, sysfs, master);
      48           0 :                 if (!d)
      49           0 :                         return -ENOMEM;
      50             :         }
      51             : 
      52           0 :         if (_device)
      53           0 :                 *_device = d;
      54             : 
      55           0 :         return 0;
      56             : }
      57             : 
      58           0 : int manager_add_seat(Manager *m, const char *id, Seat **_seat) {
      59             :         Seat *s;
      60             : 
      61           0 :         assert(m);
      62           0 :         assert(id);
      63             : 
      64           0 :         s = hashmap_get(m->seats, id);
      65           0 :         if (!s) {
      66           0 :                 s = seat_new(m, id);
      67           0 :                 if (!s)
      68           0 :                         return -ENOMEM;
      69             :         }
      70             : 
      71           0 :         if (_seat)
      72           0 :                 *_seat = s;
      73             : 
      74           0 :         return 0;
      75             : }
      76             : 
      77           0 : int manager_add_session(Manager *m, const char *id, Session **_session) {
      78             :         Session *s;
      79             : 
      80           0 :         assert(m);
      81           0 :         assert(id);
      82             : 
      83           0 :         s = hashmap_get(m->sessions, id);
      84           0 :         if (!s) {
      85           0 :                 s = session_new(m, id);
      86           0 :                 if (!s)
      87           0 :                         return -ENOMEM;
      88             :         }
      89             : 
      90           0 :         if (_session)
      91           0 :                 *_session = s;
      92             : 
      93           0 :         return 0;
      94             : }
      95             : 
      96           0 : int manager_add_user(Manager *m, uid_t uid, gid_t gid, const char *name, User **_user) {
      97             :         User *u;
      98             : 
      99           0 :         assert(m);
     100           0 :         assert(name);
     101             : 
     102           0 :         u = hashmap_get(m->users, UID_TO_PTR(uid));
     103           0 :         if (!u) {
     104           0 :                 u = user_new(m, uid, gid, name);
     105           0 :                 if (!u)
     106           0 :                         return -ENOMEM;
     107             :         }
     108             : 
     109           0 :         if (_user)
     110           0 :                 *_user = u;
     111             : 
     112           0 :         return 0;
     113             : }
     114             : 
     115           0 : int manager_add_user_by_name(Manager *m, const char *name, User **_user) {
     116             :         uid_t uid;
     117             :         gid_t gid;
     118             :         int r;
     119             : 
     120           0 :         assert(m);
     121           0 :         assert(name);
     122             : 
     123           0 :         r = get_user_creds(&name, &uid, &gid, NULL, NULL);
     124           0 :         if (r < 0)
     125           0 :                 return r;
     126             : 
     127           0 :         return manager_add_user(m, uid, gid, name, _user);
     128             : }
     129             : 
     130           0 : int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user) {
     131             :         struct passwd *p;
     132             : 
     133           0 :         assert(m);
     134             : 
     135           0 :         errno = 0;
     136           0 :         p = getpwuid(uid);
     137           0 :         if (!p)
     138           0 :                 return errno ? -errno : -ENOENT;
     139             : 
     140           0 :         return manager_add_user(m, uid, p->pw_gid, p->pw_name, _user);
     141             : }
     142             : 
     143           0 : int manager_add_inhibitor(Manager *m, const char* id, Inhibitor **_inhibitor) {
     144             :         Inhibitor *i;
     145             : 
     146           0 :         assert(m);
     147           0 :         assert(id);
     148             : 
     149           0 :         i = hashmap_get(m->inhibitors, id);
     150           0 :         if (i) {
     151           0 :                 if (_inhibitor)
     152           0 :                         *_inhibitor = i;
     153             : 
     154           0 :                 return 0;
     155             :         }
     156             : 
     157           0 :         i = inhibitor_new(m, id);
     158           0 :         if (!i)
     159           0 :                 return -ENOMEM;
     160             : 
     161           0 :         if (_inhibitor)
     162           0 :                 *_inhibitor = i;
     163             : 
     164           0 :         return 0;
     165             : }
     166             : 
     167           0 : int manager_add_button(Manager *m, const char *name, Button **_button) {
     168             :         Button *b;
     169             : 
     170           0 :         assert(m);
     171           0 :         assert(name);
     172             : 
     173           0 :         b = hashmap_get(m->buttons, name);
     174           0 :         if (!b) {
     175           0 :                 b = button_new(m, name);
     176           0 :                 if (!b)
     177           0 :                         return -ENOMEM;
     178             :         }
     179             : 
     180           0 :         if (_button)
     181           0 :                 *_button = b;
     182             : 
     183           0 :         return 0;
     184             : }
     185             : 
     186           0 : int manager_watch_busname(Manager *m, const char *name) {
     187             :         char *n;
     188             :         int r;
     189             : 
     190           0 :         assert(m);
     191           0 :         assert(name);
     192             : 
     193           0 :         if (set_get(m->busnames, (char*) name))
     194           0 :                 return 0;
     195             : 
     196           0 :         n = strdup(name);
     197           0 :         if (!n)
     198           0 :                 return -ENOMEM;
     199             : 
     200           0 :         r = set_put(m->busnames, n);
     201           0 :         if (r < 0) {
     202           0 :                 free(n);
     203           0 :                 return r;
     204             :         }
     205             : 
     206           0 :         return 0;
     207             : }
     208             : 
     209           0 : void manager_drop_busname(Manager *m, const char *name) {
     210             :         Session *session;
     211             :         Iterator i;
     212             : 
     213           0 :         assert(m);
     214           0 :         assert(name);
     215             : 
     216             :         /* keep it if the name still owns a controller */
     217           0 :         HASHMAP_FOREACH(session, m->sessions, i)
     218           0 :                 if (session_is_controller(session, name))
     219           0 :                         return;
     220             : 
     221           0 :         free(set_remove(m->busnames, (char*) name));
     222             : }
     223             : 
     224           0 : int manager_process_seat_device(Manager *m, struct udev_device *d) {
     225             :         Device *device;
     226             :         int r;
     227             : 
     228           0 :         assert(m);
     229             : 
     230           0 :         if (streq_ptr(udev_device_get_action(d), "remove")) {
     231             : 
     232           0 :                 device = hashmap_get(m->devices, udev_device_get_syspath(d));
     233           0 :                 if (!device)
     234           0 :                         return 0;
     235             : 
     236           0 :                 seat_add_to_gc_queue(device->seat);
     237           0 :                 device_free(device);
     238             : 
     239             :         } else {
     240             :                 const char *sn;
     241           0 :                 Seat *seat = NULL;
     242             :                 bool master;
     243             : 
     244           0 :                 sn = udev_device_get_property_value(d, "ID_SEAT");
     245           0 :                 if (isempty(sn))
     246           0 :                         sn = "seat0";
     247             : 
     248           0 :                 if (!seat_name_is_valid(sn)) {
     249           0 :                         log_warning("Device with invalid seat name %s found, ignoring.", sn);
     250           0 :                         return 0;
     251             :                 }
     252             : 
     253           0 :                 seat = hashmap_get(m->seats, sn);
     254           0 :                 master = udev_device_has_tag(d, "master-of-seat");
     255             : 
     256             :                 /* Ignore non-master devices for unknown seats */
     257           0 :                 if (!master && !seat)
     258           0 :                         return 0;
     259             : 
     260           0 :                 r = manager_add_device(m, udev_device_get_syspath(d), master, &device);
     261           0 :                 if (r < 0)
     262           0 :                         return r;
     263             : 
     264           0 :                 if (!seat) {
     265           0 :                         r = manager_add_seat(m, sn, &seat);
     266           0 :                         if (r < 0) {
     267           0 :                                 if (!device->seat)
     268           0 :                                         device_free(device);
     269             : 
     270           0 :                                 return r;
     271             :                         }
     272             :                 }
     273             : 
     274           0 :                 device_attach(device, seat);
     275           0 :                 seat_start(seat);
     276             :         }
     277             : 
     278           0 :         return 0;
     279             : }
     280             : 
     281           0 : int manager_process_button_device(Manager *m, struct udev_device *d) {
     282             :         Button *b;
     283             : 
     284             :         int r;
     285             : 
     286           0 :         assert(m);
     287             : 
     288           0 :         if (streq_ptr(udev_device_get_action(d), "remove")) {
     289             : 
     290           0 :                 b = hashmap_get(m->buttons, udev_device_get_sysname(d));
     291           0 :                 if (!b)
     292           0 :                         return 0;
     293             : 
     294           0 :                 button_free(b);
     295             : 
     296             :         } else {
     297             :                 const char *sn;
     298             : 
     299           0 :                 r = manager_add_button(m, udev_device_get_sysname(d), &b);
     300           0 :                 if (r < 0)
     301           0 :                         return r;
     302             : 
     303           0 :                 sn = udev_device_get_property_value(d, "ID_SEAT");
     304           0 :                 if (isempty(sn))
     305           0 :                         sn = "seat0";
     306             : 
     307           0 :                 button_set_seat(b, sn);
     308           0 :                 button_open(b);
     309             :         }
     310             : 
     311           0 :         return 0;
     312             : }
     313             : 
     314           0 : int manager_get_session_by_pid(Manager *m, pid_t pid, Session **session) {
     315           0 :         _cleanup_free_ char *unit = NULL;
     316             :         Session *s;
     317             :         int r;
     318             : 
     319           0 :         assert(m);
     320             : 
     321           0 :         if (pid < 1)
     322           0 :                 return -EINVAL;
     323             : 
     324           0 :         r = cg_pid_get_unit(pid, &unit);
     325           0 :         if (r < 0)
     326           0 :                 return 0;
     327             : 
     328           0 :         s = hashmap_get(m->session_units, unit);
     329           0 :         if (!s)
     330           0 :                 return 0;
     331             : 
     332           0 :         if (session)
     333           0 :                 *session = s;
     334           0 :         return 1;
     335             : }
     336             : 
     337           0 : int manager_get_user_by_pid(Manager *m, pid_t pid, User **user) {
     338           0 :         _cleanup_free_ char *unit = NULL;
     339             :         User *u;
     340             :         int r;
     341             : 
     342           0 :         assert(m);
     343           0 :         assert(user);
     344             : 
     345           0 :         if (pid < 1)
     346           0 :                 return -EINVAL;
     347             : 
     348           0 :         r = cg_pid_get_slice(pid, &unit);
     349           0 :         if (r < 0)
     350           0 :                 return 0;
     351             : 
     352           0 :         u = hashmap_get(m->user_units, unit);
     353           0 :         if (!u)
     354           0 :                 return 0;
     355             : 
     356           0 :         *user = u;
     357           0 :         return 1;
     358             : }
     359             : 
     360           0 : int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
     361             :         Session *s;
     362             :         bool idle_hint;
     363           0 :         dual_timestamp ts = DUAL_TIMESTAMP_NULL;
     364             :         Iterator i;
     365             : 
     366           0 :         assert(m);
     367             : 
     368           0 :         idle_hint = !manager_is_inhibited(m, INHIBIT_IDLE, INHIBIT_BLOCK, t, false, false, 0, NULL);
     369             : 
     370           0 :         HASHMAP_FOREACH(s, m->sessions, i) {
     371             :                 dual_timestamp k;
     372             :                 int ih;
     373             : 
     374           0 :                 ih = session_get_idle_hint(s, &k);
     375           0 :                 if (ih < 0)
     376           0 :                         return ih;
     377             : 
     378           0 :                 if (!ih) {
     379           0 :                         if (!idle_hint) {
     380           0 :                                 if (k.monotonic < ts.monotonic)
     381           0 :                                         ts = k;
     382             :                         } else {
     383           0 :                                 idle_hint = false;
     384           0 :                                 ts = k;
     385             :                         }
     386           0 :                 } else if (idle_hint) {
     387             : 
     388           0 :                         if (k.monotonic > ts.monotonic)
     389           0 :                                 ts = k;
     390             :                 }
     391             :         }
     392             : 
     393           0 :         if (t)
     394           0 :                 *t = ts;
     395             : 
     396           0 :         return idle_hint;
     397             : }
     398             : 
     399           0 : bool manager_shall_kill(Manager *m, const char *user) {
     400           0 :         assert(m);
     401           0 :         assert(user);
     402             : 
     403           0 :         if (!m->kill_user_processes)
     404           0 :                 return false;
     405             : 
     406           0 :         if (strv_contains(m->kill_exclude_users, user))
     407           0 :                 return false;
     408             : 
     409           0 :         if (strv_isempty(m->kill_only_users))
     410           0 :                 return true;
     411             : 
     412           0 :         return strv_contains(m->kill_only_users, user);
     413             : }
     414             : 
     415           0 : static int vt_is_busy(unsigned int vtnr) {
     416             :         struct vt_stat vt_stat;
     417           0 :         int r = 0;
     418           0 :         _cleanup_close_ int fd;
     419             : 
     420           0 :         assert(vtnr >= 1);
     421             : 
     422             :         /* We explicitly open /dev/tty1 here instead of /dev/tty0. If
     423             :          * we'd open the latter we'd open the foreground tty which
     424             :          * hence would be unconditionally busy. By opening /dev/tty1
     425             :          * we avoid this. Since tty1 is special and needs to be an
     426             :          * explicitly loaded getty or DM this is safe. */
     427             : 
     428           0 :         fd = open_terminal("/dev/tty1", O_RDWR|O_NOCTTY|O_CLOEXEC);
     429           0 :         if (fd < 0)
     430           0 :                 return -errno;
     431             : 
     432           0 :         if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0)
     433           0 :                 r = -errno;
     434             :         else
     435           0 :                 r = !!(vt_stat.v_state & (1 << vtnr));
     436             : 
     437           0 :         return r;
     438             : }
     439             : 
     440           0 : int manager_spawn_autovt(Manager *m, unsigned int vtnr) {
     441           0 :         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
     442             :         char name[sizeof("autovt@tty.service") + DECIMAL_STR_MAX(unsigned int)];
     443             :         int r;
     444             : 
     445           0 :         assert(m);
     446           0 :         assert(vtnr >= 1);
     447             : 
     448           0 :         if (vtnr > m->n_autovts &&
     449           0 :             vtnr != m->reserve_vt)
     450           0 :                 return 0;
     451             : 
     452           0 :         if (vtnr != m->reserve_vt) {
     453             :                 /* If this is the reserved TTY, we'll start the getty
     454             :                  * on it in any case, but otherwise only if it is not
     455             :                  * busy. */
     456             : 
     457           0 :                 r = vt_is_busy(vtnr);
     458           0 :                 if (r < 0)
     459           0 :                         return r;
     460           0 :                 else if (r > 0)
     461           0 :                         return -EBUSY;
     462             :         }
     463             : 
     464           0 :         snprintf(name, sizeof(name), "autovt@tty%u.service", vtnr);
     465           0 :         r = sd_bus_call_method(
     466             :                         m->bus,
     467             :                         "org.freedesktop.systemd1",
     468             :                         "/org/freedesktop/systemd1",
     469             :                         "org.freedesktop.systemd1.Manager",
     470             :                         "StartUnit",
     471             :                         &error,
     472             :                         NULL,
     473             :                         "ss", name, "fail");
     474           0 :         if (r < 0)
     475           0 :                 log_error("Failed to start %s: %s", name, bus_error_message(&error, r));
     476             : 
     477           0 :         return r;
     478             : }
     479             : 
     480           0 : static bool manager_is_docked(Manager *m) {
     481             :         Iterator i;
     482             :         Button *b;
     483             : 
     484           0 :         HASHMAP_FOREACH(b, m->buttons, i)
     485           0 :                 if (b->docked)
     486           0 :                         return true;
     487             : 
     488           0 :         return false;
     489             : }
     490             : 
     491           0 : static int manager_count_external_displays(Manager *m) {
     492           0 :         _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
     493           0 :         struct udev_list_entry *item = NULL, *first = NULL;
     494             :         int r;
     495           0 :         int n = 0;
     496             : 
     497           0 :         e = udev_enumerate_new(m->udev);
     498           0 :         if (!e)
     499           0 :                 return -ENOMEM;
     500             : 
     501           0 :         r = udev_enumerate_add_match_subsystem(e, "drm");
     502           0 :         if (r < 0)
     503           0 :                 return r;
     504             : 
     505           0 :         r = udev_enumerate_scan_devices(e);
     506           0 :         if (r < 0)
     507           0 :                 return r;
     508             : 
     509           0 :         first = udev_enumerate_get_list_entry(e);
     510           0 :         udev_list_entry_foreach(item, first) {
     511           0 :                 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
     512             :                 struct udev_device *p;
     513             :                 const char *status, *enabled, *dash, *nn, *i;
     514           0 :                 bool external = false;
     515             : 
     516           0 :                 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
     517           0 :                 if (!d)
     518           0 :                         return -ENOMEM;
     519             : 
     520           0 :                 p = udev_device_get_parent(d);
     521           0 :                 if (!p)
     522           0 :                         continue;
     523             : 
     524             :                 /* If the parent shares the same subsystem as the
     525             :                  * device we are looking at then it is a connector,
     526             :                  * which is what we are interested in. */
     527           0 :                 if (!streq_ptr(udev_device_get_subsystem(p), "drm"))
     528           0 :                         continue;
     529             : 
     530           0 :                 nn = udev_device_get_sysname(d);
     531           0 :                 if (!nn)
     532           0 :                         continue;
     533             : 
     534             :                 /* Ignore internal displays: the type is encoded in
     535             :                  * the sysfs name, as the second dash seperated item
     536             :                  * (the first is the card name, the last the connector
     537             :                  * number). We implement a whitelist of external
     538             :                  * displays here, rather than a whitelist, to ensure
     539             :                  * we don't block suspends too eagerly. */
     540           0 :                 dash = strchr(nn, '-');
     541           0 :                 if (!dash)
     542           0 :                         continue;
     543             : 
     544           0 :                 dash++;
     545           0 :                 FOREACH_STRING(i, "VGA-", "DVI-I-", "DVI-D-", "DVI-A-"
     546             :                                "Composite-", "SVIDEO-", "Component-",
     547             :                                "DIN-", "DP-", "HDMI-A-", "HDMI-B-", "TV-") {
     548             : 
     549           0 :                         if (startswith(dash, i)) {
     550           0 :                                 external = true;
     551           0 :                                 break;
     552             :                         }
     553             :                 }
     554           0 :                 if (!external)
     555           0 :                         continue;
     556             : 
     557             :                 /* Ignore ports that are not enabled */
     558           0 :                 enabled = udev_device_get_sysattr_value(d, "enabled");
     559           0 :                 if (!enabled)
     560           0 :                         continue;
     561           0 :                 if (!streq_ptr(enabled, "enabled"))
     562           0 :                         continue;
     563             : 
     564             :                 /* We count any connector which is not explicitly
     565             :                  * "disconnected" as connected. */
     566           0 :                 status = udev_device_get_sysattr_value(d, "status");
     567           0 :                 if (!streq_ptr(status, "disconnected"))
     568           0 :                         n++;
     569             :         }
     570             : 
     571           0 :         return n;
     572             : }
     573             : 
     574           0 : bool manager_is_docked_or_external_displays(Manager *m) {
     575             :         int n;
     576             : 
     577             :         /* If we are docked don't react to lid closing */
     578           0 :         if (manager_is_docked(m)) {
     579           0 :                 log_debug("System is docked.");
     580           0 :                 return true;
     581             :         }
     582             : 
     583             :         /* If we have more than one display connected,
     584             :          * assume that we are docked. */
     585           0 :         n = manager_count_external_displays(m);
     586           0 :         if (n < 0)
     587           0 :                 log_warning_errno(n, "Display counting failed: %m");
     588           0 :         else if (n >= 1) {
     589           0 :                 log_debug("External (%i) displays connected.", n);
     590           0 :                 return true;
     591             :         }
     592             : 
     593           0 :         return false;
     594             : }

Generated by: LCOV version 1.11