LCOV - code coverage report
Current view: top level - login - logind-core.c (source / functions) Hit Total Coverage
Test: systemd_full.info Lines: 0 422 0.0 %
Date: 2019-08-23 13:36:53 Functions: 0 29 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 361 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: LGPL-2.1+ */
       2                 :            : 
       3                 :            : #include <fcntl.h>
       4                 :            : #include <pwd.h>
       5                 :            : #include <sys/ioctl.h>
       6                 :            : #include <sys/types.h>
       7                 :            : #include <linux/vt.h>
       8                 :            : #if ENABLE_UTMP
       9                 :            : #include <utmpx.h>
      10                 :            : #endif
      11                 :            : 
      12                 :            : #include "sd-device.h"
      13                 :            : 
      14                 :            : #include "alloc-util.h"
      15                 :            : #include "bus-error.h"
      16                 :            : #include "bus-util.h"
      17                 :            : #include "cgroup-util.h"
      18                 :            : #include "conf-parser.h"
      19                 :            : #include "device-util.h"
      20                 :            : #include "errno-util.h"
      21                 :            : #include "fd-util.h"
      22                 :            : #include "limits-util.h"
      23                 :            : #include "logind.h"
      24                 :            : #include "parse-util.h"
      25                 :            : #include "path-util.h"
      26                 :            : #include "process-util.h"
      27                 :            : #include "strv.h"
      28                 :            : #include "terminal-util.h"
      29                 :            : #include "udev-util.h"
      30                 :            : #include "user-util.h"
      31                 :            : 
      32                 :          0 : void manager_reset_config(Manager *m) {
      33         [ #  # ]:          0 :         assert(m);
      34                 :            : 
      35                 :          0 :         m->n_autovts = 6;
      36                 :          0 :         m->reserve_vt = 6;
      37                 :          0 :         m->remove_ipc = true;
      38                 :          0 :         m->inhibit_delay_max = 5 * USEC_PER_SEC;
      39                 :          0 :         m->user_stop_delay = 10 * USEC_PER_SEC;
      40                 :            : 
      41                 :          0 :         m->handle_power_key = HANDLE_POWEROFF;
      42                 :          0 :         m->handle_suspend_key = HANDLE_SUSPEND;
      43                 :          0 :         m->handle_hibernate_key = HANDLE_HIBERNATE;
      44                 :          0 :         m->handle_lid_switch = HANDLE_SUSPEND;
      45                 :          0 :         m->handle_lid_switch_ep = _HANDLE_ACTION_INVALID;
      46                 :          0 :         m->handle_lid_switch_docked = HANDLE_IGNORE;
      47                 :          0 :         m->power_key_ignore_inhibited = false;
      48                 :          0 :         m->suspend_key_ignore_inhibited = false;
      49                 :          0 :         m->hibernate_key_ignore_inhibited = false;
      50                 :          0 :         m->lid_switch_ignore_inhibited = true;
      51                 :            : 
      52                 :          0 :         m->holdoff_timeout_usec = 30 * USEC_PER_SEC;
      53                 :            : 
      54                 :          0 :         m->idle_action_usec = 30 * USEC_PER_MINUTE;
      55                 :          0 :         m->idle_action = HANDLE_IGNORE;
      56                 :            : 
      57                 :          0 :         m->runtime_dir_size = physical_memory_scale(10U, 100U); /* 10% */
      58                 :          0 :         m->user_tasks_max = system_tasks_max_scale(DEFAULT_USER_TASKS_MAX_PERCENTAGE, 100U); /* 33% */
      59                 :          0 :         m->sessions_max = 8192;
      60                 :          0 :         m->inhibitors_max = 8192;
      61                 :            : 
      62                 :          0 :         m->kill_user_processes = KILL_USER_PROCESSES;
      63                 :            : 
      64                 :          0 :         m->kill_only_users = strv_free(m->kill_only_users);
      65                 :          0 :         m->kill_exclude_users = strv_free(m->kill_exclude_users);
      66                 :          0 : }
      67                 :            : 
      68                 :          0 : int manager_parse_config_file(Manager *m) {
      69         [ #  # ]:          0 :         assert(m);
      70                 :            : 
      71                 :          0 :         return config_parse_many_nulstr(PKGSYSCONFDIR "/logind.conf",
      72                 :            :                                         CONF_PATHS_NULSTR("systemd/logind.conf.d"),
      73                 :            :                                         "Login\0",
      74                 :            :                                         config_item_perf_lookup, logind_gperf_lookup,
      75                 :            :                                         CONFIG_PARSE_WARN, m);
      76                 :            : }
      77                 :            : 
      78                 :          0 : int manager_add_device(Manager *m, const char *sysfs, bool master, Device **_device) {
      79                 :            :         Device *d;
      80                 :            : 
      81         [ #  # ]:          0 :         assert(m);
      82         [ #  # ]:          0 :         assert(sysfs);
      83                 :            : 
      84                 :          0 :         d = hashmap_get(m->devices, sysfs);
      85         [ #  # ]:          0 :         if (d)
      86                 :            :                 /* we support adding master-flags, but not removing them */
      87   [ #  #  #  # ]:          0 :                 d->master = d->master || master;
      88                 :            :         else {
      89                 :          0 :                 d = device_new(m, sysfs, master);
      90         [ #  # ]:          0 :                 if (!d)
      91                 :          0 :                         return -ENOMEM;
      92                 :            :         }
      93                 :            : 
      94         [ #  # ]:          0 :         if (_device)
      95                 :          0 :                 *_device = d;
      96                 :            : 
      97                 :          0 :         return 0;
      98                 :            : }
      99                 :            : 
     100                 :          0 : int manager_add_seat(Manager *m, const char *id, Seat **_seat) {
     101                 :            :         Seat *s;
     102                 :            :         int r;
     103                 :            : 
     104         [ #  # ]:          0 :         assert(m);
     105         [ #  # ]:          0 :         assert(id);
     106                 :            : 
     107                 :          0 :         s = hashmap_get(m->seats, id);
     108         [ #  # ]:          0 :         if (!s) {
     109                 :          0 :                 r = seat_new(&s, m, id);
     110         [ #  # ]:          0 :                 if (r < 0)
     111                 :          0 :                         return r;
     112                 :            :         }
     113                 :            : 
     114         [ #  # ]:          0 :         if (_seat)
     115                 :          0 :                 *_seat = s;
     116                 :            : 
     117                 :          0 :         return 0;
     118                 :            : }
     119                 :            : 
     120                 :          0 : int manager_add_session(Manager *m, const char *id, Session **_session) {
     121                 :            :         Session *s;
     122                 :            :         int r;
     123                 :            : 
     124         [ #  # ]:          0 :         assert(m);
     125         [ #  # ]:          0 :         assert(id);
     126                 :            : 
     127                 :          0 :         s = hashmap_get(m->sessions, id);
     128         [ #  # ]:          0 :         if (!s) {
     129                 :          0 :                 r = session_new(&s, m, id);
     130         [ #  # ]:          0 :                 if (r < 0)
     131                 :          0 :                         return r;
     132                 :            :         }
     133                 :            : 
     134         [ #  # ]:          0 :         if (_session)
     135                 :          0 :                 *_session = s;
     136                 :            : 
     137                 :          0 :         return 0;
     138                 :            : }
     139                 :            : 
     140                 :          0 : int manager_add_user(
     141                 :            :                 Manager *m,
     142                 :            :                 uid_t uid,
     143                 :            :                 gid_t gid,
     144                 :            :                 const char *name,
     145                 :            :                 const char *home,
     146                 :            :                 User **_user) {
     147                 :            : 
     148                 :            :         User *u;
     149                 :            :         int r;
     150                 :            : 
     151         [ #  # ]:          0 :         assert(m);
     152         [ #  # ]:          0 :         assert(name);
     153                 :            : 
     154                 :          0 :         u = hashmap_get(m->users, UID_TO_PTR(uid));
     155         [ #  # ]:          0 :         if (!u) {
     156                 :          0 :                 r = user_new(&u, m, uid, gid, name, home);
     157         [ #  # ]:          0 :                 if (r < 0)
     158                 :          0 :                         return r;
     159                 :            :         }
     160                 :            : 
     161         [ #  # ]:          0 :         if (_user)
     162                 :          0 :                 *_user = u;
     163                 :            : 
     164                 :          0 :         return 0;
     165                 :            : }
     166                 :            : 
     167                 :          0 : int manager_add_user_by_name(
     168                 :            :                 Manager *m,
     169                 :            :                 const char *name,
     170                 :            :                 User **_user) {
     171                 :            : 
     172                 :          0 :         const char *home = NULL;
     173                 :            :         uid_t uid;
     174                 :            :         gid_t gid;
     175                 :            :         int r;
     176                 :            : 
     177         [ #  # ]:          0 :         assert(m);
     178         [ #  # ]:          0 :         assert(name);
     179                 :            : 
     180                 :          0 :         r = get_user_creds(&name, &uid, &gid, &home, NULL, 0);
     181         [ #  # ]:          0 :         if (r < 0)
     182                 :          0 :                 return r;
     183                 :            : 
     184                 :          0 :         return manager_add_user(m, uid, gid, name, home, _user);
     185                 :            : }
     186                 :            : 
     187                 :          0 : int manager_add_user_by_uid(Manager *m, uid_t uid, User **_user) {
     188                 :            :         struct passwd *p;
     189                 :            : 
     190         [ #  # ]:          0 :         assert(m);
     191                 :            : 
     192                 :          0 :         errno = 0;
     193                 :          0 :         p = getpwuid(uid);
     194         [ #  # ]:          0 :         if (!p)
     195                 :          0 :                 return errno_or_else(ENOENT);
     196                 :            : 
     197                 :          0 :         return manager_add_user(m, uid, p->pw_gid, p->pw_name, p->pw_dir, _user);
     198                 :            : }
     199                 :            : 
     200                 :          0 : int manager_add_inhibitor(Manager *m, const char* id, Inhibitor **ret) {
     201                 :            :         Inhibitor *i;
     202                 :            :         int r;
     203                 :            : 
     204         [ #  # ]:          0 :         assert(m);
     205         [ #  # ]:          0 :         assert(id);
     206                 :            : 
     207                 :          0 :         i = hashmap_get(m->inhibitors, id);
     208         [ #  # ]:          0 :         if (!i) {
     209                 :          0 :                 r = inhibitor_new(&i, m, id);
     210         [ #  # ]:          0 :                 if (r < 0)
     211                 :          0 :                         return r;
     212                 :            :         }
     213                 :            : 
     214         [ #  # ]:          0 :         if (ret)
     215                 :          0 :                 *ret = i;
     216                 :            : 
     217                 :          0 :         return 0;
     218                 :            : }
     219                 :            : 
     220                 :          0 : int manager_add_button(Manager *m, const char *name, Button **_button) {
     221                 :            :         Button *b;
     222                 :            : 
     223         [ #  # ]:          0 :         assert(m);
     224         [ #  # ]:          0 :         assert(name);
     225                 :            : 
     226                 :          0 :         b = hashmap_get(m->buttons, name);
     227         [ #  # ]:          0 :         if (!b) {
     228                 :          0 :                 b = button_new(m, name);
     229         [ #  # ]:          0 :                 if (!b)
     230                 :          0 :                         return -ENOMEM;
     231                 :            :         }
     232                 :            : 
     233         [ #  # ]:          0 :         if (_button)
     234                 :          0 :                 *_button = b;
     235                 :            : 
     236                 :          0 :         return 0;
     237                 :            : }
     238                 :            : 
     239                 :          0 : int manager_process_seat_device(Manager *m, sd_device *d) {
     240                 :            :         Device *device;
     241                 :            :         int r;
     242                 :            : 
     243         [ #  # ]:          0 :         assert(m);
     244                 :            : 
     245         [ #  # ]:          0 :         if (device_for_action(d, DEVICE_ACTION_REMOVE)) {
     246                 :            :                 const char *syspath;
     247                 :            : 
     248                 :          0 :                 r = sd_device_get_syspath(d, &syspath);
     249         [ #  # ]:          0 :                 if (r < 0)
     250                 :          0 :                         return 0;
     251                 :            : 
     252                 :          0 :                 device = hashmap_get(m->devices, syspath);
     253         [ #  # ]:          0 :                 if (!device)
     254                 :          0 :                         return 0;
     255                 :            : 
     256                 :          0 :                 seat_add_to_gc_queue(device->seat);
     257                 :          0 :                 device_free(device);
     258                 :            : 
     259                 :            :         } else {
     260                 :            :                 const char *sn, *syspath;
     261                 :            :                 bool master;
     262                 :            :                 Seat *seat;
     263                 :            : 
     264   [ #  #  #  # ]:          0 :                 if (sd_device_get_property_value(d, "ID_SEAT", &sn) < 0 || isempty(sn))
     265                 :          0 :                         sn = "seat0";
     266                 :            : 
     267         [ #  # ]:          0 :                 if (!seat_name_is_valid(sn)) {
     268   [ #  #  #  #  :          0 :                         log_device_warning(d, "Device with invalid seat name %s found, ignoring.", sn);
                   #  # ]
     269                 :          0 :                         return 0;
     270                 :            :                 }
     271                 :            : 
     272                 :          0 :                 seat = hashmap_get(m->seats, sn);
     273                 :          0 :                 master = sd_device_has_tag(d, "master-of-seat") > 0;
     274                 :            : 
     275                 :            :                 /* Ignore non-master devices for unknown seats */
     276   [ #  #  #  # ]:          0 :                 if (!master && !seat)
     277                 :          0 :                         return 0;
     278                 :            : 
     279                 :          0 :                 r = sd_device_get_syspath(d, &syspath);
     280         [ #  # ]:          0 :                 if (r < 0)
     281                 :          0 :                         return r;
     282                 :            : 
     283                 :          0 :                 r = manager_add_device(m, syspath, master, &device);
     284         [ #  # ]:          0 :                 if (r < 0)
     285                 :          0 :                         return r;
     286                 :            : 
     287         [ #  # ]:          0 :                 if (!seat) {
     288                 :          0 :                         r = manager_add_seat(m, sn, &seat);
     289         [ #  # ]:          0 :                         if (r < 0) {
     290         [ #  # ]:          0 :                                 if (!device->seat)
     291                 :          0 :                                         device_free(device);
     292                 :            : 
     293                 :          0 :                                 return r;
     294                 :            :                         }
     295                 :            :                 }
     296                 :            : 
     297                 :          0 :                 device_attach(device, seat);
     298                 :          0 :                 seat_start(seat);
     299                 :            :         }
     300                 :            : 
     301                 :          0 :         return 0;
     302                 :            : }
     303                 :            : 
     304                 :          0 : int manager_process_button_device(Manager *m, sd_device *d) {
     305                 :            :         const char *sysname;
     306                 :            :         Button *b;
     307                 :            :         int r;
     308                 :            : 
     309         [ #  # ]:          0 :         assert(m);
     310                 :            : 
     311                 :          0 :         r = sd_device_get_sysname(d, &sysname);
     312         [ #  # ]:          0 :         if (r < 0)
     313                 :          0 :                 return r;
     314                 :            : 
     315         [ #  # ]:          0 :         if (device_for_action(d, DEVICE_ACTION_REMOVE)) {
     316                 :            : 
     317                 :          0 :                 b = hashmap_get(m->buttons, sysname);
     318         [ #  # ]:          0 :                 if (!b)
     319                 :          0 :                         return 0;
     320                 :            : 
     321                 :          0 :                 button_free(b);
     322                 :            : 
     323                 :            :         } else {
     324                 :            :                 const char *sn;
     325                 :            : 
     326                 :          0 :                 r = manager_add_button(m, sysname, &b);
     327         [ #  # ]:          0 :                 if (r < 0)
     328                 :          0 :                         return r;
     329                 :            : 
     330   [ #  #  #  # ]:          0 :                 if (sd_device_get_property_value(d, "ID_SEAT", &sn) < 0 || isempty(sn))
     331                 :          0 :                         sn = "seat0";
     332                 :            : 
     333                 :          0 :                 button_set_seat(b, sn);
     334                 :            : 
     335                 :          0 :                 r = button_open(b);
     336         [ #  # ]:          0 :                 if (r < 0) /* event device doesn't have any keys or switches relevant to us? (or any other error
     337                 :            :                             * opening the device?) let's close the button again. */
     338                 :          0 :                         button_free(b);
     339                 :            :         }
     340                 :            : 
     341                 :          0 :         return 0;
     342                 :            : }
     343                 :            : 
     344                 :          0 : int manager_get_session_by_pid(Manager *m, pid_t pid, Session **ret) {
     345                 :          0 :         _cleanup_free_ char *unit = NULL;
     346                 :            :         Session *s;
     347                 :            :         int r;
     348                 :            : 
     349         [ #  # ]:          0 :         assert(m);
     350                 :            : 
     351         [ #  # ]:          0 :         if (!pid_is_valid(pid))
     352                 :          0 :                 return -EINVAL;
     353                 :            : 
     354                 :          0 :         s = hashmap_get(m->sessions_by_leader, PID_TO_PTR(pid));
     355         [ #  # ]:          0 :         if (!s) {
     356                 :          0 :                 r = cg_pid_get_unit(pid, &unit);
     357         [ #  # ]:          0 :                 if (r < 0)
     358                 :          0 :                         goto not_found;
     359                 :            : 
     360                 :          0 :                 s = hashmap_get(m->session_units, unit);
     361         [ #  # ]:          0 :                 if (!s)
     362                 :          0 :                         goto not_found;
     363                 :            :         }
     364                 :            : 
     365         [ #  # ]:          0 :         if (ret)
     366                 :          0 :                 *ret = s;
     367                 :            : 
     368                 :          0 :         return 1;
     369                 :            : 
     370                 :          0 : not_found:
     371         [ #  # ]:          0 :         if (ret)
     372                 :          0 :                 *ret = NULL;
     373                 :          0 :         return 0;
     374                 :            : }
     375                 :            : 
     376                 :          0 : int manager_get_user_by_pid(Manager *m, pid_t pid, User **ret) {
     377                 :          0 :         _cleanup_free_ char *unit = NULL;
     378                 :            :         User *u;
     379                 :            :         int r;
     380                 :            : 
     381         [ #  # ]:          0 :         assert(m);
     382                 :            : 
     383         [ #  # ]:          0 :         if (!pid_is_valid(pid))
     384                 :          0 :                 return -EINVAL;
     385                 :            : 
     386                 :          0 :         r = cg_pid_get_slice(pid, &unit);
     387         [ #  # ]:          0 :         if (r < 0)
     388                 :          0 :                 goto not_found;
     389                 :            : 
     390                 :          0 :         u = hashmap_get(m->user_units, unit);
     391         [ #  # ]:          0 :         if (!u)
     392                 :          0 :                 goto not_found;
     393                 :            : 
     394         [ #  # ]:          0 :         if (ret)
     395                 :          0 :                 *ret = u;
     396                 :            : 
     397                 :          0 :         return 1;
     398                 :            : 
     399                 :          0 : not_found:
     400         [ #  # ]:          0 :         if (ret)
     401                 :          0 :                 *ret = NULL;
     402                 :            : 
     403                 :          0 :         return 0;
     404                 :            : }
     405                 :            : 
     406                 :          0 : int manager_get_idle_hint(Manager *m, dual_timestamp *t) {
     407                 :            :         Session *s;
     408                 :            :         bool idle_hint;
     409                 :          0 :         dual_timestamp ts = DUAL_TIMESTAMP_NULL;
     410                 :            :         Iterator i;
     411                 :            : 
     412         [ #  # ]:          0 :         assert(m);
     413                 :            : 
     414                 :          0 :         idle_hint = !manager_is_inhibited(m, INHIBIT_IDLE, INHIBIT_BLOCK, t, false, false, 0, NULL);
     415                 :            : 
     416         [ #  # ]:          0 :         HASHMAP_FOREACH(s, m->sessions, i) {
     417                 :            :                 dual_timestamp k;
     418                 :            :                 int ih;
     419                 :            : 
     420                 :          0 :                 ih = session_get_idle_hint(s, &k);
     421         [ #  # ]:          0 :                 if (ih < 0)
     422                 :          0 :                         return ih;
     423                 :            : 
     424         [ #  # ]:          0 :                 if (!ih) {
     425         [ #  # ]:          0 :                         if (!idle_hint) {
     426         [ #  # ]:          0 :                                 if (k.monotonic < ts.monotonic)
     427                 :          0 :                                         ts = k;
     428                 :            :                         } else {
     429                 :          0 :                                 idle_hint = false;
     430                 :          0 :                                 ts = k;
     431                 :            :                         }
     432         [ #  # ]:          0 :                 } else if (idle_hint) {
     433                 :            : 
     434         [ #  # ]:          0 :                         if (k.monotonic > ts.monotonic)
     435                 :          0 :                                 ts = k;
     436                 :            :                 }
     437                 :            :         }
     438                 :            : 
     439         [ #  # ]:          0 :         if (t)
     440                 :          0 :                 *t = ts;
     441                 :            : 
     442                 :          0 :         return idle_hint;
     443                 :            : }
     444                 :            : 
     445                 :          0 : bool manager_shall_kill(Manager *m, const char *user) {
     446         [ #  # ]:          0 :         assert(m);
     447         [ #  # ]:          0 :         assert(user);
     448                 :            : 
     449   [ #  #  #  # ]:          0 :         if (!m->kill_exclude_users && streq(user, "root"))
     450                 :          0 :                 return false;
     451                 :            : 
     452         [ #  # ]:          0 :         if (strv_contains(m->kill_exclude_users, user))
     453                 :          0 :                 return false;
     454                 :            : 
     455         [ #  # ]:          0 :         if (!strv_isempty(m->kill_only_users))
     456                 :          0 :                 return strv_contains(m->kill_only_users, user);
     457                 :            : 
     458                 :          0 :         return m->kill_user_processes;
     459                 :            : }
     460                 :            : 
     461                 :          0 : int config_parse_n_autovts(
     462                 :            :                 const char *unit,
     463                 :            :                 const char *filename,
     464                 :            :                 unsigned line,
     465                 :            :                 const char *section,
     466                 :            :                 unsigned section_line,
     467                 :            :                 const char *lvalue,
     468                 :            :                 int ltype,
     469                 :            :                 const char *rvalue,
     470                 :            :                 void *data,
     471                 :            :                 void *userdata) {
     472                 :            : 
     473                 :          0 :         unsigned *n = data;
     474                 :            :         unsigned o;
     475                 :            :         int r;
     476                 :            : 
     477         [ #  # ]:          0 :         assert(filename);
     478         [ #  # ]:          0 :         assert(lvalue);
     479         [ #  # ]:          0 :         assert(rvalue);
     480         [ #  # ]:          0 :         assert(data);
     481                 :            : 
     482                 :          0 :         r = safe_atou(rvalue, &o);
     483         [ #  # ]:          0 :         if (r < 0) {
     484         [ #  # ]:          0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse number of autovts, ignoring: %s", rvalue);
     485                 :          0 :                 return 0;
     486                 :            :         }
     487                 :            : 
     488         [ #  # ]:          0 :         if (o > 15) {
     489         [ #  # ]:          0 :                 log_syntax(unit, LOG_ERR, filename, line, r, "A maximum of 15 autovts are supported, ignoring: %s", rvalue);
     490                 :          0 :                 return 0;
     491                 :            :         }
     492                 :            : 
     493                 :          0 :         *n = o;
     494                 :          0 :         return 0;
     495                 :            : }
     496                 :            : 
     497                 :          0 : static int vt_is_busy(unsigned vtnr) {
     498                 :            :         struct vt_stat vt_stat;
     499                 :          0 :         int r = 0;
     500                 :          0 :         _cleanup_close_ int fd;
     501                 :            : 
     502         [ #  # ]:          0 :         assert(vtnr >= 1);
     503                 :            : 
     504                 :            :         /* VT_GETSTATE "cannot return state for more than 16 VTs, since v_state is short" */
     505         [ #  # ]:          0 :         assert(vtnr <= 15);
     506                 :            : 
     507                 :            :         /* We explicitly open /dev/tty1 here instead of /dev/tty0. If
     508                 :            :          * we'd open the latter we'd open the foreground tty which
     509                 :            :          * hence would be unconditionally busy. By opening /dev/tty1
     510                 :            :          * we avoid this. Since tty1 is special and needs to be an
     511                 :            :          * explicitly loaded getty or DM this is safe. */
     512                 :            : 
     513                 :          0 :         fd = open_terminal("/dev/tty1", O_RDWR|O_NOCTTY|O_CLOEXEC);
     514         [ #  # ]:          0 :         if (fd < 0)
     515                 :          0 :                 return -errno;
     516                 :            : 
     517         [ #  # ]:          0 :         if (ioctl(fd, VT_GETSTATE, &vt_stat) < 0)
     518                 :          0 :                 r = -errno;
     519                 :            :         else
     520                 :          0 :                 r = !!(vt_stat.v_state & (1 << vtnr));
     521                 :            : 
     522                 :          0 :         return r;
     523                 :            : }
     524                 :            : 
     525                 :          0 : int manager_spawn_autovt(Manager *m, unsigned vtnr) {
     526                 :          0 :         _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
     527                 :            :         char name[sizeof("autovt@tty.service") + DECIMAL_STR_MAX(unsigned)];
     528                 :            :         int r;
     529                 :            : 
     530         [ #  # ]:          0 :         assert(m);
     531         [ #  # ]:          0 :         assert(vtnr >= 1);
     532                 :            : 
     533         [ #  # ]:          0 :         if (vtnr > m->n_autovts &&
     534         [ #  # ]:          0 :             vtnr != m->reserve_vt)
     535                 :          0 :                 return 0;
     536                 :            : 
     537         [ #  # ]:          0 :         if (vtnr != m->reserve_vt) {
     538                 :            :                 /* If this is the reserved TTY, we'll start the getty
     539                 :            :                  * on it in any case, but otherwise only if it is not
     540                 :            :                  * busy. */
     541                 :            : 
     542                 :          0 :                 r = vt_is_busy(vtnr);
     543         [ #  # ]:          0 :                 if (r < 0)
     544                 :          0 :                         return r;
     545         [ #  # ]:          0 :                 else if (r > 0)
     546                 :          0 :                         return -EBUSY;
     547                 :            :         }
     548                 :            : 
     549                 :          0 :         snprintf(name, sizeof(name), "autovt@tty%u.service", vtnr);
     550                 :          0 :         r = sd_bus_call_method(
     551                 :            :                         m->bus,
     552                 :            :                         "org.freedesktop.systemd1",
     553                 :            :                         "/org/freedesktop/systemd1",
     554                 :            :                         "org.freedesktop.systemd1.Manager",
     555                 :            :                         "StartUnit",
     556                 :            :                         &error,
     557                 :            :                         NULL,
     558                 :            :                         "ss", name, "fail");
     559         [ #  # ]:          0 :         if (r < 0)
     560         [ #  # ]:          0 :                 return log_error_errno(r, "Failed to start %s: %s", name, bus_error_message(&error, r));
     561                 :            : 
     562                 :          0 :         return 0;
     563                 :            : }
     564                 :            : 
     565                 :          0 : bool manager_is_lid_closed(Manager *m) {
     566                 :            :         Iterator i;
     567                 :            :         Button *b;
     568                 :            : 
     569         [ #  # ]:          0 :         HASHMAP_FOREACH(b, m->buttons, i)
     570         [ #  # ]:          0 :                 if (b->lid_closed)
     571                 :          0 :                         return true;
     572                 :            : 
     573                 :          0 :         return false;
     574                 :            : }
     575                 :            : 
     576                 :          0 : static bool manager_is_docked(Manager *m) {
     577                 :            :         Iterator i;
     578                 :            :         Button *b;
     579                 :            : 
     580         [ #  # ]:          0 :         HASHMAP_FOREACH(b, m->buttons, i)
     581         [ #  # ]:          0 :                 if (b->docked)
     582                 :          0 :                         return true;
     583                 :            : 
     584                 :          0 :         return false;
     585                 :            : }
     586                 :            : 
     587                 :          0 : static int manager_count_external_displays(Manager *m) {
     588                 :          0 :         _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL;
     589                 :            :         sd_device *d;
     590                 :          0 :         int r, n = 0;
     591                 :            : 
     592                 :          0 :         r = sd_device_enumerator_new(&e);
     593         [ #  # ]:          0 :         if (r < 0)
     594                 :          0 :                 return r;
     595                 :            : 
     596                 :          0 :         r = sd_device_enumerator_allow_uninitialized(e);
     597         [ #  # ]:          0 :         if (r < 0)
     598                 :          0 :                 return r;
     599                 :            : 
     600                 :          0 :         r = sd_device_enumerator_add_match_subsystem(e, "drm", true);
     601         [ #  # ]:          0 :         if (r < 0)
     602                 :          0 :                 return r;
     603                 :            : 
     604         [ #  # ]:          0 :         FOREACH_DEVICE(e, d) {
     605                 :            :                 const char *status, *enabled, *dash, *nn, *subsys;
     606                 :            :                 sd_device *p;
     607                 :            : 
     608         [ #  # ]:          0 :                 if (sd_device_get_parent(d, &p) < 0)
     609                 :          0 :                         continue;
     610                 :            : 
     611                 :            :                 /* If the parent shares the same subsystem as the
     612                 :            :                  * device we are looking at then it is a connector,
     613                 :            :                  * which is what we are interested in. */
     614   [ #  #  #  # ]:          0 :                 if (sd_device_get_subsystem(p, &subsys) < 0 || !streq(subsys, "drm"))
     615                 :          0 :                         continue;
     616                 :            : 
     617         [ #  # ]:          0 :                 if (sd_device_get_sysname(d, &nn) < 0)
     618                 :          0 :                         continue;
     619                 :            : 
     620                 :            :                 /* Ignore internal displays: the type is encoded in the sysfs name, as the second dash separated item
     621                 :            :                  * (the first is the card name, the last the connector number). We implement a blacklist of external
     622                 :            :                  * displays here, rather than a whitelist of internal ones, to ensure we don't block suspends too
     623                 :            :                  * eagerly. */
     624                 :          0 :                 dash = strchr(nn, '-');
     625         [ #  # ]:          0 :                 if (!dash)
     626                 :          0 :                         continue;
     627                 :            : 
     628                 :          0 :                 dash++;
     629   [ #  #  #  #  :          0 :                 if (!STARTSWITH_SET(dash,
             #  #  #  # ]
     630                 :            :                                     "VGA-", "DVI-I-", "DVI-D-", "DVI-A-"
     631                 :            :                                     "Composite-", "SVIDEO-", "Component-",
     632                 :            :                                     "DIN-", "DP-", "HDMI-A-", "HDMI-B-", "TV-"))
     633                 :          0 :                         continue;
     634                 :            : 
     635                 :            :                 /* Ignore ports that are not enabled */
     636   [ #  #  #  # ]:          0 :                 if (sd_device_get_sysattr_value(d, "enabled", &enabled) < 0 || !streq(enabled, "enabled"))
     637                 :          0 :                         continue;
     638                 :            : 
     639                 :            :                 /* We count any connector which is not explicitly
     640                 :            :                  * "disconnected" as connected. */
     641   [ #  #  #  # ]:          0 :                 if (sd_device_get_sysattr_value(d, "status", &status) < 0 || !streq(status, "disconnected"))
     642                 :          0 :                         n++;
     643                 :            :         }
     644                 :            : 
     645                 :          0 :         return n;
     646                 :            : }
     647                 :            : 
     648                 :          0 : bool manager_is_docked_or_external_displays(Manager *m) {
     649                 :            :         int n;
     650                 :            : 
     651                 :            :         /* If we are docked don't react to lid closing */
     652         [ #  # ]:          0 :         if (manager_is_docked(m)) {
     653         [ #  # ]:          0 :                 log_debug("System is docked.");
     654                 :          0 :                 return true;
     655                 :            :         }
     656                 :            : 
     657                 :            :         /* If we have more than one display connected,
     658                 :            :          * assume that we are docked. */
     659                 :          0 :         n = manager_count_external_displays(m);
     660         [ #  # ]:          0 :         if (n < 0)
     661         [ #  # ]:          0 :                 log_warning_errno(n, "Display counting failed: %m");
     662         [ #  # ]:          0 :         else if (n >= 1) {
     663         [ #  # ]:          0 :                 log_debug("External (%i) displays connected.", n);
     664                 :          0 :                 return true;
     665                 :            :         }
     666                 :            : 
     667                 :          0 :         return false;
     668                 :            : }
     669                 :            : 
     670                 :          0 : bool manager_is_on_external_power(void) {
     671                 :            :         int r;
     672                 :            : 
     673                 :            :         /* For now we only check for AC power, but 'external power' can apply to anything that isn't an internal
     674                 :            :          * battery */
     675                 :          0 :         r = on_ac_power();
     676         [ #  # ]:          0 :         if (r < 0)
     677         [ #  # ]:          0 :                 log_warning_errno(r, "Failed to read AC power status: %m");
     678                 :            : 
     679                 :          0 :         return r != 0; /* Treat failure as 'on AC' */
     680                 :            : }
     681                 :            : 
     682                 :          0 : bool manager_all_buttons_ignored(Manager *m) {
     683         [ #  # ]:          0 :         assert(m);
     684                 :            : 
     685         [ #  # ]:          0 :         if (m->handle_power_key != HANDLE_IGNORE)
     686                 :          0 :                 return false;
     687         [ #  # ]:          0 :         if (m->handle_suspend_key != HANDLE_IGNORE)
     688                 :          0 :                 return false;
     689         [ #  # ]:          0 :         if (m->handle_hibernate_key != HANDLE_IGNORE)
     690                 :          0 :                 return false;
     691         [ #  # ]:          0 :         if (m->handle_lid_switch != HANDLE_IGNORE)
     692                 :          0 :                 return false;
     693   [ #  #  #  # ]:          0 :         if (!IN_SET(m->handle_lid_switch_ep, _HANDLE_ACTION_INVALID, HANDLE_IGNORE))
     694                 :          0 :                 return false;
     695         [ #  # ]:          0 :         if (m->handle_lid_switch_docked != HANDLE_IGNORE)
     696                 :          0 :                 return false;
     697                 :            : 
     698                 :          0 :         return true;
     699                 :            : }
     700                 :            : 
     701                 :          0 : int manager_read_utmp(Manager *m) {
     702                 :            : #if ENABLE_UTMP
     703                 :            :         int r;
     704                 :            : 
     705         [ #  # ]:          0 :         assert(m);
     706                 :            : 
     707         [ #  # ]:          0 :         if (utmpxname(_PATH_UTMPX) < 0)
     708         [ #  # ]:          0 :                 return log_error_errno(errno, "Failed to set utmp path to " _PATH_UTMPX ": %m");
     709                 :            : 
     710                 :          0 :         setutxent();
     711                 :            : 
     712                 :          0 :         for (;;) {
     713      [ #  #  # ]:          0 :                 _cleanup_free_ char *t = NULL;
     714                 :            :                 struct utmpx *u;
     715                 :            :                 const char *c;
     716                 :            :                 Session *s;
     717                 :            : 
     718                 :          0 :                 errno = 0;
     719                 :          0 :                 u = getutxent();
     720         [ #  # ]:          0 :                 if (!u) {
     721         [ #  # ]:          0 :                         if (errno != 0)
     722         [ #  # ]:          0 :                                 log_warning_errno(errno, "Failed to read " _PATH_UTMPX ", ignoring: %m");
     723                 :          0 :                         r = 0;
     724                 :          0 :                         break;
     725                 :            :                 }
     726                 :            : 
     727         [ #  # ]:          0 :                 if (u->ut_type != USER_PROCESS)
     728                 :          0 :                         continue;
     729                 :            : 
     730         [ #  # ]:          0 :                 if (!pid_is_valid(u->ut_pid))
     731                 :          0 :                         continue;
     732                 :            : 
     733                 :          0 :                 t = strndup(u->ut_line, sizeof(u->ut_line));
     734         [ #  # ]:          0 :                 if (!t) {
     735                 :          0 :                         r = log_oom();
     736                 :          0 :                         break;
     737                 :            :                 }
     738                 :            : 
     739                 :          0 :                 c = path_startswith(t, "/dev/");
     740         [ #  # ]:          0 :                 if (c) {
     741                 :          0 :                         r = free_and_strdup(&t, c);
     742         [ #  # ]:          0 :                         if (r < 0) {
     743                 :          0 :                                 log_oom();
     744                 :          0 :                                 break;
     745                 :            :                         }
     746                 :            :                 }
     747                 :            : 
     748         [ #  # ]:          0 :                 if (isempty(t))
     749                 :          0 :                         continue;
     750                 :            : 
     751                 :          0 :                 s = hashmap_get(m->sessions_by_leader, PID_TO_PTR(u->ut_pid));
     752         [ #  # ]:          0 :                 if (!s)
     753                 :          0 :                         continue;
     754                 :            : 
     755   [ #  #  #  # ]:          0 :                 if (s->tty_validity == TTY_FROM_UTMP && !streq_ptr(s->tty, t)) {
     756                 :            :                         /* This may happen on multiplexed SSH connection (i.e. 'SSH connection sharing'). In
     757                 :            :                          * this case PAM and utmp sessions don't match. In such a case let's invalidate the TTY
     758                 :            :                          * information and never acquire it again. */
     759                 :            : 
     760                 :          0 :                         s->tty = mfree(s->tty);
     761                 :          0 :                         s->tty_validity = TTY_UTMP_INCONSISTENT;
     762         [ #  # ]:          0 :                         log_debug("Session '%s' has inconsistent TTY information, dropping TTY information.", s->id);
     763                 :          0 :                         continue;
     764                 :            :                 }
     765                 :            : 
     766                 :            :                 /* Never override what we figured out once */
     767   [ #  #  #  # ]:          0 :                 if (s->tty || s->tty_validity >= 0)
     768                 :          0 :                         continue;
     769                 :            : 
     770                 :          0 :                 s->tty = TAKE_PTR(t);
     771                 :          0 :                 s->tty_validity = TTY_FROM_UTMP;
     772         [ #  # ]:          0 :                 log_debug("Acquired TTY information '%s' from utmp for session '%s'.", s->tty, s->id);
     773                 :            :         }
     774                 :            : 
     775                 :          0 :         endutxent();
     776                 :          0 :         return r;
     777                 :            : #else
     778                 :            :         return 0;
     779                 :            : #endif
     780                 :            : }
     781                 :            : 
     782                 :            : #if ENABLE_UTMP
     783                 :          0 : static int manager_dispatch_utmp(sd_event_source *s, const struct inotify_event *event, void *userdata) {
     784                 :          0 :         Manager *m = userdata;
     785                 :            : 
     786         [ #  # ]:          0 :         assert(m);
     787                 :            : 
     788                 :            :         /* If there's indication the file itself might have been removed or became otherwise unavailable, then let's
     789                 :            :          * reestablish the watch on whatever there's now. */
     790         [ #  # ]:          0 :         if ((event->mask & (IN_ATTRIB|IN_DELETE_SELF|IN_MOVE_SELF|IN_Q_OVERFLOW|IN_UNMOUNT)) != 0)
     791                 :          0 :                 manager_connect_utmp(m);
     792                 :            : 
     793                 :          0 :         (void) manager_read_utmp(m);
     794                 :          0 :         return 0;
     795                 :            : }
     796                 :            : #endif
     797                 :            : 
     798                 :          0 : void manager_connect_utmp(Manager *m) {
     799                 :            : #if ENABLE_UTMP
     800                 :          0 :         sd_event_source *s = NULL;
     801                 :            :         int r;
     802                 :            : 
     803         [ #  # ]:          0 :         assert(m);
     804                 :            : 
     805                 :            :         /* Watch utmp for changes via inotify. We do this to deal with tools such as ssh, which will register the PAM
     806                 :            :          * session early, and acquire a TTY only much later for the connection. Thus during PAM the TTY won't be known
     807                 :            :          * yet. ssh will register itself with utmp when it finally acquired the TTY. Hence, let's make use of this, and
     808                 :            :          * watch utmp for the TTY asynchronously. We use the PAM session's leader PID as key, to find the right entry.
     809                 :            :          *
     810                 :            :          * Yes, relying on utmp is pretty ugly, but it's good enough for informational purposes, as well as idle
     811                 :            :          * detection (which, for tty sessions, relies on the TTY used) */
     812                 :            : 
     813                 :          0 :         r = sd_event_add_inotify(m->event, &s, _PATH_UTMPX, IN_MODIFY|IN_MOVE_SELF|IN_DELETE_SELF|IN_ATTRIB, manager_dispatch_utmp, m);
     814         [ #  # ]:          0 :         if (r < 0)
     815   [ #  #  #  # ]:          0 :                 log_full_errno(r == -ENOENT ? LOG_DEBUG: LOG_WARNING, r, "Failed to create inotify watch on " _PATH_UTMPX ", ignoring: %m");
     816                 :            :         else {
     817                 :          0 :                 r = sd_event_source_set_priority(s, SD_EVENT_PRIORITY_IDLE);
     818         [ #  # ]:          0 :                 if (r < 0)
     819         [ #  # ]:          0 :                         log_warning_errno(r, "Failed to adjust utmp event source priority, ignoring: %m");
     820                 :            : 
     821                 :          0 :                 (void) sd_event_source_set_description(s, "utmp");
     822                 :            :         }
     823                 :            : 
     824                 :          0 :         sd_event_source_unref(m->utmp_event_source);
     825                 :          0 :         m->utmp_event_source = s;
     826                 :            : #endif
     827                 :          0 : }
     828                 :            : 
     829                 :          0 : void manager_reconnect_utmp(Manager *m) {
     830                 :            : #if ENABLE_UTMP
     831         [ #  # ]:          0 :         assert(m);
     832                 :            : 
     833         [ #  # ]:          0 :         if (m->utmp_event_source)
     834                 :          0 :                 return;
     835                 :            : 
     836                 :          0 :         manager_connect_utmp(m);
     837                 :            : #endif
     838                 :            : }

Generated by: LCOV version 1.14