diff options
-rw-r--r-- | LICENSE | 20 | ||||
-rw-r--r-- | README.md | 10 | ||||
-rw-r--r-- | ioctl/__init__.py | 103 | ||||
-rw-r--r-- | setup.cfg | 19 | ||||
-rw-r--r-- | setup.py | 4 |
5 files changed, 156 insertions, 0 deletions
@@ -0,0 +1,20 @@ +Copyright © 2020 Filipe Laíns <filipe.lains@gmail.com> + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice (including the next +paragraph) shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..6550e6e --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# python-ioctl + +Pure python typed ioctl implementation + + +### Development + +We use [mypy](http://mypy-lang.org/) to run static checks in scripts, and +[pre-commit](https://pre-commit.com/) to run misc checks. Install the pre-commit +hook with `pre-commit install`. 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) diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..6b9ea38 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,19 @@ +[metadata] +name = ioctl +version = 0.1.0 +long_description = file: README.md +long_description_content_type = text/markdown +author = Filipe Laíns +author_email = lains@archlinux.org +license = MIT +license_file = LICENSE +classifiers = + License :: OSI Approved :: MIT License + Programming Language :: Python :: 3.6 + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 +url = https://github.com/FFY00/python-ioctl + +[options] +packages = find: +python_requires = >=3.6, <4 diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..b024da8 --- /dev/null +++ b/setup.py @@ -0,0 +1,4 @@ +from setuptools import setup + + +setup() |