-1

When trying to read input_events from /dev/input/event16 I noticed that the size of the buffer I'm reading into may cause an exception. Here is the code I wrote:

    public static void main(String[] args) throws IOException{
        FileInputStream is = new FileInputStream("/dev/input/event16");
        byte[] three_bytes = new byte[3];
        byte[] twentyfour_bytes = new byte[24];
        is.read(three_bytes); // fails
        is.read(twentyfour_bytes); // does not fail

    }

My initial experiments suggest that the buffer needs capacity for at least one full input_event struct. But I could not find out why.

The problem is the line is.read(three_bytes); causes the follwoing exception:

Exception in thread "main" java.io.IOException: Invalid argument
        at java.base/java.io.FileInputStream.readBytes(Native Method)
        at java.base/java.io.FileInputStream.read(FileInputStream.java:249)
        at main.Test.main(Test.java:11)

I would like to figure out why the line is.read(three_bytes); throws the exception while is.read(twentyfour_bytes); reads the data as expected

13
  • I'm not sure if I understand you correctly. Do you want to programmatically get the size of /dev/input/event16? Commented Jun 8, 2021 at 8:49
  • No, I try to read the content of the file Commented Jun 8, 2021 at 8:55
  • It's still not clear to me what you are going to find out. It seems you can read the file with a 24 bytes array, why not just use the larger array? Commented Jun 8, 2021 at 9:03
  • I am curious why I need the larger array. Commented Jun 8, 2021 at 9:20
  • 1
    Read this: stackoverflow.com/questions/39380993/… Commented Jun 14, 2021 at 7:51

1 Answer 1

2
+50

I would like to figure out why the line is.read(three_bytes); throws the exception while is.read(twentyfour_bytes); reads the data as expected.

For a start, /dev/input/event16 is not a regular file. It is a device file, and device files often don't behave like regular files.

In this case, the /dev/input/event* device files are for reading events from input devices. When you perform a read syscall on them, they will return one or more complete events. These are binary data whose format is given by the following C struct:

struct input_event {    
    struct timeval time;    
    unsigned short type;
    unsigned short code;
    unsigned int value; 
};

The size of that struct is (presumably) 24 bytes on a typical 64bit Linux system, though.

My initial experiments suggest that the buffer needs capacity for at least one full input_event struct. But I could not find out why.

The behavior of the event devices is documented in Linux Input drivers v1.0, section 5. It states that a read will always give a whole number of input_event structs.

It follows that the read syscall provides a buffer that is less than sizeof(input_event), the kernel cannot return anything. Apparently, this causes the read syscall to fail with errno value EINVAL. (IMO, this is a reasonable design choice, and consistent with the documented meaning of EINVAL.)


So, in Java, when you call read(three_bytes), that will map to a read syscall with a read size of 3 bytes which fails; see above. The syscall failure is signaled to the Java application by throw an IOException.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.