[PATCH] evdev - relax checks when reopening devices

Peter Hutterer peter.hutterer at who-t.net
Tue Nov 3 20:49:53 PST 2009


On Mon, Nov 02, 2009 at 11:11:55PM -0800, Dmitry Torokhov wrote:
> Evdev is way too paranoid when checking whether it deals with the same
> device when switching consoles which causes people lose keyboards if
> they happen to adjust keymap after X starts. PLease consider applying
> the patch below.

Thanks for the patch Dmitry. I certainly agree with the principle but I do
have a few minor comments.

> From: Dmitry Torokhov <dmitry.torokhov at gmail.com>
> Subject: [PATCH] evdev - relax checks when reopening devices
> 
> When checking whether we are dealing with the same device as before
> when we try to reopen it evdev should not require exact match of
> entire keymap. Users should be allowed to adjust keymaps to better
> match their hardware even after X starts. However we don't expect
> changes in [BTN_MISC, KEY_OK) range since these codes are reserved for
> mice, joysticks, tablets and so forth, so we will limit the check to
> this range.
> 
> The same goes for absinfo - limits can change and it should not result
> in device being disabled.
> 
> Also check the length of the data returned by ioctl and don't try to
> compare more than we were given.
> 
> Signed-off-by: Dmitry Torokhov <dtor at mail.ru>
> ---
>  src/evdev.c |  126 +++++++++++++++++++++++++++++++++--------------------------
>  1 files changed, 71 insertions(+), 55 deletions(-)
> 
> diff --git a/src/evdev.c b/src/evdev.c
> index 0dff271..747f3b1 100644
> --- a/src/evdev.c
> +++ b/src/evdev.c
> @@ -1671,6 +1671,7 @@ static int
>  EvdevCacheCompare(InputInfoPtr pInfo, BOOL compare)
>  {
>      EvdevPtr pEvdev = pInfo->private;
> +    size_t len;
>      int i;
>  
>      char name[1024]                  = {0};
> @@ -1679,107 +1680,122 @@ EvdevCacheCompare(InputInfoPtr pInfo, BOOL compare)
>      unsigned long rel_bitmask[NLONGS(REL_CNT)] = {0};
>      unsigned long abs_bitmask[NLONGS(ABS_CNT)] = {0};
>      unsigned long led_bitmask[NLONGS(LED_CNT)] = {0};
> -    struct input_absinfo absinfo[ABS_CNT];
>  
> -    if (ioctl(pInfo->fd,
> -              EVIOCGNAME(sizeof(name) - 1), name) < 0) {
> +    if (ioctl(pInfo->fd, EVIOCGNAME(sizeof(name) - 1), name) < 0) {

this line is white-space only, no?

>          xf86Msg(X_ERROR, "ioctl EVIOCGNAME failed: %s\n", strerror(errno));
>          goto error;
>      }
>  
[...]
  
> -    if (ioctl(pInfo->fd,
> -              EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask) < 0) {
> -        xf86Msg(X_ERROR, "%s: ioctl EVIOCGBIT failed: %s\n", pInfo->name, strerror(errno));
> +    len = ioctl(pInfo->fd, EVIOCGBIT(EV_KEY, sizeof(key_bitmask)), key_bitmask);
> +    if (len < 0) {
> +        xf86Msg(X_ERROR, "%s: ioctl EVIOCGBIT failed: %s\n",
> +                pInfo->name, strerror(errno));
>          goto error;
>      }
>  
> -    if (compare && memcmp(pEvdev->key_bitmask, key_bitmask, sizeof(key_bitmask))) {
> -        xf86Msg(X_ERROR, "%s: device key_bitmask has changed\n", pInfo->name);
> -        goto error;
> +    if (compare) {
> +        /*
> +         * Keys are special as user can adjust keymap at any time (on
> +         * devices that support EVIOCSKEYCODE. However we do not expect
> +         * buttons reserved fir mice/tablets/digitizers and so on to

typo: "for"

> +         * appear/disappear so we will check only those in
> +         * [BTN_MISC, KEY_OK) range.
> +         */
> +        size_t start_word = BTN_MISC / LONG_BITS;
> +        size_t start_byte = start_word * sizeof(unsigned long);
> +        size_t end_word = KEY_OK / LONG_BITS;
> +        size_t end_byte = end_word * sizeof(unsigned long);
> +
> +        if (len >= start_byte &&
> +            memcmp(&pEvdev->key_bitmask[start_word], &key_bitmask[start_word],
> +                   min(len, end_byte) - start_byte + 1)) {
> +            xf86Msg(X_ERROR, "%s: device key_bitmask has changed\n", pInfo->name);
> +            goto error;
> +        }
>      }
>  
> -    if (ioctl(pInfo->fd,
> -              EVIOCGBIT(EV_LED, sizeof(led_bitmask)), led_bitmask) < 0) {
> -        xf86Msg(X_ERROR, "%s: ioctl EVIOCGBIT failed: %s\n", pInfo->name, strerror(errno));
> +    /* Copy the data so we have reasonably up-to-date info */
> +    memcpy(pEvdev->key_bitmask, key_bitmask, len);

I think we should move this whole keyinfo bit below the absinfo stuff
before. Otherwise there is a narrow case where the key info is updated but
the compare still then still fail because something else has changed.

Other than that, I'm happy with the patch. Eric - have you managed to test
this patch yet?

Cheers,
  Peter

> +
> +    len = ioctl(pInfo->fd, EVIOCGBIT(EV_LED, sizeof(led_bitmask)), led_bitmask);
> +    if (len < 0) {
> +        xf86Msg(X_ERROR, "%s: ioctl EVIOCGBIT failed: %s\n",
> +                pInfo->name, strerror(errno));
>          goto error;
>      }
>  
> -    if (compare && memcmp(pEvdev->led_bitmask, led_bitmask, sizeof(led_bitmask))) {
> +    if (!compare) {
> +        memcpy(pEvdev->led_bitmask, led_bitmask, len);
> +    } else if (memcmp(pEvdev->led_bitmask, led_bitmask, len)) {
>          xf86Msg(X_ERROR, "%s: device led_bitmask has changed\n", pInfo->name);
>          goto error;
>      }

> -    memset(absinfo, 0, sizeof(absinfo));
> -
> -    for (i = ABS_X; i <= ABS_MAX; i++)
> -    {
> -        if (TestBit(i, abs_bitmask))
> -        {
> -            if (ioctl(pInfo->fd, EVIOCGABS(i), &absinfo[i]) < 0) {
> -                xf86Msg(X_ERROR, "%s: ioctl EVIOCGABS failed: %s\n", pInfo->name, strerror(errno));
> +    /*
> +     * Do not try to validate absinfo data since it is not expected
> +     * to be static, always refresh it in evdev structure.
> +     */
> +    for (i = ABS_X; i <= ABS_MAX; i++) {
> +        if (TestBit(i, abs_bitmask)) {
> +            len = ioctl(pInfo->fd, EVIOCGABS(i), &pEvdev->absinfo[i]);
> +            if (len < 0) {
> +                xf86Msg(X_ERROR, "%s: ioctl EVIOCGABSi(%d) failed: %s\n",
> +                        pInfo->name, i, strerror(errno));
>                  goto error;
>              }
> -            /* ignore current position (value) in comparison (bug #19819) */
> -            absinfo[i].value = pEvdev->absinfo[i].value;
>          }
>      }
>  
> -    if (compare && memcmp(pEvdev->absinfo, absinfo, sizeof(absinfo))) {
> -        xf86Msg(X_ERROR, "%s: device absinfo has changed\n", pInfo->name);
> -        goto error;
> -    }
> -
> -    /* cache info */
> -    if (!compare)
> -    {
> -        strcpy(pEvdev->name, name);
> -        memcpy(pEvdev->bitmask, bitmask, sizeof(bitmask));
> -        memcpy(pEvdev->key_bitmask, key_bitmask, sizeof(key_bitmask));
> -        memcpy(pEvdev->rel_bitmask, rel_bitmask, sizeof(rel_bitmask));
> -        memcpy(pEvdev->abs_bitmask, abs_bitmask, sizeof(abs_bitmask));
> -        memcpy(pEvdev->led_bitmask, led_bitmask, sizeof(led_bitmask));
> -        memcpy(pEvdev->absinfo, absinfo, sizeof(absinfo));
> -    }
> -
>      return Success;
>  
>  error:




More information about the xorg mailing list