In my Python (2.7.3) code, I'm trying to use an ioctl call, accepting a long int (64 bit) as an argument. I'm on a 64-bit system, so a 64-bit int is the same size as a pointer.
My problem is that Python doesn't seem to accept a 64-bit int as the argument for a fcntl.ioctl() call. It happily accepts a 32-bit int or a 64-bit pointer - but what I need is to pass a 64-bit int.
Here's my ioctl handler:
static long trivial_driver_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
long err = 0;
switch (cmd)
{
case 1234:
printk("=== (%u) Driver got arg %lx; arg<<32 is %lx\n", cmd, arg, arg<<32);
break;
case 5678:
printk("=== (%u) Driver got arg %lx\n", cmd, arg);
break;
default:
printk("=== OH NOES!!! %u %lu\n", cmd, arg);
err = -EINVAL;
}
return err;
}
In existing C code, I use the call like this:
static int trivial_ioctl_test(){
int ret;
int fd = open(DEV_NAME, O_RDWR);
unsigned long arg = 0xffff;
ret = ioctl(fd, 1234, arg); // ===(1234) Driver got arg ffff; arg<<32 is ffff00000000
arg = arg<<32;
ret = ioctl(fd, 5678, arg); // === (5678) Driver got arg ffff00000000
close(fd);
}
In python, I open the device file, and then I get the following results:
>>> from fcntl import ioctl
>>> import os
>>> fd = os.open (DEV_NAME, os.O_RDWR, 0666)
>>> ioctl(fd, 1234, 0xffff)
0
>>> arg = 0xffff<<32
>>> # Kernel log: === (1234) Driver got arg ffff; arg<<32 is ffff00000000
>>> # This demonstrates that ioctl() happily accepts a 32-bit int as an argument.
>>> import struct
>>> ioctl(fd, 5678, struct.pack("L",arg))
'\x00\x00\x00\x00\xff\xff\x00\x00'
>>> # Kernel log: === (5678) Driver got arg 7fff9eb1fcb0
>>> # This demonstrates that ioctl() happily accepts a 64-bit pointer as an argument.
>>> ioctl(fd, 5678, arg)
Traceback (most recent call last):
File "<pyshell#10>", line 1, in <module>
ioctl(fd, 5678, arg)
OverflowError: signed integer is greater than maximum
>>> # Kernel log: (no change - OverflowError is within python)
>>> # Oh no! Can't pass a 64-bit int!
>>>
Is there any way Python can pass my 64-bit argument to ioctl()?
Whether or not this is possible using Python's fcntl.ioctl()
will be system-dependent. Tracing through the source code, the error message is coming from the following test on line 658 of getargs.c
...
else if (ival > INT_MAX) {
PyErr_SetString(PyExc_OverflowError,
"signed integer is greater than maximum");
RETURN_ERR_OCCURRED;
}
...and on my system, /usr/include/limits.h
tells me...
# define INT_MAX 2147483647
...which is (presumably) (2 ** ((sizeof(int) * 8) - 1)) - 1
.
So, unless you're working on a system where sizeof(int)
is at least 8
, you'll have to call the underlying C function directly using the ctypes
module, but it's platform-specific.
Assuming Linux, something like this ought to work...
from ctypes import *
libc = CDLL('libc.so.6')
fd = os.open (DEV_NAME, os.O_RDWR, 0666)
value = c_uint64(0xffff<<32)
libc.ioctl(fd, 5678, value)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With