LCOV - code coverage report
Current view: top level - login - logind-button.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 0 131 0.0 %
Date: 2015-07-29 18:47:03 Functions: 0 9 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 2012 Lennart Poettering
       7             : 
       8             :   systemd is free software; you can redistribute it and/or modify it
       9             :   under the terms of the GNU Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   systemd is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             : ***/
      21             : 
      22             : #include <string.h>
      23             : #include <errno.h>
      24             : #include <fcntl.h>
      25             : #include <sys/ioctl.h>
      26             : #include <unistd.h>
      27             : #include <linux/input.h>
      28             : 
      29             : #include "sd-messages.h"
      30             : #include "util.h"
      31             : #include "logind-button.h"
      32             : 
      33           0 : Button* button_new(Manager *m, const char *name) {
      34             :         Button *b;
      35             : 
      36           0 :         assert(m);
      37           0 :         assert(name);
      38             : 
      39           0 :         b = new0(Button, 1);
      40           0 :         if (!b)
      41           0 :                 return NULL;
      42             : 
      43           0 :         b->name = strdup(name);
      44           0 :         if (!b->name) {
      45           0 :                 free(b);
      46           0 :                 return NULL;
      47             :         }
      48             : 
      49           0 :         if (hashmap_put(m->buttons, b->name, b) < 0) {
      50           0 :                 free(b->name);
      51           0 :                 free(b);
      52           0 :                 return NULL;
      53             :         }
      54             : 
      55           0 :         b->manager = m;
      56           0 :         b->fd = -1;
      57             : 
      58           0 :         return b;
      59             : }
      60             : 
      61           0 : void button_free(Button *b) {
      62           0 :         assert(b);
      63             : 
      64           0 :         hashmap_remove(b->manager->buttons, b->name);
      65             : 
      66           0 :         sd_event_source_unref(b->io_event_source);
      67           0 :         sd_event_source_unref(b->check_event_source);
      68             : 
      69           0 :         if (b->fd >= 0) {
      70             :                 /* If the device has been unplugged close() returns
      71             :                  * ENODEV, let's ignore this, hence we don't use
      72             :                  * safe_close() */
      73           0 :                 (void) close(b->fd);
      74             :         }
      75             : 
      76           0 :         free(b->name);
      77           0 :         free(b->seat);
      78           0 :         free(b);
      79           0 : }
      80             : 
      81           0 : int button_set_seat(Button *b, const char *sn) {
      82             :         char *s;
      83             : 
      84           0 :         assert(b);
      85           0 :         assert(sn);
      86             : 
      87           0 :         s = strdup(sn);
      88           0 :         if (!s)
      89           0 :                 return -ENOMEM;
      90             : 
      91           0 :         free(b->seat);
      92           0 :         b->seat = s;
      93             : 
      94           0 :         return 0;
      95             : }
      96             : 
      97           0 : static void button_lid_switch_handle_action(Manager *manager, bool is_edge) {
      98             :         HandleAction handle_action;
      99             : 
     100           0 :         assert(manager);
     101             : 
     102             :         /* If we are docked, handle the lid switch differently */
     103           0 :         if (manager_is_docked_or_external_displays(manager))
     104           0 :                 handle_action = manager->handle_lid_switch_docked;
     105             :         else
     106           0 :                 handle_action = manager->handle_lid_switch;
     107             : 
     108           0 :         manager_handle_action(manager, INHIBIT_HANDLE_LID_SWITCH, handle_action, manager->lid_switch_ignore_inhibited, is_edge);
     109           0 : }
     110             : 
     111           0 : static int button_recheck(sd_event_source *e, void *userdata) {
     112           0 :         Button *b = userdata;
     113             : 
     114           0 :         assert(b);
     115           0 :         assert(b->lid_closed);
     116             : 
     117           0 :         button_lid_switch_handle_action(b->manager, false);
     118           0 :         return 1;
     119             : }
     120             : 
     121           0 : static int button_install_check_event_source(Button *b) {
     122             :         int r;
     123           0 :         assert(b);
     124             : 
     125             :         /* Install a post handler, so that we keep rechecking as long as the lid is closed. */
     126             : 
     127           0 :         if (b->check_event_source)
     128           0 :                 return 0;
     129             : 
     130           0 :         r = sd_event_add_post(b->manager->event, &b->check_event_source, button_recheck, b);
     131           0 :         if (r < 0)
     132           0 :                 return r;
     133             : 
     134           0 :         return sd_event_source_set_priority(b->check_event_source, SD_EVENT_PRIORITY_IDLE+1);
     135             : }
     136             : 
     137           0 : static int button_dispatch(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
     138           0 :         Button *b = userdata;
     139             :         struct input_event ev;
     140             :         ssize_t l;
     141             : 
     142           0 :         assert(s);
     143           0 :         assert(fd == b->fd);
     144           0 :         assert(b);
     145             : 
     146           0 :         l = read(b->fd, &ev, sizeof(ev));
     147           0 :         if (l < 0)
     148           0 :                 return errno != EAGAIN ? -errno : 0;
     149           0 :         if ((size_t) l < sizeof(ev))
     150           0 :                 return -EIO;
     151             : 
     152           0 :         if (ev.type == EV_KEY && ev.value > 0) {
     153             : 
     154           0 :                 switch (ev.code) {
     155             : 
     156             :                 case KEY_POWER:
     157             :                 case KEY_POWER2:
     158           0 :                         log_struct(LOG_INFO,
     159             :                                    LOG_MESSAGE("Power key pressed."),
     160             :                                    LOG_MESSAGE_ID(SD_MESSAGE_POWER_KEY),
     161             :                                    NULL);
     162             : 
     163           0 :                         manager_handle_action(b->manager, INHIBIT_HANDLE_POWER_KEY, b->manager->handle_power_key, b->manager->power_key_ignore_inhibited, true);
     164           0 :                         break;
     165             : 
     166             :                 /* The kernel is a bit confused here:
     167             : 
     168             :                    KEY_SLEEP   = suspend-to-ram, which everybody else calls "suspend"
     169             :                    KEY_SUSPEND = suspend-to-disk, which everybody else calls "hibernate"
     170             :                 */
     171             : 
     172             :                 case KEY_SLEEP:
     173           0 :                         log_struct(LOG_INFO,
     174             :                                    LOG_MESSAGE("Suspend key pressed."),
     175             :                                    LOG_MESSAGE_ID(SD_MESSAGE_SUSPEND_KEY),
     176             :                                    NULL);
     177             : 
     178           0 :                         manager_handle_action(b->manager, INHIBIT_HANDLE_SUSPEND_KEY, b->manager->handle_suspend_key, b->manager->suspend_key_ignore_inhibited, true);
     179           0 :                         break;
     180             : 
     181             :                 case KEY_SUSPEND:
     182           0 :                         log_struct(LOG_INFO,
     183             :                                    LOG_MESSAGE("Hibernate key pressed."),
     184             :                                    LOG_MESSAGE_ID(SD_MESSAGE_HIBERNATE_KEY),
     185             :                                    NULL);
     186             : 
     187           0 :                         manager_handle_action(b->manager, INHIBIT_HANDLE_HIBERNATE_KEY, b->manager->handle_hibernate_key, b->manager->hibernate_key_ignore_inhibited, true);
     188           0 :                         break;
     189             :                 }
     190             : 
     191           0 :         } else if (ev.type == EV_SW && ev.value > 0) {
     192             : 
     193           0 :                 if (ev.code == SW_LID) {
     194           0 :                         log_struct(LOG_INFO,
     195             :                                    LOG_MESSAGE("Lid closed."),
     196             :                                    LOG_MESSAGE_ID(SD_MESSAGE_LID_CLOSED),
     197             :                                    NULL);
     198             : 
     199           0 :                         b->lid_closed = true;
     200           0 :                         button_lid_switch_handle_action(b->manager, true);
     201           0 :                         button_install_check_event_source(b);
     202             : 
     203           0 :                 } else if (ev.code == SW_DOCK) {
     204           0 :                         log_struct(LOG_INFO,
     205             :                                    LOG_MESSAGE("System docked."),
     206             :                                    LOG_MESSAGE_ID(SD_MESSAGE_SYSTEM_DOCKED),
     207             :                                    NULL);
     208             : 
     209           0 :                         b->docked = true;
     210             :                 }
     211             : 
     212           0 :         } else if (ev.type == EV_SW && ev.value == 0) {
     213             : 
     214           0 :                 if (ev.code == SW_LID) {
     215           0 :                         log_struct(LOG_INFO,
     216             :                                    LOG_MESSAGE("Lid opened."),
     217             :                                    LOG_MESSAGE_ID(SD_MESSAGE_LID_OPENED),
     218             :                                    NULL);
     219             : 
     220           0 :                         b->lid_closed = false;
     221           0 :                         b->check_event_source = sd_event_source_unref(b->check_event_source);
     222             : 
     223           0 :                 } else if (ev.code == SW_DOCK) {
     224           0 :                         log_struct(LOG_INFO,
     225             :                                    LOG_MESSAGE("System undocked."),
     226             :                                    LOG_MESSAGE_ID(SD_MESSAGE_SYSTEM_UNDOCKED),
     227             :                                    NULL);
     228             : 
     229           0 :                         b->docked = false;
     230             :                 }
     231             :         }
     232             : 
     233           0 :         return 0;
     234             : }
     235             : 
     236           0 : int button_open(Button *b) {
     237             :         char *p, name[256];
     238             :         int r;
     239             : 
     240           0 :         assert(b);
     241             : 
     242           0 :         if (b->fd >= 0) {
     243           0 :                 close(b->fd);
     244           0 :                 b->fd = -1;
     245             :         }
     246             : 
     247           0 :         p = strjoina("/dev/input/", b->name);
     248             : 
     249           0 :         b->fd = open(p, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
     250           0 :         if (b->fd < 0)
     251           0 :                 return log_warning_errno(errno, "Failed to open %s: %m", b->name);
     252             : 
     253           0 :         if (ioctl(b->fd, EVIOCGNAME(sizeof(name)), name) < 0) {
     254           0 :                 log_error_errno(errno, "Failed to get input name: %m");
     255           0 :                 r = -errno;
     256           0 :                 goto fail;
     257             :         }
     258             : 
     259           0 :         r = sd_event_add_io(b->manager->event, &b->io_event_source, b->fd, EPOLLIN, button_dispatch, b);
     260           0 :         if (r < 0) {
     261           0 :                 log_error_errno(r, "Failed to add button event: %m");
     262           0 :                 goto fail;
     263             :         }
     264             : 
     265           0 :         log_info("Watching system buttons on /dev/input/%s (%s)", b->name, name);
     266             : 
     267           0 :         return 0;
     268             : 
     269             : fail:
     270           0 :         close(b->fd);
     271           0 :         b->fd = -1;
     272           0 :         return r;
     273             : }
     274             : 
     275           0 : int button_check_switches(Button *b) {
     276           0 :         uint8_t switches[SW_MAX/8+1] = {};
     277           0 :         assert(b);
     278             : 
     279           0 :         if (b->fd < 0)
     280           0 :                 return -EINVAL;
     281             : 
     282           0 :         if (ioctl(b->fd, EVIOCGSW(sizeof(switches)), switches) < 0)
     283           0 :                 return -errno;
     284             : 
     285           0 :         b->lid_closed = (switches[SW_LID/8] >> (SW_LID % 8)) & 1;
     286           0 :         b->docked = (switches[SW_DOCK/8] >> (SW_DOCK % 8)) & 1;
     287             : 
     288           0 :         if (b->lid_closed)
     289           0 :                 button_install_check_event_source(b);
     290             : 
     291           0 :         return 0;
     292             : }

Generated by: LCOV version 1.11