summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--LICENSE20
-rw-r--r--README.md10
-rw-r--r--ioctl/__init__.py103
-rw-r--r--setup.cfg19
-rw-r--r--setup.py4
5 files changed, 156 insertions, 0 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..cd415b2
--- /dev/null
+++ b/LICENSE
@@ -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()