summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBartosz Golaszewski <bartosz.golaszewski@linaro.org>2024-12-10 13:32:43 +0100
committerKhem Raj <raj.khem@gmail.com>2024-12-10 13:43:54 -0800
commitae88d2ff59eb851d7badbe5ff8eb11ed7040aeb9 (patch)
tree7e3729f956c9999b75572b4a5ecb2a74bddaa688
parent06eacb769a9915b6eff2d5bf1957ef088ee74c1c (diff)
downloadmeta-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>
-rw-r--r--meta-filesystems/conf/layer.conf4
-rw-r--r--meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/gpiod-sysfs-proxy.init.in84
-rw-r--r--meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/gpiod-sysfs-proxy.service.in15
-rw-r--r--meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/run-gpio-sys.mount13
-rw-r--r--meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/run-ptest.in21
-rw-r--r--meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/sys-class.mount16
-rw-r--r--meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy_0.1.1.bb85
7 files changed, 238 insertions, 0 deletions
diff --git a/meta-filesystems/conf/layer.conf b/meta-filesystems/conf/layer.conf
index 8a0c831e2b..5323913d58 100644
--- a/meta-filesystems/conf/layer.conf
+++ b/meta-filesystems/conf/layer.conf
@@ -16,3 +16,7 @@ LAYERVERSION_filesystems-layer = "1"
16LAYERDEPENDS_filesystems-layer = "core openembedded-layer networking-layer" 16LAYERDEPENDS_filesystems-layer = "core openembedded-layer networking-layer"
17 17
18LAYERSERIES_COMPAT_filesystems-layer = "styhead walnascar" 18LAYERSERIES_COMPAT_filesystems-layer = "styhead walnascar"
19
20BBFILES_DYNAMIC += " \
21 meta-python:${LAYERDIR}/dynamic-layers/meta-python/recipes-*/*/*.bb \
22"
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
20PROG="/usr/bin/gpiod-sysfs-proxy"
21NAME="gpiod-sysfs-proxy"
22DESC="/sys/class/gpio compatibility layer"
23MOUNTPOINT="@mountpoint@"
24
25test -x $PROG || exit 0
26
27do_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
47do_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
62case "$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 ;;
82esac
83
84exit 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]
5Description=User-space, libgpiod-based compatibility layer for linux GPIO sysfs interface
6
7[Service]
8RuntimeDirectory=gpio
9Type=simple
10ExecStart=/usr/bin/gpiod-sysfs-proxy @mountpoint@ -f -o nonempty -o allow_other -o default_permissions -o entry_timeout=0
11ExecStop=/bin/umount @mountpoint@
12Restart=always
13
14[Install]
15WantedBy=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]
5Description=Remount of sysfs for gpiod-sysfs-proxy
6ConditionPathExists=!/sys/class/gpio
7
8[Mount]
9DirectoryMode=0700
10What=sysfs
11Where=/run/gpio/sys
12Type=sysfs
13Options=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
3ptestdir=$(dirname "$(readlink -f "$0")")
4testbin="gpio-sysfs-compat-tests"
5
6modprobe gpio-sim
7modprobe configfs
8
9mountpoint -q /sys/kernel/config
10if [ "$?" -ne "0" ]; then
11 mount -t configfs configfs /sys/kernel/config
12fi
13
14cd $ptestdir/tests
15
16./$testbin -v --gpio-class @mountpoint@ --chown-user gpio-test > ./$testbin.out 2>&1
17if [ $? -ne 0 ]; then
18 echo "FAIL: $testbin"
19else
20 echo "PASS: $testbin"
21fi
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]
5Description=Overlay on top of /sys/class adding the gpio class directory
6Before=gpiod-sysfs-proxy.service
7After=run-gpio-sys.mount
8ConditionPathExists=!/sys/class/gpio
9
10[Mount]
11RuntimeDirectory=gpio/class/gpio
12DirectoryMode=0755
13What=overlay
14Where=/sys/class
15Type=overlay
16Options=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 @@
1SUMMARY = "User-space, libgpiod-based compatibility layer for linux GPIO sysfs interface."
2
3LICENSE = "MIT"
4LIC_FILES_CHKSUM = "file://COPYING;md5=0dcf8b702b5c96178978c7223f64a73b"
5
6inherit systemd update-rc.d ptest pypi python_pep517 python_setuptools_build_meta useradd
7
8PYPI_PACKAGE = "gpiod_sysfs_proxy"
9
10SRC_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
18SRC_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.
25PACKAGECONFIG[sys-class-mount] = ""
26
27export MOUNTPOINT="${@bb.utils.contains('PACKAGECONFIG', 'sys-class-mount', '\/sys\/class\/gpio', '\/run\/gpio', d)}"
28
29do_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
52SYSTEMD_SERVICE:${PN} = "gpiod-sysfs-proxy.service"
53SYSTEMD_AUTO_ENABLE = "enable"
54
55INITSCRIPT_NAME = "gpiod-sysfs-proxy"
56INITSCRIPT_PARAMS = "start 20 2 3 4 5 . stop 20 0 1 6 ."
57
58FILES:${PN} += "/usr/lib/systemd/system"
59
60RDEPENDS:${PN} += " \
61 python3-fuse \
62 python3-gpiod \
63 python3-pyudev \
64"
65
66python __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
72do_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.
80USERADD_PACKAGES = "${PN}-ptest"
81GROUPADD_PARAM:${PN}-ptest = "--system gpio-test"
82USERADD_PARAM:${PN}-ptest = "--system -M -s /bin/nologin -g gpio-test gpio-test"
83
84RDEPENDS:${PN}-ptest += "kmod"
85RRECOMMENDS:${PN}-ptest += "kernel-module-gpio-sim kernel-module-configfs"