diff options
| author | Bartosz Golaszewski <bartosz.golaszewski@linaro.org> | 2024-12-10 13:32:43 +0100 |
|---|---|---|
| committer | Khem Raj <raj.khem@gmail.com> | 2024-12-10 13:43:54 -0800 |
| commit | ae88d2ff59eb851d7badbe5ff8eb11ed7040aeb9 (patch) | |
| tree | 7e3729f956c9999b75572b4a5ecb2a74bddaa688 /meta-filesystems/dynamic-layers/meta-python | |
| parent | 06eacb769a9915b6eff2d5bf1957ef088ee74c1c (diff) | |
| download | meta-openembedded-ae88d2ff59eb851d7badbe5ff8eb11ed7040aeb9.tar.gz | |
gpiod-sysfs-proxy: new recipe
Many users are reluctant to use libgpiod instead of the deprecated
/sys/class/gpio interface. The gpiod-sysfs-proxy project aims at making
the transition easier by implementing a compatibility layer in
user-space using FUSE and python3-gpiod. This way we can eat the cookie
by disabling the sysfs ABI and have the users have it too by sticking to
their existing scripts.
The project itself is a very simple setuptools-based python package but
the recipe is quite complex due to comprehensive distro integration.
By default we use /run/gpio as mountpoint. For full backward
compatibility with the kernel interface, the user must explicitly add
the 'sys-class-mount' switch to PACKAGECONFIG. We do this because,
depending on whether CONFIG_GPIO_SYSFS Kconfig option is enabled,
/sys/class/gpio will either be non-empty or not exist at all. In the
latter case, we need to somehow create the /sys/class/gpio and, since
user-space is not allowed to mkdir() inside sysfs, we use overlayfs for
that. As this is rather non-standard, we want the user to be aware of
this.
We support both systemd and sys V init managers.
We also provide a ptest package which uses an external
gpio-sysfs-compat-tests script.
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Signed-off-by: Khem Raj <raj.khem@gmail.com>
Diffstat (limited to 'meta-filesystems/dynamic-layers/meta-python')
6 files changed, 234 insertions, 0 deletions
diff --git a/meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/gpiod-sysfs-proxy.init.in b/meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/gpiod-sysfs-proxy.init.in new file mode 100644 index 0000000000..a9cf5e4075 --- /dev/null +++ b/meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/gpiod-sysfs-proxy.init.in | |||
| @@ -0,0 +1,84 @@ | |||
| 1 | #! /bin/sh | ||
| 2 | ### BEGIN INIT INFO | ||
| 3 | # Provides: gpiod-sysfs-proxy | ||
| 4 | # Required-Start: $remote_fs $syslog | ||
| 5 | # Required-Stop: $remote_fs $syslog | ||
| 6 | # Default-Start: 2 3 4 5 | ||
| 7 | # Default-Stop: 1 | ||
| 8 | # Short-Description: User-space, libgpiod-based compatibility layer for linux GPIO sysfs interface. | ||
| 9 | ### END INIT INFO | ||
| 10 | # | ||
| 11 | # -*- coding: utf-8 -*- | ||
| 12 | # Debian init.d script for gpiod-sysfs-proxy | ||
| 13 | # Copyright (c) 2024 Bartosz Golaszewski <bartosz.golaszewski@linaro.org> | ||
| 14 | |||
| 15 | # set -e | ||
| 16 | |||
| 17 | # Source function library. | ||
| 18 | . /etc/init.d/functions | ||
| 19 | |||
| 20 | PROG="/usr/bin/gpiod-sysfs-proxy" | ||
| 21 | NAME="gpiod-sysfs-proxy" | ||
| 22 | DESC="/sys/class/gpio compatibility layer" | ||
| 23 | MOUNTPOINT="@mountpoint@" | ||
| 24 | |||
| 25 | test -x $PROG || exit 0 | ||
| 26 | |||
| 27 | do_start() | ||
| 28 | { | ||
| 29 | echo -n "Starting $DESC: " | ||
| 30 | |||
| 31 | if [ "$MOUNTPOINT" = "/sys/class/gpio" ] && [ ! -e /sys/class/gpio ]; then | ||
| 32 | mkdir -p /run/gpio/sys /run/gpio/class/gpio /run/gpio/work | ||
| 33 | mount -t sysfs sysfs /run/gpio/sys -o nosuid,nodev,noexec | ||
| 34 | # Bail out if overlayfs is not available | ||
| 35 | set -e | ||
| 36 | mount -t overlay overlay /sys/class \ | ||
| 37 | -o upperdir=/run/gpio/class,lowerdir=/run/gpio/sys/class,workdir=/run/gpio/work,nosuid,nodev,noexec,relatime,ro | ||
| 38 | set +e | ||
| 39 | else | ||
| 40 | mkdir -p $MOUNTPOINT | ||
| 41 | fi | ||
| 42 | |||
| 43 | $PROG $MOUNTPOINT -o nonempty -o allow_other -o default_permissions -o entry_timeout=0 -f | logger -i $NAME & | ||
| 44 | echo "done" | ||
| 45 | } | ||
| 46 | |||
| 47 | do_stop() | ||
| 48 | { | ||
| 49 | echo -n "Stopping $DESC: " | ||
| 50 | |||
| 51 | umount $MOUNTPOINT | ||
| 52 | |||
| 53 | mountpoint -q /sys/class | ||
| 54 | if [ "$?" = "0" ]; then | ||
| 55 | umount /sys/class | ||
| 56 | umount /run/gpio/sys | ||
| 57 | rm -rf /run/gpio | ||
| 58 | fi | ||
| 59 | echo "done" | ||
| 60 | } | ||
| 61 | |||
| 62 | case "$1" in | ||
| 63 | start) | ||
| 64 | do_start | ||
| 65 | ;; | ||
| 66 | stop) | ||
| 67 | do_stop | ||
| 68 | ;; | ||
| 69 | status) | ||
| 70 | status $PROG | ||
| 71 | exit $? | ||
| 72 | ;; | ||
| 73 | restart) | ||
| 74 | do_stop | ||
| 75 | sleep 1 | ||
| 76 | do_start | ||
| 77 | ;; | ||
| 78 | *) | ||
| 79 | echo "Usage: /etc/init.d/$NAME {start|stop|status|restart}" >&2 | ||
| 80 | exit 1 | ||
| 81 | ;; | ||
| 82 | esac | ||
| 83 | |||
| 84 | exit 0 | ||
diff --git a/meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/gpiod-sysfs-proxy.service.in b/meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/gpiod-sysfs-proxy.service.in new file mode 100644 index 0000000000..313523268c --- /dev/null +++ b/meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/gpiod-sysfs-proxy.service.in | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | # SPDX-License-Identifier: CC0-1.0 | ||
| 2 | # SPDX-FileCopyrightText: 2024 Bartosz Golaszewski <bartosz.golaszewski@linaro.org> | ||
| 3 | |||
| 4 | [Unit] | ||
| 5 | Description=User-space, libgpiod-based compatibility layer for linux GPIO sysfs interface | ||
| 6 | |||
| 7 | [Service] | ||
| 8 | RuntimeDirectory=gpio | ||
| 9 | Type=simple | ||
| 10 | ExecStart=/usr/bin/gpiod-sysfs-proxy @mountpoint@ -f -o nonempty -o allow_other -o default_permissions -o entry_timeout=0 | ||
| 11 | ExecStop=/bin/umount @mountpoint@ | ||
| 12 | Restart=always | ||
| 13 | |||
| 14 | [Install] | ||
| 15 | WantedBy=multi-user.target | ||
diff --git a/meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/run-gpio-sys.mount b/meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/run-gpio-sys.mount new file mode 100644 index 0000000000..a924cb9b64 --- /dev/null +++ b/meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/run-gpio-sys.mount | |||
| @@ -0,0 +1,13 @@ | |||
| 1 | # SPDX-License-Identifier: CC0-1.0 | ||
| 2 | # SPDX-FileCopyrightText: 2024 Bartosz Golaszewski <bartosz.golaszewski@linaro.org> | ||
| 3 | |||
| 4 | [Unit] | ||
| 5 | Description=Remount of sysfs for gpiod-sysfs-proxy | ||
| 6 | ConditionPathExists=!/sys/class/gpio | ||
| 7 | |||
| 8 | [Mount] | ||
| 9 | DirectoryMode=0700 | ||
| 10 | What=sysfs | ||
| 11 | Where=/run/gpio/sys | ||
| 12 | Type=sysfs | ||
| 13 | Options=nosuid,nodev,noexec | ||
diff --git a/meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/run-ptest.in b/meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/run-ptest.in new file mode 100644 index 0000000000..aab3a5ce3e --- /dev/null +++ b/meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/run-ptest.in | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | |||
| 3 | ptestdir=$(dirname "$(readlink -f "$0")") | ||
| 4 | testbin="gpio-sysfs-compat-tests" | ||
| 5 | |||
| 6 | modprobe gpio-sim | ||
| 7 | modprobe configfs | ||
| 8 | |||
| 9 | mountpoint -q /sys/kernel/config | ||
| 10 | if [ "$?" -ne "0" ]; then | ||
| 11 | mount -t configfs configfs /sys/kernel/config | ||
| 12 | fi | ||
| 13 | |||
| 14 | cd $ptestdir/tests | ||
| 15 | |||
| 16 | ./$testbin -v --gpio-class @mountpoint@ --chown-user gpio-test > ./$testbin.out 2>&1 | ||
| 17 | if [ $? -ne 0 ]; then | ||
| 18 | echo "FAIL: $testbin" | ||
| 19 | else | ||
| 20 | echo "PASS: $testbin" | ||
| 21 | fi | ||
diff --git a/meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/sys-class.mount b/meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/sys-class.mount new file mode 100644 index 0000000000..e3e3ce8e74 --- /dev/null +++ b/meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/sys-class.mount | |||
| @@ -0,0 +1,16 @@ | |||
| 1 | # SPDX-License-Identifier: CC0-1.0 | ||
| 2 | # SPDX-FileCopyrightText: 2024 Bartosz Golaszewski <bartosz.golaszewski@linaro.org> | ||
| 3 | |||
| 4 | [Unit] | ||
| 5 | Description=Overlay on top of /sys/class adding the gpio class directory | ||
| 6 | Before=gpiod-sysfs-proxy.service | ||
| 7 | After=run-gpio-sys.mount | ||
| 8 | ConditionPathExists=!/sys/class/gpio | ||
| 9 | |||
| 10 | [Mount] | ||
| 11 | RuntimeDirectory=gpio/class/gpio | ||
| 12 | DirectoryMode=0755 | ||
| 13 | What=overlay | ||
| 14 | Where=/sys/class | ||
| 15 | Type=overlay | ||
| 16 | Options=upperdir=/run/gpio/class,lowerdir=/run/gpio/sys/class,workdir=/run/gpio/work,ro,nosuid,nodev,noexec,relatime | ||
diff --git a/meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy_0.1.1.bb b/meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy_0.1.1.bb new file mode 100644 index 0000000000..4d466d30f0 --- /dev/null +++ b/meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy_0.1.1.bb | |||
| @@ -0,0 +1,85 @@ | |||
| 1 | SUMMARY = "User-space, libgpiod-based compatibility layer for linux GPIO sysfs interface." | ||
| 2 | |||
| 3 | LICENSE = "MIT" | ||
| 4 | LIC_FILES_CHKSUM = "file://COPYING;md5=0dcf8b702b5c96178978c7223f64a73b" | ||
| 5 | |||
| 6 | inherit systemd update-rc.d ptest pypi python_pep517 python_setuptools_build_meta useradd | ||
| 7 | |||
| 8 | PYPI_PACKAGE = "gpiod_sysfs_proxy" | ||
| 9 | |||
| 10 | SRC_URI += " \ | ||
| 11 | file://gpiod-sysfs-proxy.service.in \ | ||
| 12 | file://run-gpio-sys.mount \ | ||
| 13 | file://sys-class.mount \ | ||
| 14 | file://gpiod-sysfs-proxy.init.in \ | ||
| 15 | file://run-ptest.in \ | ||
| 16 | " | ||
| 17 | |||
| 18 | SRC_URI[sha256sum] = "c7830cb6a2c01914df2bc0549aef2dcfcb955520d400f65b3b50fb7a6f77f1b4" | ||
| 19 | |||
| 20 | # For full backward compatibility with the kernel sysfs interface, this option | ||
| 21 | # must be selected. However, we don't make it the default as - with kernel sysfs | ||
| 22 | # disabled - it plays a silly game with /sys/class, where it mounts a read-only | ||
| 23 | # overlay containing the missing /sys/class/gpio directory. This is a rather | ||
| 24 | # non-standard behavior so make sure the user actually wants it. | ||
| 25 | PACKAGECONFIG[sys-class-mount] = "" | ||
| 26 | |||
| 27 | export MOUNTPOINT="${@bb.utils.contains('PACKAGECONFIG', 'sys-class-mount', '\/sys\/class\/gpio', '\/run\/gpio', d)}" | ||
| 28 | |||
| 29 | do_install:append() { | ||
| 30 | if ${@bb.utils.contains('DISTRO_FEATURES','systemd','true','false',d)}; then | ||
| 31 | install -d ${D}${systemd_system_unitdir} | ||
| 32 | install -m 0644 ${UNPACKDIR}/gpiod-sysfs-proxy.service.in ${D}${systemd_system_unitdir}/gpiod-sysfs-proxy.service | ||
| 33 | |||
| 34 | if ${@bb.utils.contains('PACKAGECONFIG', 'sys-class-mount', 'true', 'false', d)}; then | ||
| 35 | install -d ${D}${systemd_system_unitdir}/sysinit.target.wants/ | ||
| 36 | |||
| 37 | install -m 0644 ${UNPACKDIR}/run-gpio-sys.mount ${D}${systemd_system_unitdir}/run-gpio-sys.mount | ||
| 38 | install -m 0644 ${UNPACKDIR}/sys-class.mount ${D}${systemd_system_unitdir}/sys-class.mount | ||
| 39 | |||
| 40 | ln -sf ../run-gpio-sys.mount ${D}${systemd_system_unitdir}/sysinit.target.wants/run-gpio-sys.mount | ||
| 41 | ln -sf ../sys-class.mount ${D}${systemd_system_unitdir}/sysinit.target.wants/sys-class.mount | ||
| 42 | fi | ||
| 43 | |||
| 44 | sed -i "s/@mountpoint@/$MOUNTPOINT/g" ${D}${systemd_system_unitdir}/gpiod-sysfs-proxy.service | ||
| 45 | elif ${@bb.utils.contains('DISTRO_FEATURES', 'sysvinit', 'true', 'false', d)}; then | ||
| 46 | install -d ${D}${sysconfdir}/init.d | ||
| 47 | install -m 0755 ${UNPACKDIR}/gpiod-sysfs-proxy.init.in ${D}${sysconfdir}/init.d/gpiod-sysfs-proxy | ||
| 48 | sed -i "s/@mountpoint@/$MOUNTPOINT/g" ${D}${sysconfdir}/init.d/gpiod-sysfs-proxy | ||
| 49 | fi | ||
| 50 | } | ||
| 51 | |||
| 52 | SYSTEMD_SERVICE:${PN} = "gpiod-sysfs-proxy.service" | ||
| 53 | SYSTEMD_AUTO_ENABLE = "enable" | ||
| 54 | |||
| 55 | INITSCRIPT_NAME = "gpiod-sysfs-proxy" | ||
| 56 | INITSCRIPT_PARAMS = "start 20 2 3 4 5 . stop 20 0 1 6 ." | ||
| 57 | |||
| 58 | FILES:${PN} += "/usr/lib/systemd/system" | ||
| 59 | |||
| 60 | RDEPENDS:${PN} += " \ | ||
| 61 | python3-fuse \ | ||
| 62 | python3-gpiod \ | ||
| 63 | python3-pyudev \ | ||
| 64 | " | ||
| 65 | |||
| 66 | python __anonymous() { | ||
| 67 | if d.getVar("PTEST_ENABLED") == "1": | ||
| 68 | d.appendVar("SRC_URI", "git://github.com/brgl/gpio-sysfs-compat-tests;protocol=https;branch=main;destsuffix=tests;name=tests") | ||
| 69 | d.setVar("SRCREV_tests", "a3c9daa4650dd1e8d7fd8972db68d9c2c204263d") | ||
| 70 | } | ||
| 71 | |||
| 72 | do_install_ptest() { | ||
| 73 | install -d ${D}${PTEST_PATH}/tests/ | ||
| 74 | install -m 0755 ${UNPACKDIR}/run-ptest.in ${D}${PTEST_PATH}/run-ptest | ||
| 75 | sed -i "s/@mountpoint@/$MOUNTPOINT/g" ${D}${PTEST_PATH}/run-ptest | ||
| 76 | install -m 0755 ${UNPACKDIR}/tests/gpio-sysfs-compat-tests ${D}${PTEST_PATH}/tests/gpio-sysfs-compat-tests | ||
| 77 | } | ||
| 78 | |||
| 79 | # Test user is created for verifying chown() and chmod() operations. | ||
| 80 | USERADD_PACKAGES = "${PN}-ptest" | ||
| 81 | GROUPADD_PARAM:${PN}-ptest = "--system gpio-test" | ||
| 82 | USERADD_PARAM:${PN}-ptest = "--system -M -s /bin/nologin -g gpio-test gpio-test" | ||
| 83 | |||
| 84 | RDEPENDS:${PN}-ptest += "kmod" | ||
| 85 | RRECOMMENDS:${PN}-ptest += "kernel-module-gpio-sim kernel-module-configfs" | ||
