From: Bartosz Golaszewski <brgl@bgdev.pl>
To: Khem Raj <raj.khem@gmail.com>,
Bruce Ashfield <bruce.ashfield@gmail.com>,
openembedded-devel@lists.openembedded.org
Cc: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Subject: [meta-filesystems][PATCH] gpiod-sysfs-proxy: new recipe
Date: Tue, 10 Dec 2024 13:32:43 +0100 [thread overview]
Message-ID: <20241210123243.58809-1-brgl@bgdev.pl> (raw)
From: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
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>
---
meta-filesystems/conf/layer.conf | 4 +
.../gpiod-sysfs-proxy.init.in | 84 ++++++++++++++++++
.../gpiod-sysfs-proxy.service.in | 15 ++++
.../gpiod-sysfs-proxy/run-gpio-sys.mount | 13 +++
.../gpiod-sysfs-proxy/run-ptest.in | 21 +++++
.../gpiod-sysfs-proxy/sys-class.mount | 16 ++++
.../gpiod-sysfs-proxy_0.1.1.bb | 85 +++++++++++++++++++
7 files changed, 238 insertions(+)
create mode 100644 meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/gpiod-sysfs-proxy.init.in
create mode 100644 meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/gpiod-sysfs-proxy.service.in
create mode 100644 meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/run-gpio-sys.mount
create mode 100644 meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/run-ptest.in
create mode 100644 meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/sys-class.mount
create mode 100644 meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy_0.1.1.bb
diff --git a/meta-filesystems/conf/layer.conf b/meta-filesystems/conf/layer.conf
index 8a0c831e2..5323913d5 100644
--- a/meta-filesystems/conf/layer.conf
+++ b/meta-filesystems/conf/layer.conf
@@ -16,3 +16,7 @@ LAYERVERSION_filesystems-layer = "1"
LAYERDEPENDS_filesystems-layer = "core openembedded-layer networking-layer"
LAYERSERIES_COMPAT_filesystems-layer = "styhead walnascar"
+
+BBFILES_DYNAMIC += " \
+ meta-python:${LAYERDIR}/dynamic-layers/meta-python/recipes-*/*/*.bb \
+"
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 000000000..a9cf5e407
--- /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 @@
+#! /bin/sh
+### BEGIN INIT INFO
+# Provides: gpiod-sysfs-proxy
+# Required-Start: $remote_fs $syslog
+# Required-Stop: $remote_fs $syslog
+# Default-Start: 2 3 4 5
+# Default-Stop: 1
+# Short-Description: User-space, libgpiod-based compatibility layer for linux GPIO sysfs interface.
+### END INIT INFO
+#
+# -*- coding: utf-8 -*-
+# Debian init.d script for gpiod-sysfs-proxy
+# Copyright (c) 2024 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+# set -e
+
+# Source function library.
+. /etc/init.d/functions
+
+PROG="/usr/bin/gpiod-sysfs-proxy"
+NAME="gpiod-sysfs-proxy"
+DESC="/sys/class/gpio compatibility layer"
+MOUNTPOINT="@mountpoint@"
+
+test -x $PROG || exit 0
+
+do_start()
+{
+ echo -n "Starting $DESC: "
+
+ if [ "$MOUNTPOINT" = "/sys/class/gpio" ] && [ ! -e /sys/class/gpio ]; then
+ mkdir -p /run/gpio/sys /run/gpio/class/gpio /run/gpio/work
+ mount -t sysfs sysfs /run/gpio/sys -o nosuid,nodev,noexec
+ # Bail out if overlayfs is not available
+ set -e
+ mount -t overlay overlay /sys/class \
+-o upperdir=/run/gpio/class,lowerdir=/run/gpio/sys/class,workdir=/run/gpio/work,nosuid,nodev,noexec,relatime,ro
+ set +e
+ else
+ mkdir -p $MOUNTPOINT
+ fi
+
+ $PROG $MOUNTPOINT -o nonempty -o allow_other -o default_permissions -o entry_timeout=0 -f | logger -i $NAME &
+ echo "done"
+}
+
+do_stop()
+{
+ echo -n "Stopping $DESC: "
+
+ umount $MOUNTPOINT
+
+ mountpoint -q /sys/class
+ if [ "$?" = "0" ]; then
+ umount /sys/class
+ umount /run/gpio/sys
+ rm -rf /run/gpio
+ fi
+ echo "done"
+}
+
+case "$1" in
+ start)
+ do_start
+ ;;
+ stop)
+ do_stop
+ ;;
+ status)
+ status $PROG
+ exit $?
+ ;;
+ restart)
+ do_stop
+ sleep 1
+ do_start
+ ;;
+ *)
+ echo "Usage: /etc/init.d/$NAME {start|stop|status|restart}" >&2
+ exit 1
+ ;;
+esac
+
+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 000000000..313523268
--- /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 @@
+# SPDX-License-Identifier: CC0-1.0
+# SPDX-FileCopyrightText: 2024 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+[Unit]
+Description=User-space, libgpiod-based compatibility layer for linux GPIO sysfs interface
+
+[Service]
+RuntimeDirectory=gpio
+Type=simple
+ExecStart=/usr/bin/gpiod-sysfs-proxy @mountpoint@ -f -o nonempty -o allow_other -o default_permissions -o entry_timeout=0
+ExecStop=/bin/umount @mountpoint@
+Restart=always
+
+[Install]
+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 000000000..a924cb9b6
--- /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 @@
+# SPDX-License-Identifier: CC0-1.0
+# SPDX-FileCopyrightText: 2024 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+[Unit]
+Description=Remount of sysfs for gpiod-sysfs-proxy
+ConditionPathExists=!/sys/class/gpio
+
+[Mount]
+DirectoryMode=0700
+What=sysfs
+Where=/run/gpio/sys
+Type=sysfs
+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 000000000..aab3a5ce3
--- /dev/null
+++ b/meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/run-ptest.in
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+ptestdir=$(dirname "$(readlink -f "$0")")
+testbin="gpio-sysfs-compat-tests"
+
+modprobe gpio-sim
+modprobe configfs
+
+mountpoint -q /sys/kernel/config
+if [ "$?" -ne "0" ]; then
+ mount -t configfs configfs /sys/kernel/config
+fi
+
+cd $ptestdir/tests
+
+./$testbin -v --gpio-class @mountpoint@ --chown-user gpio-test > ./$testbin.out 2>&1
+if [ $? -ne 0 ]; then
+ echo "FAIL: $testbin"
+else
+ echo "PASS: $testbin"
+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 000000000..e3e3ce8e7
--- /dev/null
+++ b/meta-filesystems/dynamic-layers/meta-python/recipes-support/gpiod-sysfs-proxy/gpiod-sysfs-proxy/sys-class.mount
@@ -0,0 +1,16 @@
+# SPDX-License-Identifier: CC0-1.0
+# SPDX-FileCopyrightText: 2024 Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
+
+[Unit]
+Description=Overlay on top of /sys/class adding the gpio class directory
+Before=gpiod-sysfs-proxy.service
+After=run-gpio-sys.mount
+ConditionPathExists=!/sys/class/gpio
+
+[Mount]
+RuntimeDirectory=gpio/class/gpio
+DirectoryMode=0755
+What=overlay
+Where=/sys/class
+Type=overlay
+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 000000000..4d466d30f
--- /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 @@
+SUMMARY = "User-space, libgpiod-based compatibility layer for linux GPIO sysfs interface."
+
+LICENSE = "MIT"
+LIC_FILES_CHKSUM = "file://COPYING;md5=0dcf8b702b5c96178978c7223f64a73b"
+
+inherit systemd update-rc.d ptest pypi python_pep517 python_setuptools_build_meta useradd
+
+PYPI_PACKAGE = "gpiod_sysfs_proxy"
+
+SRC_URI += " \
+ file://gpiod-sysfs-proxy.service.in \
+ file://run-gpio-sys.mount \
+ file://sys-class.mount \
+ file://gpiod-sysfs-proxy.init.in \
+ file://run-ptest.in \
+"
+
+SRC_URI[sha256sum] = "c7830cb6a2c01914df2bc0549aef2dcfcb955520d400f65b3b50fb7a6f77f1b4"
+
+# For full backward compatibility with the kernel sysfs interface, this option
+# must be selected. However, we don't make it the default as - with kernel sysfs
+# disabled - it plays a silly game with /sys/class, where it mounts a read-only
+# overlay containing the missing /sys/class/gpio directory. This is a rather
+# non-standard behavior so make sure the user actually wants it.
+PACKAGECONFIG[sys-class-mount] = ""
+
+export MOUNTPOINT="${@bb.utils.contains('PACKAGECONFIG', 'sys-class-mount', '\/sys\/class\/gpio', '\/run\/gpio', d)}"
+
+do_install:append() {
+ if ${@bb.utils.contains('DISTRO_FEATURES','systemd','true','false',d)}; then
+ install -d ${D}${systemd_system_unitdir}
+ install -m 0644 ${UNPACKDIR}/gpiod-sysfs-proxy.service.in ${D}${systemd_system_unitdir}/gpiod-sysfs-proxy.service
+
+ if ${@bb.utils.contains('PACKAGECONFIG', 'sys-class-mount', 'true', 'false', d)}; then
+ install -d ${D}${systemd_system_unitdir}/sysinit.target.wants/
+
+ install -m 0644 ${UNPACKDIR}/run-gpio-sys.mount ${D}${systemd_system_unitdir}/run-gpio-sys.mount
+ install -m 0644 ${UNPACKDIR}/sys-class.mount ${D}${systemd_system_unitdir}/sys-class.mount
+
+ ln -sf ../run-gpio-sys.mount ${D}${systemd_system_unitdir}/sysinit.target.wants/run-gpio-sys.mount
+ ln -sf ../sys-class.mount ${D}${systemd_system_unitdir}/sysinit.target.wants/sys-class.mount
+ fi
+
+ sed -i "s/@mountpoint@/$MOUNTPOINT/g" ${D}${systemd_system_unitdir}/gpiod-sysfs-proxy.service
+ elif ${@bb.utils.contains('DISTRO_FEATURES', 'sysvinit', 'true', 'false', d)}; then
+ install -d ${D}${sysconfdir}/init.d
+ install -m 0755 ${UNPACKDIR}/gpiod-sysfs-proxy.init.in ${D}${sysconfdir}/init.d/gpiod-sysfs-proxy
+ sed -i "s/@mountpoint@/$MOUNTPOINT/g" ${D}${sysconfdir}/init.d/gpiod-sysfs-proxy
+ fi
+}
+
+SYSTEMD_SERVICE:${PN} = "gpiod-sysfs-proxy.service"
+SYSTEMD_AUTO_ENABLE = "enable"
+
+INITSCRIPT_NAME = "gpiod-sysfs-proxy"
+INITSCRIPT_PARAMS = "start 20 2 3 4 5 . stop 20 0 1 6 ."
+
+FILES:${PN} += "/usr/lib/systemd/system"
+
+RDEPENDS:${PN} += " \
+ python3-fuse \
+ python3-gpiod \
+ python3-pyudev \
+"
+
+python __anonymous() {
+ if d.getVar("PTEST_ENABLED") == "1":
+ d.appendVar("SRC_URI", "git://github.com/brgl/gpio-sysfs-compat-tests;protocol=https;branch=main;destsuffix=tests;name=tests")
+ d.setVar("SRCREV_tests", "a3c9daa4650dd1e8d7fd8972db68d9c2c204263d")
+}
+
+do_install_ptest() {
+ install -d ${D}${PTEST_PATH}/tests/
+ install -m 0755 ${UNPACKDIR}/run-ptest.in ${D}${PTEST_PATH}/run-ptest
+ sed -i "s/@mountpoint@/$MOUNTPOINT/g" ${D}${PTEST_PATH}/run-ptest
+ install -m 0755 ${UNPACKDIR}/tests/gpio-sysfs-compat-tests ${D}${PTEST_PATH}/tests/gpio-sysfs-compat-tests
+}
+
+# Test user is created for verifying chown() and chmod() operations.
+USERADD_PACKAGES = "${PN}-ptest"
+GROUPADD_PARAM:${PN}-ptest = "--system gpio-test"
+USERADD_PARAM:${PN}-ptest = "--system -M -s /bin/nologin -g gpio-test gpio-test"
+
+RDEPENDS:${PN}-ptest += "kmod"
+RRECOMMENDS:${PN}-ptest += "kernel-module-gpio-sim kernel-module-configfs"
--
2.45.2
reply other threads:[~2024-12-10 12:32 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20241210123243.58809-1-brgl@bgdev.pl \
--to=brgl@bgdev.pl \
--cc=bartosz.golaszewski@linaro.org \
--cc=bruce.ashfield@gmail.com \
--cc=openembedded-devel@lists.openembedded.org \
--cc=raj.khem@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.