Problem reading /dev/input in Linux

Hi,

I'm trying to use a simple script in Linux:

File.open('/dev/input/event4', 'r') do |f|
  p f.read(16)
end

But I'm getting this:

test.rb:4:in `read': Invalid argument - /dev/input/event4 (Errno::EINVAL)
from test.rb:4:in `block in <main>'
from test.rb:3:in `open'
from test.rb:3:in `<main>'

Doing exactly the same in C works just fine, plus I have rw
permissions to everyone on that file.

What is going on? Anybody else can reproduce?

···

--
Felipe Contreras

Felipe Contreras wrote in post #1124259:

Hi,

I'm trying to use a simple script in Linux:

File.open('/dev/input/event4', 'r') do |f|
  p f.read(16)
end

But I'm getting this:

test.rb:4:in `read': Invalid argument - /dev/input/event4
(Errno::EINVAL)
from test.rb:4:in `block in <main>'
from test.rb:3:in `open'
from test.rb:3:in `<main>'

Doing exactly the same in C works just fine, plus I have rw
permissions to everyone on that file.

What is going on? Anybody else can reproduce?

Just a wild guess. Is /dev/input/event4 a File ? Did you try IO.open ?
_md

···

--
Posted via http://www.ruby-forum.com/\.

strace both versions and compare the differences between the relevant
syscalls

···

Felipe Contreras <felipe.contreras@gmail.com> wrote:

Hi,

I'm trying to use a simple script in Linux:

File.open('/dev/input/event4', 'r') do |f|
  p f.read(16)
end

But I'm getting this:

test.rb:4:in `read': Invalid argument - /dev/input/event4 (Errno::EINVAL)
from test.rb:4:in `block in <main>'
from test.rb:3:in `open'
from test.rb:3:in `<main>'

Doing exactly the same in C works just fine, plus I have rw
permissions to everyone on that file.

Felipe Contreras wrote in post #1124259:

File.open('/dev/input/event4', 'r') do |f|
  p f.read(16)
end

test.rb:4:in `read': Invalid argument - /dev/input/event4
(Errno::EINVAL)
from test.rb:4:in `block in <main>'
from test.rb:3:in `open'
from test.rb:3:in `<main>'

I'm assuming the f.read is line 4; which version of ruby are you using?
I've had a cursory look through the source on github (trunk/2.1 and
1.9.3), and can't see where that error would be raised in that fashion.

···

--
Posted via http://www.ruby-forum.com/\.

From another data point - I cannot reproduce this on linux kernel 2.6.32-5-686, ruby 2.0.0p247 (2013-06-27 revision 41674) [i686-linux]

···

On Oct 11, 2013, at 6:25 AM, Felipe Contreras <felipe.contreras@gmail.com> wrote:

Hi,

I'm trying to use a simple script in Linux:

File.open('/dev/input/event4', 'r') do |f|
p f.read(16)
end

But I'm getting this:

test.rb:4:in `read': Invalid argument - /dev/input/event4 (Errno::EINVAL)
from test.rb:4:in `block in <main>'
from test.rb:3:in `open'
from test.rb:3:in `<main>'

Doing exactly the same in C works just fine, plus I have rw
permissions to everyone on that file.

What is going on? Anybody else can reproduce?

--
Felipe Contreras

I don't know what you mean, '/dev/input/event4' is a string, IO.open
takes a file descriptor.

···

On Fri, Oct 11, 2013 at 8:51 AM, Michel Demazure <lists@ruby-forum.com> wrote:

Felipe Contreras wrote in post #1124259:

Hi,

I'm trying to use a simple script in Linux:

File.open('/dev/input/event4', 'r') do |f|
  p f.read(16)
end

But I'm getting this:

test.rb:4:in `read': Invalid argument - /dev/input/event4
(Errno::EINVAL)
from test.rb:4:in `block in <main>'
from test.rb:3:in `open'
from test.rb:3:in `<main>'

Doing exactly the same in C works just fine, plus I have rw
permissions to everyone on that file.

What is going on? Anybody else can reproduce?

Just a wild guess. Is /dev/input/event4 a File ? Did you try IO.open ?

--
Felipe Contreras

Well:

open("/dev/input/event4", O_RDONLY|O_CLOEXEC) = 7
fcntl(7, F_GETFD) = 0x1 (flags FD_CLOEXEC)
fstat(7, {st_mode=S_IFCHR|0640, st_rdev=makedev(13, 68), ...}) = 0
ioctl(7, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or
TCGETS, 0x7fff295c31b0) = -1 EINVAL (Invalid argument)
ppoll([{fd=7, events=POLLIN}], 1, NULL, NULL, 8) = 1 ([{fd=7, revents=POLLIN}])
read(7, 0x1bc5ae8, 16) = -1 EINVAL (Invalid argument)
close(7) = 0

My C version doesn't do that SNDCTL_TMR_TIMEBASE or
SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS ioctl.

···

On Fri, Oct 11, 2013 at 5:28 PM, Eric Wong <normalperson@yhbt.net> wrote:

Felipe Contreras <felipe.contreras@gmail.com> wrote:

Hi,

I'm trying to use a simple script in Linux:

File.open('/dev/input/event4', 'r') do |f|
  p f.read(16)
end

But I'm getting this:

test.rb:4:in `read': Invalid argument - /dev/input/event4 (Errno::EINVAL)
from test.rb:4:in `block in <main>'
from test.rb:3:in `open'
from test.rb:3:in `<main>'

Doing exactly the same in C works just fine, plus I have rw
permissions to everyone on that file.

strace both versions and compare the differences between the relevant
syscalls

--
Felipe Contreras

I tried both 2.0.0p247 and 1.9.3. I suppose -EINVAL comes from the kernel.

···

On Fri, Oct 11, 2013 at 8:12 PM, Matthew Kerwin <lists@ruby-forum.com> wrote:

Felipe Contreras wrote in post #1124259:

File.open('/dev/input/event4', 'r') do |f|
  p f.read(16)
end

test.rb:4:in `read': Invalid argument - /dev/input/event4
(Errno::EINVAL)
from test.rb:4:in `block in <main>'
from test.rb:3:in `open'
from test.rb:3:in `<main>'

I'm assuming the f.read is line 4; which version of ruby are you using?
I've had a cursory look through the source on github (trunk/2.1 and
1.9.3), and can't see where that error would be raised in that fashion.

--
Felipe Contreras

You might try replacing read with sysread.

-jh

···

On Sat, 12 Oct 2013 02:47:12 -0500, Felipe Contreras wrote:

On Fri, Oct 11, 2013 at 8:12 PM, Matthew Kerwin lists-fsXkhYbjdPsEEoCn2XhGlw@public.gmane.org wrote:

Felipe Contreras wrote in post #1124259:

File.open(‘/dev/input/event4’, ‘r’) do |f|
p f.read(16)
end

test.rb:4:in read': Invalid argument - /dev/input/event4 (Errno::EINVAL) from test.rb:4:in block in ’
from test.rb:3:in open' from test.rb:3:in

I’m assuming the f.read is line 4; which version of ruby are you using?
I’ve had a cursory look through the source on github (trunk/2.1 and
1.9.3), and can’t see where that error would be raised in that fashion.

I tried both 2.0.0p247 and 1.9.3. I suppose -EINVAL comes from the kernel.


Felipe Contreras

It's probably related to the version of the Linux kernel: 3.11.4+.

···

On Sat, Oct 12, 2013 at 1:07 PM, Tamara Temple <tamouse.lists@gmail.com> wrote:

On Oct 11, 2013, at 6:25 AM, Felipe Contreras <felipe.contreras@gmail.com> wrote:

Hi,

I'm trying to use a simple script in Linux:

File.open('/dev/input/event4', 'r') do |f|
p f.read(16)
end

But I'm getting this:

test.rb:4:in `read': Invalid argument - /dev/input/event4 (Errno::EINVAL)
from test.rb:4:in `block in <main>'
from test.rb:3:in `open'
from test.rb:3:in `<main>'

Doing exactly the same in C works just fine, plus I have rw
permissions to everyone on that file.

What is going on? Anybody else can reproduce?

--
Felipe Contreras

From another data point - I cannot reproduce this on linux kernel 2.6.32-5-686, ruby 2.0.0p247 (2013-06-27 revision 41674) [i686-linux]

--
Felipe Contreras

Jonathan Hudson wrote:

···

On Sat, 12 Oct 2013 02:47:12 -0500, Felipe Contreras wrote:

> On Fri, Oct 11, 2013 at 8:12 PM, Matthew Kerwin <lists@ruby-forum.com> wrote:
> > Felipe Contreras wrote in post #1124259:
> >>
> >> File.open('/dev/input/event4', 'r') do |f|
> >> p f.read(16)
> >> end
> >>
> >>
> >> test.rb:4:in `read': Invalid argument - /dev/input/event4
> >> (Errno::EINVAL)
> >> from test.rb:4:in `block in <main>'
> >> from test.rb:3:in `open'
> >> from test.rb:3:in `<main>'
> >
> > I'm assuming the f.read is line 4; which version of ruby are you using?
> > I've had a cursory look through the source on github (trunk/2.1 and
> > 1.9.3), and can't see where that error would be raised in that fashion.
>
> I tried both 2.0.0p247 and 1.9.3. I suppose -EINVAL comes from the kernel.

You might try replacing read with sysread.

I did. Doesn't make a difference.

--
Felipe Contreras

Felipe Contreras wrote in post #1124361:

open("/dev/input/event4", O_RDONLY|O_CLOEXEC) = 7
fcntl(7, F_GETFD) = 0x1 (flags FD_CLOEXEC)
fstat(7, {st_mode=S_IFCHR|0640, st_rdev=makedev(13, 68), ...}) = 0
ioctl(7, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or
TCGETS, 0x7fff295c31b0) = -1 EINVAL (Invalid argument)
ppoll([{fd=7, events=POLLIN}], 1, NULL, NULL, 8) = 1 ([{fd=7,
revents=POLLIN}])
read(7, 0x1bc5ae8, 16) = -1 EINVAL (Invalid argument)
close(7) = 0

My C version doesn't do that SNDCTL_TMR_TIMEBASE or
SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS ioctl.

SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS all have
the same value; strace just didn't know which name to give it (TCGETS).
I guess that's just ruby poking the new fd to see if it's a file or a
tty. (Perl does this, I assume ruby might too.)

It's odd that the failed ioctl() apparently sets errno to EINVAL instead
of ENOTTY; but in any case, ruby apparently doesn't care, because it
goes on to call ppoll() and read() anyway.

And fails.

My unsupported hunch tells me that ioctl()'s EINVAL is related to
read()'s, but I couldn't tell you why. Sorry.

···

--
Posted via http://www.ruby-forum.com/\.

My equivalent C version failed, too (event3 is my mouse, I don't
expect to read from my event4 (USB DAC)):

  #include <unistd.h>
  #include <sys/types.h>
  #include <sys/stat.h>
  #include <fcntl.h>
  int main(void)
  {
    int fd = open("/dev/input/event3", O_RDONLY|O_CLOEXEC);
    char buf[16];

    read(fd, buf, sizeof(buf));

    return 0;
  }

I used event3 to capture my mouse with a bigger buffer and it worked fine.

OK, reading the source of evdev_read() in drivers/input/evdev.c of the
Linux kernel, EINVAL seems to be caused by the buffer being too small:

  if (count != 0 && count < input_event_size())
    return -EINVAL;

I just used readpartial(64) since I didn't feel like calculating
input_event_size() to get the exact size:

  File.open('/dev/input/event3', 'r') do |f|
    p f.readpartial(64) # => 48 bytes
  end

Bumping up the buf size in my C version to 64 succeeded, too.

···

Felipe Contreras <felipe.contreras@gmail.com> wrote:

On Fri, Oct 11, 2013 at 5:28 PM, Eric Wong <normalperson@yhbt.net> wrote:
> Felipe Contreras <felipe.contreras@gmail.com> wrote:
>> I'm trying to use a simple script in Linux:
>>
>> File.open('/dev/input/event4', 'r') do |f|
>> p f.read(16)
>> end
>>
>> But I'm getting this:
>>
>> test.rb:4:in `read': Invalid argument - /dev/input/event4 (Errno::EINVAL)
>> from test.rb:4:in `block in <main>'
>> from test.rb:3:in `open'
>> from test.rb:3:in `<main>'
>>
>> Doing exactly the same in C works just fine, plus I have rw
>> permissions to everyone on that file.
>
> strace both versions and compare the differences between the relevant
> syscalls

Well:

open("/dev/input/event4", O_RDONLY|O_CLOEXEC) = 7
fcntl(7, F_GETFD) = 0x1 (flags FD_CLOEXEC)
fstat(7, {st_mode=S_IFCHR|0640, st_rdev=makedev(13, 68), ...}) = 0
ioctl(7, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or
TCGETS, 0x7fff295c31b0) = -1 EINVAL (Invalid argument)
ppoll([{fd=7, events=POLLIN}], 1, NULL, NULL, 8) = 1 ([{fd=7, revents=POLLIN}])
read(7, 0x1bc5ae8, 16) = -1 EINVAL (Invalid argument)
close(7) = 0

Or maybe it's because your system is 32 bits, so you can read 16, but
if you read less, you should get the same error.

···

On Sat, Oct 12, 2013 at 5:45 PM, Felipe Contreras <felipe.contreras@gmail.com> wrote:

On Sat, Oct 12, 2013 at 1:07 PM, Tamara Temple <tamouse.lists@gmail.com> wrote:

On Oct 11, 2013, at 6:25 AM, Felipe Contreras <felipe.contreras@gmail.com> wrote:

Hi,

I'm trying to use a simple script in Linux:

File.open('/dev/input/event4', 'r') do |f|
p f.read(16)
end

But I'm getting this:

test.rb:4:in `read': Invalid argument - /dev/input/event4 (Errno::EINVAL)
from test.rb:4:in `block in <main>'
from test.rb:3:in `open'
from test.rb:3:in `<main>'

Doing exactly the same in C works just fine, plus I have rw
permissions to everyone on that file.

What is going on? Anybody else can reproduce?

--
Felipe Contreras

From another data point - I cannot reproduce this on linux kernel 2.6.32-5-686, ruby 2.0.0p247 (2013-06-27 revision 41674) [i686-linux]

It's probably related to the version of the Linux kernel: 3.11.4+.

--
Felipe Contreras

That is weird. This code works:

FILE *f;
char *buf[16];
int r;
f = fopen("/dev/input/event4", "r");
r = fread(buf, 16, 1, f);
printf("r=%i\n", r);
fclose(f);

But this one doesn't:

int fd, r;
char *buf[16];
fd = open("/dev/input/event4", O_RDONLY);
r = read(fd, &ev, sizeof(ev));
printf("r=%i\n", r);
close(fd);

I don't know what's going on, but using the size of input even structs
(24) works everywhere.

Thanks!

···

On Sat, Oct 12, 2013 at 4:08 PM, Eric Wong <normalperson@yhbt.net> wrote:

Felipe Contreras <felipe.contreras@gmail.com> wrote:

On Fri, Oct 11, 2013 at 5:28 PM, Eric Wong <normalperson@yhbt.net> wrote:
> Felipe Contreras <felipe.contreras@gmail.com> wrote:
>> I'm trying to use a simple script in Linux:
>>
>> File.open('/dev/input/event4', 'r') do |f|
>> p f.read(16)
>> end
>>
>> But I'm getting this:
>>
>> test.rb:4:in `read': Invalid argument - /dev/input/event4 (Errno::EINVAL)
>> from test.rb:4:in `block in <main>'
>> from test.rb:3:in `open'
>> from test.rb:3:in `<main>'
>>
>> Doing exactly the same in C works just fine, plus I have rw
>> permissions to everyone on that file.
>
> strace both versions and compare the differences between the relevant
> syscalls

Well:

open("/dev/input/event4", O_RDONLY|O_CLOEXEC) = 7
fcntl(7, F_GETFD) = 0x1 (flags FD_CLOEXEC)
fstat(7, {st_mode=S_IFCHR|0640, st_rdev=makedev(13, 68), ...}) = 0
ioctl(7, SNDCTL_TMR_TIMEBASE or SNDRV_TIMER_IOCTL_NEXT_DEVICE or
TCGETS, 0x7fff295c31b0) = -1 EINVAL (Invalid argument)
ppoll([{fd=7, events=POLLIN}], 1, NULL, NULL, 8) = 1 ([{fd=7, revents=POLLIN}])
read(7, 0x1bc5ae8, 16) = -1 EINVAL (Invalid argument)
close(7) = 0

My equivalent C version failed, too (event3 is my mouse, I don't
expect to read from my event4 (USB DAC)):

        #include <unistd.h>
        #include <sys/types.h>
        #include <sys/stat.h>
        #include <fcntl.h>
        int main(void)
        {
                int fd = open("/dev/input/event3", O_RDONLY|O_CLOEXEC);
                char buf[16];

                read(fd, buf, sizeof(buf));

                return 0;
        }

I used event3 to capture my mouse with a bigger buffer and it worked fine.

OK, reading the source of evdev_read() in drivers/input/evdev.c of the
Linux kernel, EINVAL seems to be caused by the buffer being too small:

        if (count != 0 && count < input_event_size())
                return -EINVAL;

I just used readpartial(64) since I didn't feel like calculating
input_event_size() to get the exact size:

        File.open('/dev/input/event3', 'r') do |f|
          p f.readpartial(64) # => 48 bytes
        end

Bumping up the buf size in my C version to 64 succeeded, too.

--
Felipe Contreras

That is weird. This code works:

FILE *f;
char *buf[16];
int r;
f = fopen("/dev/input/event4", "r");
r = fread(buf, 16, 1, f);

I bet fread() issues a bigger read() syscall behind-the-scenes

···

Felipe Contreras <felipe.contreras@gmail.com> wrote:

printf("r=%i\n", r);
fclose(f);

Yeap:

read(3, "\345sZR\0\0\0\0\333\371\10\0\0\0\0\0\4\0\4\0\34\0\0\0\345sZR\0\0\0\0"...,
4096) = 72

···

On Sat, Oct 12, 2013 at 8:13 PM, Eric Wong <normalperson@yhbt.net> wrote:

Felipe Contreras <felipe.contreras@gmail.com> wrote:

That is weird. This code works:

FILE *f;
char *buf[16];
int r;
f = fopen("/dev/input/event4", "r");
r = fread(buf, 16, 1, f);

I bet fread() issues a bigger read() syscall behind-the-scenes

--
Felipe Contreras