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:inblock in ’
from test.rb:3:in open' from test.rb:3:in

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 C. 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:inblock in ’
from test.rb:3:in open' from test.rb:3:in

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

On Fri, Oct 11, 2013 at 8:51 AM, Michel D. [email protected]
wrote:

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

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

Felipe C. [email protected] wrote:

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

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

On Fri, Oct 11, 2013 at 5:28 PM, Eric W. [email protected]
wrote:

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

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 C version doesn’t do that SNDCTL_TMR_TIMEBASE or
SNDRV_TIMER_IOCTL_NEXT_DEVICE or TCGETS ioctl.

Felipe C. 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:inblock 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.

On Fri, Oct 11, 2013 at 8:12 PM, Matthew K. [email protected]
wrote:

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.

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

from test.rb:4:in `block in ’
Felipe C.

You might try replacing read with sysread.

-jh

Felipe C. 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.

Jonathan H. wrote:

test.rb:4:in `read’: Invalid argument - /dev/input/event4

You might try replacing read with sysread.

I did. Doesn’t make a difference.

On Oct 11, 2013, at 6:25 AM, Felipe C.
[email protected] wrote:

test.rb:4:in `read’: Invalid argument - /dev/input/event4 (Errno::EINVAL)
Felipe C.
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 C. [email protected] wrote:

test.rb:4:in `read’: Invalid argument - /dev/input/event4 (Errno::EINVAL)
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.

On Sat, Oct 12, 2013 at 4:08 PM, Eric W. [email protected]
wrote:

            char buf[16];

Bumping up the buf size in my C version to 64 succeeded, too.
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 1:07 PM, Tamara T. [email protected]
wrote:

What is going on? Anybody else can reproduce?


Felipe C.

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 C. [email protected] 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

On Sat, Oct 12, 2013 at 8:13 PM, Eric W. [email protected]
wrote:

Felipe C. [email protected] 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

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 5:45 PM, Felipe C.
[email protected] wrote:

end

What is going on? Anybody else can reproduce?


Felipe C.

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+.

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.

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs