evcat.c revision 0a1beeb64207eaa88ab9236787b1cbc2f704ae14
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
/*
* Event Catenation
* The evcat tool catenates input events of all requested devices and prints
* them to standard-output. It's only meant for debugging of input-related
* problems.
*/
#include <assert.h>
#include <errno.h>
#include <getopt.h>
#include <libevdev/libevdev.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <systemd/sd-event.h>
#include <systemd/sd-login.h>
#include <termios.h>
#include <unistd.h>
#include <xkbcommon/xkbcommon.h>
#include "build.h"
#include "bus-util.h"
#include "event-util.h"
#include "idev.h"
#include "macro.h"
#include "sysview.h"
#include "term-internal.h"
#include "util.h"
struct Evcat {
char *session;
char *seat;
bool managed : 1;
};
if (!e)
return NULL;
free(e);
return NULL;
}
static bool is_managed(const char *session) {
unsigned int vtnr;
long mode;
int r;
/* Using logind's Controller API is highly fragile if there is already
* a session controller running. If it is registered as controller
* itself, TakeControl will simply fail. But if its a legacy controller
* that does not use logind's controller API, we must never register
* our own controller. Otherwise, we really mess up the VT. Therefore,
* only run in managed mode if there's no-one else. */
if (geteuid() == 0)
return false;
if (!isatty(1))
return false;
if (!session)
return false;
return false;
mode = 0;
return false;
return false;
return true;
}
int r;
if (!e)
return log_oom();
if (r < 0) {
log_error_errno(-r, "Cannot retrieve logind session: %m");
return r;
}
if (r < 0) {
log_error_errno(-r, "Cannot retrieve seat of logind session: %m");
return r;
}
r = sd_event_default(&e->event);
if (r < 0)
return r;
r = sd_bus_open_system(&e->bus);
if (r < 0)
return r;
if (r < 0)
return r;
if (r < 0)
return r;
if (r < 0)
return r;
if (r < 0)
return r;
r = sysview_context_new(&e->sysview,
e->event,
e->bus,
NULL);
if (r < 0)
return r;
if (r < 0)
return r;
*out = e;
e = NULL;
return 0;
}
char buf[128];
uint32_t i, c;
int cwidth;
"REPEAT");
/* Resync state */
/* Keycode that triggered the event */
/* Well-known name of the keycode */
/* Well-known modifiers */
/* Consumed modifiers */
/* Resolved symbols */
printf(" |");
for (i = 0; i < k->n_syms; ++i) {
buf[0] = 0;
if (is_locale_utf8()) {
c = k->codepoints[i];
if (c < 0x110000 && c > 0x20 && (c < 0x7f || c > 0x9f)) {
/* "%4lc" doesn't work well, so hard-code it */
cwidth = mk_wcwidth(c);
while (cwidth++ < 2)
printf(" ");
} else {
printf(" ");
}
}
}
printf("\n");
}
if (k->value != 1)
return false;
if (k->n_syms != 1)
return false;
return k->codepoints[0] == 'q';
}
case IDEV_EVENT_DEVICE_ADD:
break;
case IDEV_EVENT_DEVICE_REMOVE:
break;
case IDEV_EVENT_DEVICE_DATA:
case IDEV_DATA_KEYBOARD:
sd_event_exit(e->event, 0);
else
break;
}
break;
}
return 0;
}
sysview_device *d;
const char *name;
int r;
return 1;
break;
assert(!e->idev_session);
flags = 0;
if (e->managed)
r = idev_session_new(&e->idev_session,
e->idev,
name,
e);
if (r < 0) {
log_error_errno(-r, "Cannot create idev session: %m");
return r;
}
if (e->managed) {
if (r < 0) {
log_error_errno(-r, "Cannot request session control: %m");
return r;
}
}
break;
sd_event_exit(e->event, 0);
break;
type = sysview_device_get_type(d);
if (type == SYSVIEW_DEVICE_EVDEV) {
if (r < 0) {
log_error_errno(-r, "Cannot add evdev device to idev: %m");
return r;
}
}
break;
type = sysview_device_get_type(d);
if (type == SYSVIEW_DEVICE_EVDEV) {
if (r < 0) {
log_error_errno(-r, "Cannot remove evdev device from idev: %m");
return r;
}
}
break;
if (r < 0) {
log_error_errno(-r, "Cannot acquire session control: %m");
return r;
}
if (r < 0) {
log_error("Cannot set K_UNICODE on stdout: %m");
return -errno;
}
if (r < 0) {
log_error("Cannot set KD_TEXT on stdout: %m");
return -errno;
}
printf("\n");
break;
}
return 0;
}
int r;
assert(e);
log_warning("You run in unmanaged mode without being root. This is likely to produce no output..");
printf("evcat - Read and catenate events from selected input devices\n"
" Running on seat '%s' in user-session '%s'\n"
" Exit by pressing ^C or 'q'\n\n",
if (r < 0)
goto out;
if (r < 0) {
r = -errno;
goto out;
}
if (r < 0) {
r = -errno;
goto out;
}
r = sd_event_loop(e->event);
printf("exiting..\n");
out:
return r;
}
static int help(void) {
printf("%s [OPTIONS...]\n\n"
"Read and catenate events from selected input devices.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
return 0;
}
enum {
ARG_VERSION = 0x100,
};
{},
};
int c;
switch (c) {
case 'h':
help();
return 0;
case ARG_VERSION:
return 0;
case '?':
return -EINVAL;
default:
assert_not_reached("Unhandled option");
}
log_error("Too many arguments");
return -EINVAL;
}
return 1;
}
int r;
log_open();
if (!is_locale_utf8())
log_warning("Locale is not set to UTF-8. Codepoints will not be printed!");
if (r <= 0)
goto finish;
r = evcat_new(&e);
if (r < 0)
goto finish;
r = evcat_run(e);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}