diff options
Diffstat (limited to 'ioctl/__init__.py')
-rw-r--r-- | ioctl/__init__.py | 103 |
1 files changed, 103 insertions, 0 deletions
diff --git a/ioctl/__init__.py b/ioctl/__init__.py new file mode 100644 index 0000000..820a4ba --- /dev/null +++ b/ioctl/__init__.py @@ -0,0 +1,103 @@ +# SPDX-License-Identifier: MIT + +import array +import fcntl + +from typing import BinaryIO, Optional, Union + + +class IOCTL(object): + ''' + Constructs and performs ioctl(s) + See include/asm-generic/ioctl.h + ''' + NRBITS: int = 8 + TYPEBITS: int = 8 + + SIZEBITS: int = 14 + DIRBITS: int = 2 + + NRMASK: int = (1 << NRBITS) - 1 + TYPEMASK: int = (1 << TYPEBITS) - 1 + SIZEMASK: int = (1 << SIZEBITS) - 1 + DIRMASK: int = (1 << DIRBITS) - 1 + + NRSHIFT: int = 0 + TYPESHIFT: int = NRSHIFT + NRBITS + SIZESHIFT: int = TYPESHIFT + TYPEBITS + DIRSHIFT: int = SIZESHIFT + SIZEBITS + + class Direction: + NONE = 0 + WRITE = 1 + READ = 2 + + def __init__(self, dir: int, ty: str, nr: int, size: int = 0, bad: bool = False) -> None: + assert self.Direction.NONE <= dir <= self.Direction.READ + self.Direction.WRITE + + if dir == self.Direction.NONE: + size = 0 + elif not bad: + assert size, size <= self.SIZEMASK + + self.op = ( + (dir << self.DIRSHIFT) | + (ord(ty) << self.TYPESHIFT) | + (nr << self.NRSHIFT) | + (size << self.SIZESHIFT) + ) + + def perform(self, fd: BinaryIO, buf: Optional[Union[str, bytes, 'array.array[int]']] = None) -> bytearray: + ''' + Performs the ioctl + ''' + size = self.unpack_size(self.op) + + if buf is None: + buf = (size * '\x00').encode() + + return bytearray(fcntl.ioctl(fd, self.op, buf)) # type: ignore + + @classmethod + def unpack_dir(cls, nr: int) -> int: + return (nr >> cls.DIRSHIFT) & cls.DIRMASK + + @classmethod + def unpack_type(cls, nr: int) -> int: + return (nr >> cls.TYPESHIFT) & cls.TYPEMASK + + @classmethod + def unpack_nr(cls, nr: int) -> int: + return (nr >> cls.NRSHIFT) & cls.NRMASK + + @classmethod + def unpack_size(cls, nr: int) -> int: + return (nr >> cls.SIZESHIFT) & cls.SIZEMASK + + @classmethod + def IO(cls, ty: str, nr: int) -> 'IOCTL': + ''' + Constructor for no direction + ''' + return cls(cls.Direction.NONE, ty, nr) + + @classmethod + def IOR(cls, ty: str, nr: int, size: int) -> 'IOCTL': + ''' + Constructor for read + ''' + return cls(cls.Direction.READ, ty, nr, size) + + @classmethod + def IOW(cls, ty: str, nr: int, size: int) -> 'IOCTL': + ''' + Constructor for write + ''' + return cls(cls.Direction.WRITE, ty, nr, size) + + @classmethod + def IORW(cls, ty: str, nr: int, size: int) -> 'IOCTL': + ''' + Constructor for read & write + ''' + return cls(cls.Direction.READ | cls.Direction.WRITE, ty, nr, size) |