Complete Yocto mirror with license table for TQMa6UL (2038-compliance)

- 264 license table entries with exact download URLs (224/264 resolved)
- Complete sources/ directory with all BitBake recipes
- Build configuration: tqma6ul-multi-mba6ulx, spaetzle (musl)
- Full traceability for Softwarefreigabeantrag
- GCC 13.4.0, Linux 6.6.102, U-Boot 2023.04, musl 1.2.4
- License distribution: GPL-2.0 (24), MIT (23), GPL-2.0+ (18), BSD-3 (16)
This commit is contained in:
Siggi (OpenClaw Agent)
2026-03-01 20:58:18 +00:00
commit 16accb6b24
15086 changed files with 1292356 additions and 0 deletions

View File

@@ -0,0 +1,42 @@
From 50a48a7bd8d65a165ce2aac4ba0c1e02bded04aa Mon Sep 17 00:00:00 2001
From: Khem Raj <raj.khem@gmail.com>
Date: Sat, 30 Nov 2019 12:21:31 -0800
Subject: [PATCH] Fix build on 32bit arches with 64bit time_t
time element is deprecated on new input_event structure in kernel's
input.h [1]
[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit?id=152194fe9c3f
Signed-off-by: Khem Raj <raj.khem@gmail.com>
---
Upstream-Status: Pending
plugins/devinput.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/plugins/devinput.c b/plugins/devinput.c
index d4d733a..feb4a61 100644
--- a/plugins/devinput.c
+++ b/plugins/devinput.c
@@ -34,6 +34,11 @@
#include <linux/uinput.h>
#include <sys/stat.h>
+#ifndef input_event_sec
+#define input_event_sec time.tv_sec
+#define input_event_usec time.tv_usec
+#endif
+
#ifndef EV_SYN
/* previous name */
#define EV_SYN EV_RST
@@ -459,7 +464,7 @@ char* devinput_rec(struct ir_remote* remotes)
return 0;
}
- log_trace("time %ld.%06ld type %d code %d value %d", event.time.tv_sec, event.time.tv_usec, event.type,
+ log_trace("time %ld.%06ld type %d code %d value %d", event.input_event_sec, event.input_event_usec, event.type,
event.code, event.value);
value = (unsigned)event.value;

View File

@@ -0,0 +1,57 @@
From 5e3b74927b4fef03d91518d235e9e3ba8cd7ab2e Mon Sep 17 00:00:00 2001
From: Alexander Kanavin <alex@linutronix.de>
Date: Wed, 9 Nov 2022 20:49:41 +0100
Subject: [PATCH] Makefile.am: do not clobber PYTHONPATH from build environment
This environment variable has special significance for python,
and so lirc's variable has to be named something else.
Signed-off-by: Alexander Kanavin <alex@linutronix.de>
---
Upstream-Status: Pending
Makefile.am | 2 +-
pylint.mak | 2 +-
tools/Makefile.am | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 6718af1..fae423e 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -128,7 +128,7 @@ endif
pylint: .phony
$(MAKE) -C tools pylint
- -PYTHONPATH=$(PYTHONPATH) $(PYLINT) --rcfile=pylint.conf \
+ -PYTHONPATH=$(LIRCPYTHONPATH) $(PYLINT) --rcfile=pylint.conf \
--msg-template='$(pylint_template)' $(py_PYTHON)
pep8: $(py_PYTHON)
diff --git a/pylint.mak b/pylint.mak
index bf427ab..2692951 100644
--- a/pylint.mak
+++ b/pylint.mak
@@ -1,5 +1,5 @@
PYTHONPATH1 = $(abs_top_srcdir)/python-pkg/lirc:
PYTHONPATH2 = $(abs_top_srcdir)/python-pkg/lirc/lib/.libs
-PYTHONPATH = $(PYTHONPATH1):$(PYTHONPATH2)
+LIRCPYTHONPATH = $(PYTHONPATH1):$(PYTHONPATH2)
PYLINT = python3-pylint
pylint_template = {path}:{line}: [{msg_id}({symbol}), {obj}] {msg}
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 85d1fd0..96b17f8 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -142,7 +142,7 @@ force-pylint: .phony
pylint: .pylint-stamp
.pylint-stamp: $(py_sources)
- -PYTHONPATH=$(PYTHONPATH) $(PYLINT) --rcfile=../pylint.conf \
+ -PYTHONPATH=$(LIRCPYTHONPATH) $(PYLINT) --rcfile=../pylint.conf \
--msg-template='$(pylint_template)' $? && touch $@
.phony:
--
2.30.2

View File

@@ -0,0 +1,26 @@
From ca126a2832aaff0deef3ba7eaf411dd0dc43b068 Mon Sep 17 00:00:00 2001
From: Khem Raj <raj.khem@gmail.com>
Date: Thu, 16 Mar 2023 11:31:14 -0700
Subject: [PATCH] Unbolt ubuntu hack
This bites during cross compiling where the target is different than
build host and build host might be ubuntu but that does not matter in
cross compilation case. This fails builds when usrmerge feature is used
Upstream-Status: Inappropriate [ Cross-compile specific ]
Signed-off-by: Khem Raj <raj.khem@gmail.com>
---
configure.ac | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
--- a/configure.ac
+++ b/configure.ac
@@ -429,7 +429,7 @@ AC_CHECK_LIB([udev], [udev_device_new_fr
])
dnl Ubuntu's systemd pkg-config seems broken beyond repair. So:
-kernelversion=`cat /proc/version || echo "non-linux"`
+kernelversion="cross-compiled"
AS_CASE([$kernelversion],
[*Ubuntu*],[
AC_MSG_NOTICE([Hardwiring Ubuntu systemd setup])

View File

@@ -0,0 +1,44 @@
From e9e9027d7a324e1ce5e0cb06d4eb51847262a09d Mon Sep 17 00:00:00 2001
From: Khem Raj <raj.khem@gmail.com>
Date: Sun, 28 Aug 2022 12:26:52 -0700
Subject: [PATCH] mplay: Fix build with musl
pthread_t is an opaque type, therefore typecast it to avoid warnings on
musl
Fixes
mplay.c:200:12: error: incompatible integer to pointer conversion initializing 'pthread_t' (aka 'struct __pthread *') with an expression of type 'int' [-Wint-conversion]
| .tid = -1
| ^~
Upstream-Status: Submitted [https://sourceforge.net/p/lirc/git/merge-requests/47/]
Signed-off-by: Khem Raj <raj.khem@gmail.com>
---
plugins/mplay.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/plugins/mplay.c b/plugins/mplay.c
index d6d9619..5b9eb4b 100644
--- a/plugins/mplay.c
+++ b/plugins/mplay.c
@@ -197,7 +197,7 @@ static struct {
.latest_button = MPLAY_CODE_ERROR,
.fd = -1,
.pipefd = { -1, -1 },
- .tid = -1
+ .tid = (pthread_t)-1
};
/**
@@ -788,7 +788,7 @@ int mplayfamily_deinit(void)
return 0;
}
pthread_join(mplayfamily_local_data.tid, NULL);
- mplayfamily_local_data.tid = -1;
+ mplayfamily_local_data.tid = (pthread_t)-1;
}
if (mplayfamily_local_data.pipefd[0] != -1) {
close(mplayfamily_local_data.pipefd[0]);
--
2.37.2

View File

@@ -0,0 +1,32 @@
Upstream-Status: Pending
diff --git a/configure.ac b/configure.ac
index 58347d8..8c7fca2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -77,15 +77,10 @@ AC_TYPE_UINT64_T
dnl AC_TYPE_GETGROUPS seems broken on recent MacOS, so:
AC_MSG_CHECKING([Figure out if getgrouplist() needs gid_t or int])
-oldcflags="$CFLAGS"
-export CFLAGS=-Werror
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
#include <unistd.h>
-#include <grp.h>
- ]], [[
-gid_t groups[32]; int ngroups; const char* user = "root";
-getgrouplist(user, 1, groups, &ngroups);
- ]])],[
+int getgroups(int gidsetsize, gid_t grouplist[]);
+ ]], [[ ]])],[
AC_MSG_RESULT(gid_t)
AC_DEFINE(GETGROUPS_T,[gid_t])
],[
@@ -93,7 +88,6 @@ getgrouplist(user, 1, groups, &ngroups);
AC_DEFINE(GETGROUPS_T,[int])
]
)
-export CFLAGS="$oldcflags"
dnl Checks for library functions.
AC_CHECK_FUNCS(gethostname gettimeofday mkfifo select socket strdup \

View File

@@ -0,0 +1 @@
d /run/lirc 0755 root root -

View File

@@ -0,0 +1,24 @@
# These are the default options to lircd, if installed as
# /etc/lirc/lirc_options.conf. See the lircd(8) and lircmd(8)
# manpages for info on the different options.
[lircd]
nodaemon = False
permission = 666
driver = default
device = /dev/lirc0
output = /var/run/lirc/lircd
pidfile = /var/run/lirc/lircd.pid
plugindir = /usr/lib/lirc/plugins
allow-simulate = No
repeat-max = 600
#listen = [address:]port
#connect = host[:port]
#debug = 5
#uinput = ...
#release = ...
#logfile = ...
[lircmd]
uinput = False
nodeamon = False

View File

@@ -0,0 +1,315 @@
# contributed by angelo castello
#
# note: this config file has been deduced starting from the
# raw codes provided to run mode2 utility.
#
# brand: futarque
begin remote
name futarque
bits 8
flags SPACE_ENC|CONST_LENGTH
eps 30
aeps 100
header 8048 3898
one 555 1436
zero 555 439
gap 113123
ptrail 555
pre_data_bits 8
pre_data 0x54
pre 570 3890
begin codes
MUTE 0x70
EXIT 0xA8
POWER 0xF0
CHANNEL_UP 0x50
CHANNEL_DOWN 0xD0
VOLUME_UP 0x30
VOLUME_DOWN 0xB0
OK 0x98
FAVORITES 0x04
TEXT 0x68
EPG 0xC8
BACK 0x48
MENU 0x88
1 0x00
2 0x80
3 0x40
4 0xC0
5 0x20
6 0xA0
7 0x60
8 0xE0
9 0x10
0 0x90
PAUSE 0x84
INFO 0x38
RED 0xE8
GREEN 0x08
YELLOW 0x28
BLUE 0x78
UP 0xD8
DOWN 0xB8
REWIND 0x44
FASTFORWARD 0x24
PLAYPAUSE 0xC4
STOP 0x64
RECORD 0xA4
AUDIO 0xE4
TAPE 0x14
DVD 0x94
CAPITAL_A 0xF8
CAPITAL_B 0x54
end codes
end remote
# brand: STM PVR-1
begin remote
name stm_pvr_1
bits 16
flags SPACE_ENC|CONST_LENGTH
eps 30
aeps 150
header 9000 4500
one 572 1700
zero 572 572
ptrail 572
repeat 9000 2200
pre_data_bits 16
pre_data 0xFE
gap 100000
begin codes
POWER 0x00ff
FAVORITES 0x7887
MUTE 0x28d7
0 0x708F
1 0xc03f
2 0x40bf
3 0x807f
4 0xe01f
5 0x609f
6 0xa05f
7 0xd02f
8 0x50af
9 0x906f
INFO 0x38c7
SUBTITLE 0xe817
MENU 0x9867
EXIT 0x20df
EPG 0xa857
BACK 0x48b7
CURSOR_UP 0x58a7
CURSOR_DOWN 0xd827
CURSOR_LEFT 0x8877
CURSOR_RIGHT 0xb04f
OK 0x10ef
VOLUME_UP 0x22dd
VOLUME_DOWN 0x8a75
CHANNEL_UP 0x12ed
CHANNEL_DOWN 0x4ab5
TEXT 0xf00f
RADIO 0x926d
ZOOM 0x6897
AUDIO 0x08f7
RED 0x42bd
GREEN 0xa25d
YELLOW 0x827d
BLUE 0x02fd
CUSTOM0 0x52ad
CUSTOM1 0x30cf
PLAY 0x629d
PAUSE 0xb24d
PREVIOUS 0xc837
NEXT 0xf807
REWIND 0x32cd
FASTFORWARD 0x0af5
AUX 0x7a85
CUSTOM3 0xb847
PIP 0x3ac5
SWAP 0xba45
end codes
end remote
# brand: STM DTV-2
begin remote
name stm_dtv_2
flags SHIFT_ENC|CONST_LENGTH
bits 13
aeps 150
one 850 850
zero 850 850
plead 850
gap 67800
toggle_bit 2
begin codes
POWER 0x100C
FAVORITES 0x1015
AUX 0x1038
1 0x1001
2 0x1002
3 0x1003
4 0x1004
5 0x1005
6 0x1006
7 0x1007
8 0x1008
9 0x1009
PERIOD 0x1024
0 0x103E
BACK 0x1023
MENU 0x1016
INFO 0x100F
EPG 0x101E
EXIT 0x1018
CURSOR_UP 0x1017
CURSOR_DOWN 0x101D
CURSOR_LEFT 0x1019
CURSOR_RIGHT 0x101B
OK 0x101A
VOLUME_UP 0x1010
VOLUME_DOWN 0x1011
CHANNEL_UP 0x1020
CHANNEL_DOWN 0x1021
TEXT 0x102E
SUBTITLE 0x103C
FREEZE 0x1014
ZOOM 0x102B
RED 0x1028
GREEN 0x102A
YELLOW 0x102F
BLUE 0x1030
CUSTOM10 0x1022
INTERNET 0x1027
CUSTOM11 0x102C
AUDIO 0x1025
RECORD 0x102D
PLAYPAUSE 0x1029
STOP 0x1026
CUSTOM1 0x101C
MUTE 0x100d
CUSTOM12 0x101F
PIP 0x100B
SWAP 0x100E
end codes
end remote
# brand: Comcast
# model no. of remote control: XR2
# 32 bits for the pre-date (should be value 0x170F443E)
# width between pre_bits and data: 12900 microseconds
#
# 24 bits for the data (key code)
# To get key REPEAT, XOR 0x088 with KEY value
# There are 8 post bits (both should be zero)
#
# Gap between keys: 8100 microseconds
begin remote
name Xfinity-XR2
bits 24
flags XMP
eps 20
aeps 300
one 0 137
zero 250 710
ptrail 250
pre_data_bits 32
pre_data 0x170F443E
post_data_bits 8
post_data 0x0
pre 250 12921
gap 81698
toggle_bit_mask 0x0
begin codes
1 0x1E0001
1_repeat 0x168001
2 0x1D0002
2_repeat 0x158002
3 0x1C0003
3_repeat 0x148003
4 0x1B0004
4_repeat 0x138004
5 0x1A0005
5_repeat 0x128005
6 0x190006
6_repeat 0x118006
7 0x180007
7_repeat 0x108007
8 0x170008
8_repeat 0x1F8008
9 0x160009
9_repeat 0x1E8009
0 0x1F0000
0_repeat 0x178000
OK 0x180025
OK_repeat 0x108025
POWER 0x10000F
POWER_repeat 0x18800F
UP 0x1C0021
UP_repeat 0x148021
DOWN 0x1B0022
DOWN_repeat 0x138022
LEFT 0x1A0023
LEFT_repeat 0x128023
RIGHT 0x190024
RIGHT_repeat 0x118024
REWIND 0x190033
REWIND_repeat 0x118033
PLAY 0x1C0030
PLAY_repeat 0x148030
FASTFORWARD 0x180034
FASTFORWARD_repeat 0x108034
RECORD 0x170035
RECORD_repeat 0x1F8035
REPLAY 0x170053
REPLAY_repeat 0x1F8053
A 0x190060
A_repeat 0x118060
B 0x180061
B_repeat 0x108061
C 0x170062
C_repeat 0x1F8062
D 0x160063
D_repeat 0x1E8063
PAGE_UP 0x150028
PAGE_UP_repeat 0x1D8028
PAGE_DOWN 0x140029
PAGE_DOWN_repeat 0x1C8029
GUIDE 0x160027
GUIDE_repeat 0x1E8027
MENU 0x1D0020
MENU_repeat 0x158020
EXIT 0x13002A
EXIT_repeat 0x1B802A
INFO 0x170026
INFO_repeat 0x1F8026
LAST 0x190051
LAST_repeat 0x118051
VOLUME_UP 0x15000A
VOLUME_UP_repeat 0x1D800A
CHANNEL_UP 0x12000D
CHANNEL_UP_repeat 0x1A800D
VOLUME_DOWN 0x14000B
VOLUME_DOWN_repeat 0x1C800B
CHANNEL_DOWN 0x11000E
CHANNEL_DOWN_repeat 0x19800E
MUTE 0x13000C
MUTE_repeat 0x1B800D
end codes
end remote

View File

@@ -0,0 +1,40 @@
#! /bin/sh
#
# This is an init script for Familiar
# Copy it to /etc/init.d/lircd and type
# > update-rc.d lircd defaults 20
#
test -f /usr/sbin/lircd || exit 0
test -f /etc/lircd.conf || exit 0
case "$1" in
start)
echo -n "Starting lirc daemon: lircd"
start-stop-daemon --start --quiet --exec /usr/sbin/lircd -- --device=/dev/lirc0
echo "."
;;
stop)
echo -n "Stopping lirc daemon: lircd"
start-stop-daemon --stop --quiet --exec /usr/sbin/lircd
echo "."
;;
reload|force-reload)
start-stop-daemon --stop --quiet --signal 1 --exec /usr/sbin/lircd
;;
restart)
echo -n "Stopping lirc daemon: lircd"
start-stop-daemon --stop --quiet --exec /usr/sbin/lircd
sleep 1
echo -n "Starting lirc daemon: lircd"
start-stop-daemon --start --quiet --exec /usr/sbin/lircd -- --device=/dev/lirc0
echo "."
;;
*)
echo "Usage: /etc/init.d/lircd {start|stop|reload|restart|force-reload}"
exit 1
esac
exit 0

View File

@@ -0,0 +1,20 @@
[Unit]
Description=LIRC Infrared Signal Decoder
After=network.target
[Service]
Type=forking
EnvironmentFile=/etc/lirc/lircd.conf
PIDFile=/run/lirc/lircd.pid
ExecStartPre=/bin/mkdir -p /run/lirc
ExecStartPre=/bin/rm -f /dev/lircd
ExecStartPre=/bin/rm -f /run/lirc/lircd
ExecStartPre=/bin/ln -s /run/lirc/lircd /dev/lircd
ExecStart=/usr/sbin/lircd --pidfile=/run/lirc/lircd.pid --device=/dev/lirc0
ExecStopPost=/bin/rm -f /dev/lircd
ExecStopPost=/bin/rm -fR /run/lirc
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,37 @@
#! /bin/sh
#
# This is an init script for Familiar
# Copy it to /etc/init.d/lircexecd and type
# > update-rc.d lircexecd defaults 20
# It must be started after lircd (and it does alphabetically :-)
# irexec reads /etc/lircrc by default
test -f /usr/bin/irexec || exit 0
test -f /etc/lircrc || exit 0
case "$1" in
start)
echo -n "Starting lircexec daemon: irexec"
start-stop-daemon --start --quiet --exec /usr/bin/irexec -- --daemon
echo "."
;;
stop)
echo -n "Stopping lircexec daemon: irexec"
start-stop-daemon --stop --quiet --exec /usr/bin/irexec
echo "."
;;
restart|force-restart)
echo -n "Stopping lircexec daemon: irexec"
start-stop-daemon --stop --quiet --exec /usr/bin/irexec
sleep 1
echo -n "Starting lircexec daemon: irexec"
start-stop-daemon --start --quiet --exec /usr/bin/irexec -- --daemon
echo "."
;;
*)
echo "Usage: /etc/init.d/lircexec {start|stop|reload|restart|force-restart}"
exit 1
esac
exit 0

View File

@@ -0,0 +1,115 @@
DESCRIPTION = "LIRC is a package that allows you to decode and send infra-red signals of many commonly used remote controls."
DESCRIPTION:append:lirc = " This package contains the lirc daemon, libraries and tools."
DESCRIPTION:append:lirc-exec = " This package contains a daemon that runs programs on IR signals."
DESCRIPTION:append:lirc-remotes = " This package contains some config files for remotes."
DESCRIPTION:append:lirc-nslu2example = " This package contains a working config for RC5 remotes and a modified NSLU2."
HOMEPAGE = "http://www.lirc.org"
SECTION = "console/network"
LICENSE = "GPL-2.0-only"
DEPENDS = "libxslt-native alsa-lib libftdi libusb1 libusb-compat jack portaudio-v19 python3-pyyaml python3-setuptools-native"
LIC_FILES_CHKSUM = "file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263"
SRC_URI = "http://prdownloads.sourceforge.net/lirc/lirc-${PV}.tar.bz2 \
file://0001-Fix-build-on-32bit-arches-with-64bit-time_t.patch \
file://fix_build_errors.patch \
file://0001-mplay-Fix-build-with-musl.patch \
file://lircd.service \
file://lircd.init \
file://lircexec.init \
file://lircd.conf \
file://lirc_options.conf \
file://lirc.tmpfiles \
file://0001-Makefile.am-do-not-clobber-PYTHONPATH-from-build-env.patch \
file://0001-Unbolt-ubuntu-hack.patch \
"
SRC_URI[sha256sum] = "3d44ec8274881cf262f160805641f0827ffcc20ade0d85e7e6f3b90e0d3d222a"
SYSTEMD_PACKAGES = "lirc lirc-exec"
SYSTEMD_SERVICE:${PN} = "lircd.service lircmd.service lircd-setup.service lircd-uinput.service"
SYSTEMD_SERVICE:${PN}-exec = "irexec.service"
SYSTEMD_AUTO_ENABLE:lirc = "enable"
SYSTEMD_AUTO_ENABLE:lirc-exec = "enable"
inherit autotools pkgconfig systemd python3native setuptools3-base
PACKAGECONFIG[systemd] = "--with-systemdsystemunitdir=${systemd_unitdir}/system/,--without-systemdsystemunitdir,systemd"
PACKAGECONFIG[x11] = "--with-x,--with-x=no,libx11,"
PACKAGECONFIG ?= " \
${@bb.utils.contains('DISTRO_FEATURES', 'systemd', ' systemd', '', d)} \
${@bb.utils.contains('DISTRO_FEATURES', 'x11', ' x11', '', d)} \
"
CACHED_CONFIGUREVARS = "HAVE_WORKING_POLL=yes SH_PATH=/bin/sh"
#EXTRA_OEMAKE = 'SUBDIRS="lib daemons tools"'
# Ensure python-pkg/VERSION exists
do_configure:append() {
cp ${S}/VERSION ${S}/python-pkg/
}
# Create PYTHON_TARBALL which LIRC needs for install-nodist_pkgdataDATA
do_install:prepend() {
rm -rf ${S}/python-pkg/dist/
mkdir ${S}/python-pkg/dist/
tar --exclude='${S}/python-pkg/*' -czf ${S}/python-pkg/dist/${BP}.tar.gz ${S}
}
# In code, path to python is a variable that is replaced with path to native version of it
# during the configure stage, e.g ../recipe-sysroot-native/usr/bin/python3-native/python3.
# Replace it with #!/usr/bin/env python3
do_install:append() {
sed -i '1c#!/usr/bin/env python3' ${D}${bindir}/lirc-setup \
${D}${PYTHON_SITEPACKAGES_DIR}/lirc-setup/lirc-setup \
${D}${bindir}/irtext2udp \
${D}${bindir}/lirc-init-db \
${D}${bindir}/irdb-get \
${D}${bindir}/pronto2lirc \
${D}${sbindir}/lircd-setup
install -m 0755 -d ${D}${sysconfdir}
install -m 0755 -d ${D}${sysconfdir}/lirc
install -m 0644 ${WORKDIR}/lircd.conf ${D}${sysconfdir}/lirc/
install -m 0644 ${WORKDIR}/lirc_options.conf ${D}${sysconfdir}/lirc/
if ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'true', 'false', d)}; then
install -m 0755 -d ${D}${systemd_unitdir}/system ${D}${libdir}/tmpfiles.d
install -m 0644 ${WORKDIR}/lircd.service ${D}${systemd_unitdir}/system/
install -m 0755 ${WORKDIR}/lircexec.init ${D}${systemd_unitdir}/system/
install -m 0644 ${WORKDIR}/lirc.tmpfiles ${D}${libdir}/tmpfiles.d/lirc.conf
else
rm -rf ${D}/lib
fi
rm -rf ${D}${libdir}/lirc/plugins/*.la
rmdir ${D}/var/run/lirc ${D}/var/run
chown -R root:root ${D}${datadir}/lirc/contrib
}
PACKAGES =+ "${PN}-contrib ${PN}-exec ${PN}-plugins ${PN}-python"
RDEPENDS:${PN} = "bash python3"
RDEPENDS:${PN}-exec = "${PN}"
RDEPENDS:${PN}-python = "python3-shell python3-pyyaml python3-datetime python3-netclient python3-stringold"
RRECOMMENDS:${PN} = "${PN}-exec ${PN}-plugins"
FILES:${PN}-plugins = "${libdir}/lirc/plugins/*.so ${datadir}/lirc/configs"
FILES:${PN}-contrib = "${datadir}/lirc/contrib"
FILES:${PN}-exec = "${bindir}/irexec ${sysconfdir}/lircexec ${systemd_unitdir}/system/irexec.service"
FILES:${PN} += "${systemd_unitdir}/system/lircexec.init"
FILES:${PN} += "${systemd_unitdir}/system/lircd.service"
FILES:${PN} += "${systemd_unitdir}/system/lircd.socket"
FILES:${PN} += "${libdir}/tmpfiles.d/lirc.conf"
FILES:${PN}-dbg += "${libdir}/lirc/plugins/.debug"
FILES:${PN}-python += "${bindir}/irdb-get ${bindir}/irtext2udp ${bindir}/lircd-setup ${bindir}/pronto2lirc ${PYTHON_SITEPACKAGES_DIR}"
INITSCRIPT_PACKAGES = "lirc lirc-exec"
INITSCRIPT_NAME:lirc-exec = "lircexec"
INITSCRIPT_PARAMS:lirc-exec = "defaults 21"
# this is for distributions that don't use udev
pkg_postinst:${PN}:append() {
if [ ! -c $D/dev/lirc -a ! -f /sbin/udevd ]; then mknod $D/dev/lirc c 61 0; fi
}
SECURITY_CFLAGS = "${SECURITY_NO_PIE_CFLAGS}"

View File

@@ -0,0 +1,32 @@
From 0ea11f520a8b4453e60eaf0679b9feb757024422 Mon Sep 17 00:00:00 2001
From: Zang Ruochen <zangrc.fnst@cn.fujitsu.com>
Date: Fri, 25 Dec 2020 11:41:43 +0900
Subject: [PATCH] don't fail if GLOB_BRACE is not defined
Upstream-Status: Pending
Signed-off-by: Zang Ruochen <zangrc.fnst@cn.fujitsu.com>
---
src/util.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/util.c b/src/util.c
index 36eb896a..ee13ec44 100644
--- a/src/util.c
+++ b/src/util.c
@@ -35,6 +35,12 @@
#include "names.h"
#include "yaml-helpers.h"
+/* Don't fail if the standard library
+ * doesn't provide brace expansion */
+#ifndef GLOB_BRACE
+#define GLOB_BRACE 0
+#endif
+
GHashTable*
wifi_frequency_24;
--
2.25.1

View File

@@ -0,0 +1,58 @@
From d3aa30f5cd7ba375e006a755752acbcfcd619452 Mon Sep 17 00:00:00 2001
From: Yi Zhao <yi.zhao@windriver.com>
Date: Wed, 6 Mar 2024 19:27:15 +0800
Subject: [PATCH] meson.build: drop unnecessary build dependencies
The pytest and pycoverage are required by meson test but not for
building. Mark them as 'required: false' to get rid of unnecessary
build dependencies.
Upstream-Status: Inappropriate [oe specific]
Signed-off-by: Yi Zhao <yi.zhao@windriver.com>
---
meson.build | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/meson.build b/meson.build
index 9556836a..30f33fe2 100644
--- a/meson.build
+++ b/meson.build
@@ -25,8 +25,8 @@ bash_completions_dir = completions.get_variable(pkgconfig: 'completionsdir', def
# Order: Fedora/Mageia/openSUSE || Debian/Ubuntu
pyflakes = find_program('pyflakes-3', 'pyflakes3', required: false)
pycodestyle = find_program('pycodestyle-3', 'pycodestyle', 'pep8', required: false)
-pytest = find_program('pytest-3', 'pytest3') # also requires the pytest-cov plugin
-pycoverage = find_program('coverage-3', 'python3-coverage')
+pytest = find_program('pytest-3', 'pytest3', required: false) # also requires the pytest-cov plugin
+pycoverage = find_program('coverage-3', 'python3-coverage', required: false)
pandoc = find_program('pandoc', required: false)
find = find_program('find')
@@ -75,6 +75,7 @@ if get_option('unit_testing')
endif
#FIXME: exclude doc/env/
+if pyflakes.found() and pycodestyle.found()
test('linting',
pyflakes,
timeout: 100,
@@ -91,7 +92,9 @@ test('legacy-tests',
find_program('tests/cli_legacy.py'),
timeout: 600,
env: test_env)
+endif
#TODO: split out dbus tests into own test() instance, to run in parallel
+if pycoverage.found()
test('unit-tests',
pycoverage,
args: ['run', '-a', '-m', 'pytest', '-s', '-v', '--cov-append', meson.current_source_dir()],
@@ -143,4 +146,5 @@ if get_option('b_coverage')
priority: -99, # run last
is_parallel: false)
endif
+endif
--
2.25.1

View File

@@ -0,0 +1,47 @@
From 6e3dd61bf90a7ca8c36c5b95943cbff7c1ad3c2d Mon Sep 17 00:00:00 2001
From: Yi Zhao <yi.zhao@windriver.com>
Date: Wed, 6 Mar 2024 16:12:31 +0800
Subject: [PATCH] networkd.c: define scope specific to case statement
Per [1], define a scope specific to case statement to fix build with
clang.
Fixes:
../git/src/networkd.c:544:13: error: expected expression
544 | gchar* first = g_strcmp0(def->id, def->veth_peer_link->id) < 0 ? def->id : def->veth_peer_link->id;
| ^
../git/src/networkd.c:545:17: error: use of undeclared identifier 'first'
545 | if (first != def->id) {
| ^
[1] https://stackoverflow.com/questions/92396/why-cant-variables-be-declared-in-a-switch-statement
Upstream-Status: Pending
Signed-off-by: Yi Zhao <yi.zhao@windriver.com>
---
src/networkd.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/networkd.c b/src/networkd.c
index 25121c48..5eb9c0fe 100644
--- a/src/networkd.c
+++ b/src/networkd.c
@@ -541,12 +541,14 @@ write_netdev_file(const NetplanNetDefinition* def, const char* rootdir, const ch
* and, if the selected name is the name of the netdef being written, we generate
* the .netdev file. Otherwise we skip the netdef.
*/
+ {
gchar* first = g_strcmp0(def->id, def->veth_peer_link->id) < 0 ? def->id : def->veth_peer_link->id;
if (first != def->id) {
g_string_free(s, TRUE);
return;
}
g_string_append_printf(s, "Kind=veth\n\n[Peer]\nName=%s\n", def->veth_peer_link->id);
+ }
break;
case NETPLAN_DEF_TYPE_TUNNEL:
--
2.25.1

View File

@@ -0,0 +1,29 @@
From 668ee79f39614ad758edd44c42b8b0eff57877cf Mon Sep 17 00:00:00 2001
From: Alexander Kanavin <alex@linutronix.de>
Date: Sun, 3 Oct 2021 21:52:16 +0200
Subject: [PATCH] meson.build: do not use -Werror
Upstream-Status: Inappropriate [oe specific]
Signed-off-by: Alexander Kanavin <alex@linutronix.de>
Signed-off-by: Yi Zhao <yi.zhao@windriver.com>
---
meson.build | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/meson.build b/meson.build
index 30f33fe2..0b214795 100644
--- a/meson.build
+++ b/meson.build
@@ -4,7 +4,7 @@ project('netplan', 'c',
default_options: [
'c_std=c99',
'warning_level=2',
- 'werror=true',
+ 'werror=false',
],
meson_version: '>= 0.61.0',
)
--
2.25.1

View File

@@ -0,0 +1,452 @@
From 9d9a67b00b18708ce190b806686065a6c7b73527 Mon Sep 17 00:00:00 2001
From: Danilo Egea Gondolfo <danilogondolfo@gmail.com>
Date: Wed, 22 May 2024 15:44:16 +0100
Subject: [PATCH] libnetplan: use more restrictive file permissions
A new util.c:_netplan_g_string_free_to_file_with_permissions() was added
and accepts the owner, group and file mode as arguments. When these
properties can't be set, when the generator is called by a non-root user
for example, it will not hard-fail. This function is called by unit
tests where we can't set the owner to a privileged account for example.
When generating backend files, use more restrictive permissions:
networkd related files will be owned by root:systemd-network and have
mode 0640.
service unit files will be owned by root:root and have mode 0640.
udevd files will be owned by root:root with mode 0640.
wpa_supplicant and Network Manager files will continue with the existing
permissions.
Autopkgtests will check if the permissions are set as expected when
calling the generator.
CVE: CVE-2022-4968
Upstream-Status: Backport [https://github.com/canonical/netplan/commit/4c39b75b5c6ae7d976bda6da68da60d9a7f085ee]
Signed-off-by: Jinfeng Wang <jinfeng.wang.cn@windriver.com>
---
src/networkd.c | 36 +++------------
src/networkd.h | 2 +
src/nm.c | 4 +-
src/openvswitch.c | 2 +-
src/sriov.c | 4 +-
src/util-internal.h | 3 ++
src/util.c | 46 +++++++++++++++++++
tests/generator/test_auth.py | 2 +-
tests/generator/test_wifis.py | 2 +-
tests/integration/base.py | 85 +++++++++++++++++++++++++++++++++++
10 files changed, 150 insertions(+), 36 deletions(-)
diff --git a/src/networkd.c b/src/networkd.c
index 25121c4..a051c6f 100644
--- a/src/networkd.c
+++ b/src/networkd.c
@@ -221,7 +221,6 @@ STATIC void
write_link_file(const NetplanNetDefinition* def, const char* rootdir, const char* path)
{
GString* s = NULL;
- mode_t orig_umask;
/* Don't write .link files for virtual devices; they use .netdev instead.
* Don't write .link files for MODEM devices, as they aren't supported by networkd.
@@ -293,9 +292,7 @@ write_link_file(const NetplanNetDefinition* def, const char* rootdir, const char
g_string_append_printf(s, "LargeReceiveOffload=%s\n",
(def->large_receive_offload ? "true" : "false"));
- orig_umask = umask(022);
- _netplan_g_string_free_to_file(s, rootdir, path, ".link");
- umask(orig_umask);
+ _netplan_g_string_free_to_file_with_permissions(s, rootdir, path, ".link", "root", "root", 0640);
}
STATIC gboolean
@@ -313,7 +310,7 @@ write_regdom(const NetplanNetDefinition* def, const char* rootdir, GError** erro
g_string_append(s, "\n[Service]\nType=oneshot\n");
g_string_append_printf(s, "ExecStart="SBINDIR"/iw reg set %s\n", def->regulatory_domain);
- _netplan_g_string_free_to_file(s, rootdir, path, NULL);
+ _netplan_g_string_free_to_file_with_permissions(s, rootdir, path, NULL, "root", "root", 0640);
_netplan_safe_mkdir_p_dir(link);
if (symlink(path, link) < 0 && errno != EEXIST) {
// LCOV_EXCL_START
@@ -493,7 +490,6 @@ STATIC void
write_netdev_file(const NetplanNetDefinition* def, const char* rootdir, const char* path)
{
GString* s = NULL;
- mode_t orig_umask;
g_assert(def->type >= NETPLAN_DEF_TYPE_VIRTUAL);
@@ -589,11 +585,7 @@ write_netdev_file(const NetplanNetDefinition* def, const char* rootdir, const ch
default: g_assert_not_reached(); // LCOV_EXCL_LINE
}
- /* these do not contain secrets and need to be readable by
- * systemd-networkd - LP: #1736965 */
- orig_umask = umask(022);
- _netplan_g_string_free_to_file(s, rootdir, path, ".netdev");
- umask(orig_umask);
+ _netplan_g_string_free_to_file_with_permissions(s, rootdir, path, ".netdev", "root", NETWORKD_GROUP, 0640);
}
STATIC void
@@ -737,7 +729,6 @@ _netplan_netdef_write_network_file(
g_autoptr(GString) network = NULL;
g_autoptr(GString) link = NULL;
GString* s = NULL;
- mode_t orig_umask;
gboolean is_optional = def->optional;
SET_OPT_OUT_PTR(has_been_written, FALSE);
@@ -993,11 +984,7 @@ _netplan_netdef_write_network_file(
if (network->len > 0)
g_string_append_printf(s, "\n[Network]\n%s", network->str);
- /* these do not contain secrets and need to be readable by
- * systemd-networkd - LP: #1736965 */
- orig_umask = umask(022);
- _netplan_g_string_free_to_file(s, rootdir, path, ".network");
- umask(orig_umask);
+ _netplan_g_string_free_to_file_with_permissions(s, rootdir, path, ".network", "root", NETWORKD_GROUP, 0640);
}
SET_OPT_OUT_PTR(has_been_written, TRUE);
@@ -1009,7 +996,6 @@ write_rules_file(const NetplanNetDefinition* def, const char* rootdir)
{
GString* s = NULL;
g_autofree char* path = g_strjoin(NULL, "run/udev/rules.d/99-netplan-", def->id, ".rules", NULL);
- mode_t orig_umask;
/* do we need to write a .rules file?
* It's only required for reliably setting the name of a physical device
@@ -1043,9 +1029,7 @@ write_rules_file(const NetplanNetDefinition* def, const char* rootdir)
g_string_append_printf(s, "NAME=\"%s\"\n", def->set_name);
- orig_umask = umask(022);
- _netplan_g_string_free_to_file(s, rootdir, path, NULL);
- umask(orig_umask);
+ _netplan_g_string_free_to_file_with_permissions(s, rootdir, path, NULL, "root", "root", 0640);
}
STATIC gboolean
@@ -1194,7 +1178,6 @@ STATIC void
write_wpa_unit(const NetplanNetDefinition* def, const char* rootdir)
{
g_autofree gchar *stdouth = NULL;
- mode_t orig_umask;
stdouth = systemd_escape(def->id);
@@ -1213,9 +1196,7 @@ write_wpa_unit(const NetplanNetDefinition* def, const char* rootdir)
} else {
g_string_append(s, " -Dnl80211,wext\n");
}
- orig_umask = umask(022);
- _netplan_g_string_free_to_file(s, rootdir, path, NULL);
- umask(orig_umask);
+ _netplan_g_string_free_to_file_with_permissions(s, rootdir, path, NULL, "root", "root", 0640);
}
STATIC gboolean
@@ -1224,7 +1205,6 @@ write_wpa_conf(const NetplanNetDefinition* def, const char* rootdir, GError** er
GHashTableIter iter;
GString* s = g_string_new("ctrl_interface=/run/wpa_supplicant\n\n");
g_autofree char* path = g_strjoin(NULL, "run/netplan/wpa-", def->id, ".conf", NULL);
- mode_t orig_umask;
g_debug("%s: Creating wpa_supplicant configuration file %s", def->id, path);
if (def->type == NETPLAN_DEF_TYPE_WIFI) {
@@ -1313,9 +1293,7 @@ write_wpa_conf(const NetplanNetDefinition* def, const char* rootdir, GError** er
}
/* use tight permissions as this contains secrets */
- orig_umask = umask(077);
- _netplan_g_string_free_to_file(s, rootdir, path, NULL);
- umask(orig_umask);
+ _netplan_g_string_free_to_file_with_permissions(s, rootdir, path, NULL, "root", "root", 0600);
return TRUE;
}
diff --git a/src/networkd.h b/src/networkd.h
index 2bd0848..36c34b3 100644
--- a/src/networkd.h
+++ b/src/networkd.h
@@ -20,6 +20,8 @@
#include "netplan.h"
#include <glib.h>
+#define NETWORKD_GROUP "systemd-network"
+
NETPLAN_INTERNAL gboolean
_netplan_netdef_write_networkd(
const NetplanState* np_state,
diff --git a/src/nm.c b/src/nm.c
index 2b850af..8f1bf05 100644
--- a/src/nm.c
+++ b/src/nm.c
@@ -1150,13 +1150,13 @@ netplan_state_finish_nm_write(
/* write generated NetworkManager drop-in config */
if (nm_conf->len > 0)
- _netplan_g_string_free_to_file(nm_conf, rootdir, "run/NetworkManager/conf.d/netplan.conf", NULL);
+ _netplan_g_string_free_to_file_with_permissions(nm_conf, rootdir, "run/NetworkManager/conf.d/netplan.conf", NULL, "root", "root", 0640);
else
g_string_free(nm_conf, TRUE);
/* write generated udev rules */
if (udev_rules->len > 0)
- _netplan_g_string_free_to_file(udev_rules, rootdir, "run/udev/rules.d/90-netplan.rules", NULL);
+ _netplan_g_string_free_to_file_with_permissions(udev_rules, rootdir, "run/udev/rules.d/90-netplan.rules", NULL, "root", "root", 0640);
else
g_string_free(udev_rules, TRUE);
diff --git a/src/openvswitch.c b/src/openvswitch.c
index 6eb0688..2ab77e7 100644
--- a/src/openvswitch.c
+++ b/src/openvswitch.c
@@ -66,7 +66,7 @@ write_ovs_systemd_unit(const char* id, const GString* cmds, const char* rootdir,
g_string_append(s, "StartLimitBurst=0\n");
g_string_append(s, cmds->str);
- _netplan_g_string_free_to_file(s, rootdir, path, NULL);
+ _netplan_g_string_free_to_file_with_permissions(s, rootdir, path, NULL, "root", "root", 0640);
_netplan_safe_mkdir_p_dir(link);
if (symlink(path, link) < 0 && errno != EEXIST) {
diff --git a/src/sriov.c b/src/sriov.c
index 1534c94..213f124 100644
--- a/src/sriov.c
+++ b/src/sriov.c
@@ -54,7 +54,7 @@ write_sriov_rebind_systemd_unit(GHashTable* pfs, const char* rootdir, GError** e
g_string_truncate(interfaces, interfaces->len-1); /* cut trailing whitespace */
g_string_append_printf(s, "ExecStart=" SBINDIR "/netplan rebind --debug %s\n", interfaces->str);
- _netplan_g_string_free_to_file(s, rootdir, path, NULL);
+ _netplan_g_string_free_to_file_with_permissions(s, rootdir, path, NULL, "root", "root", 0640);
g_string_free(interfaces, TRUE);
_netplan_safe_mkdir_p_dir(link);
@@ -90,7 +90,7 @@ write_sriov_apply_systemd_unit(GHashTable* pfs, const char* rootdir, GError** er
g_string_append(s, "\n[Service]\nType=oneshot\n");
g_string_append_printf(s, "ExecStart=" SBINDIR "/netplan apply --sriov-only\n");
- _netplan_g_string_free_to_file(s, rootdir, path, NULL);
+ _netplan_g_string_free_to_file_with_permissions(s, rootdir, path, NULL, "root", "root", 0640);
_netplan_safe_mkdir_p_dir(link);
if (symlink(path, link) < 0 && errno != EEXIST) {
diff --git a/src/util-internal.h b/src/util-internal.h
index 86bd1b7..7454e77 100644
--- a/src/util-internal.h
+++ b/src/util-internal.h
@@ -40,6 +40,9 @@ _netplan_safe_mkdir_p_dir(const char* file_path);
NETPLAN_INTERNAL void
_netplan_g_string_free_to_file(GString* s, const char* rootdir, const char* path, const char* suffix);
+void
+_netplan_g_string_free_to_file_with_permissions(GString* s, const char* rootdir, const char* path, const char* suffix, const char* owner, const char* group, mode_t mode);
+
NETPLAN_INTERNAL void
_netplan_unlink_glob(const char* rootdir, const char* _glob);
diff --git a/src/util.c b/src/util.c
index 36eb896..c2f9494 100644
--- a/src/util.c
+++ b/src/util.c
@@ -23,6 +23,9 @@
#include <regex.h>
#include <string.h>
#include <sys/mman.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
#include <glib.h>
#include <glib/gprintf.h>
@@ -87,6 +90,49 @@ void _netplan_g_string_free_to_file(GString* s, const char* rootdir, const char*
}
}
+void _netplan_g_string_free_to_file_with_permissions(GString* s, const char* rootdir, const char* path, const char* suffix, const char* owner, const char* group, mode_t mode)
+{
+ g_autofree char* full_path = NULL;
+ g_autofree char* path_suffix = NULL;
+ g_autofree char* contents = g_string_free(s, FALSE);
+ GError* error = NULL;
+ struct passwd* pw = NULL;
+ struct group* gr = NULL;
+ int ret = 0;
+
+ path_suffix = g_strjoin(NULL, path, suffix, NULL);
+ full_path = g_build_path(G_DIR_SEPARATOR_S, rootdir ?: G_DIR_SEPARATOR_S, path_suffix, NULL);
+ _netplan_safe_mkdir_p_dir(full_path);
+ if (!g_file_set_contents_full(full_path, contents, -1, G_FILE_SET_CONTENTS_CONSISTENT | G_FILE_SET_CONTENTS_ONLY_EXISTING, mode, &error)) {
+ /* the mkdir() just succeeded, there is no sensible
+ * method to test this without root privileges, bind mounts, and
+ * simulating ENOSPC */
+ // LCOV_EXCL_START
+ g_fprintf(stderr, "ERROR: cannot create file %s: %s\n", path, error->message);
+ exit(1);
+ // LCOV_EXCL_STOP
+ }
+
+ /* Here we take the owner and group names and look up for their IDs in the passwd and group files.
+ * It's OK to fail to set the owners and mode as this code will be called from unit tests.
+ * The autopkgtests will check if the owner/group and mode are correctly set.
+ */
+ pw = getpwnam(owner);
+ if (!pw) {
+ g_debug("Failed to determine the UID of user %s: %s", owner, strerror(errno)); // LCOV_EXCL_LINE
+ }
+ gr = getgrnam(group);
+ if (!gr) {
+ g_debug("Failed to determine the GID of group %s: %s", group, strerror(errno)); // LCOV_EXCL_LINE
+ }
+ if (pw && gr) {
+ ret = chown(full_path, pw->pw_uid, gr->gr_gid);
+ if (ret != 0) {
+ g_debug("Failed to set owner and group for file %s: %s", full_path, strerror(errno));
+ }
+ }
+}
+
/**
* Remove all files matching given glob.
*/
diff --git a/tests/generator/test_auth.py b/tests/generator/test_auth.py
index de23adb..d3d886c 100644
--- a/tests/generator/test_auth.py
+++ b/tests/generator/test_auth.py
@@ -226,7 +226,7 @@ network={
with open(os.path.join(self.workdir.name, 'run/systemd/system/netplan-wpa-eth0.service')) as f:
self.assertEqual(f.read(), SD_WPA % {'iface': 'eth0', 'drivers': 'wired'})
- self.assertEqual(stat.S_IMODE(os.fstat(f.fileno()).st_mode), 0o644)
+ self.assertEqual(stat.S_IMODE(os.fstat(f.fileno()).st_mode), 0o640)
self.assertTrue(os.path.islink(os.path.join(
self.workdir.name, 'run/systemd/system/systemd-networkd.service.wants/netplan-wpa-eth0.service')))
diff --git a/tests/generator/test_wifis.py b/tests/generator/test_wifis.py
index b875172..610782a 100644
--- a/tests/generator/test_wifis.py
+++ b/tests/generator/test_wifis.py
@@ -140,7 +140,7 @@ network={
self.workdir.name, 'run/systemd/system/netplan-wpa-wl0.service')))
with open(os.path.join(self.workdir.name, 'run/systemd/system/netplan-wpa-wl0.service')) as f:
self.assertEqual(f.read(), SD_WPA % {'iface': 'wl0', 'drivers': 'nl80211,wext'})
- self.assertEqual(stat.S_IMODE(os.fstat(f.fileno()).st_mode), 0o644)
+ self.assertEqual(stat.S_IMODE(os.fstat(f.fileno()).st_mode), 0o640)
self.assertTrue(os.path.islink(os.path.join(
self.workdir.name, 'run/systemd/system/systemd-networkd.service.wants/netplan-wpa-wl0.service')))
diff --git a/tests/integration/base.py b/tests/integration/base.py
index e9c366c..74f0682 100644
--- a/tests/integration/base.py
+++ b/tests/integration/base.py
@@ -32,6 +32,8 @@ import shutil
import gi
import glob
import json
+import pwd
+import grp
# make sure we point to libnetplan properly.
os.environ.update({'LD_LIBRARY_PATH': '.:{}'.format(os.environ.get('LD_LIBRARY_PATH'))})
@@ -367,6 +369,89 @@ class IntegrationTestsBase(unittest.TestCase):
if state:
self.wait_output(['ip', 'addr', 'show', iface], state, 30)
+ # Assert file permissions
+ self.assert_file_permissions()
+
+ def assert_file_permissions(self):
+ """ Check if the generated files have the expected permissions """
+
+ nd_expected_mode = 0o100640
+ nd_expected_owner = 'root'
+ nd_expected_group = 'systemd-network'
+
+ sd_expected_mode = 0o100640
+ sd_expected_owner = 'root'
+ sd_expected_group = 'root'
+
+ udev_expected_mode = 0o100640
+ udev_expected_owner = 'root'
+ udev_expected_group = 'root'
+
+ nm_expected_mode = 0o100600
+ nm_expected_owner = 'root'
+ nm_expected_group = 'root'
+
+ wpa_expected_mode = 0o100600
+ wpa_expected_owner = 'root'
+ wpa_expected_group = 'root'
+
+ # Check systemd-networkd files
+ base_path = '/run/systemd/network'
+ files = glob.glob(f'{base_path}/*.network') + glob.glob(f'{base_path}/*.netdev')
+ for file in files:
+ res = os.stat(file)
+ user = pwd.getpwuid(res.st_uid)
+ group = grp.getgrgid(res.st_gid)
+ self.assertEqual(res.st_mode, nd_expected_mode, f'file {file}')
+ self.assertEqual(user.pw_name, nd_expected_owner, f'file {file}')
+ self.assertEqual(group.gr_name, nd_expected_group, f'file {file}')
+
+ # Check Network Manager files
+ base_path = '/run/NetworkManager/system-connections'
+ files = glob.glob(f'{base_path}/*.nmconnection')
+ for file in files:
+ res = os.stat(file)
+ user = pwd.getpwuid(res.st_uid)
+ group = grp.getgrgid(res.st_gid)
+ self.assertEqual(res.st_mode, nm_expected_mode, f'file {file}')
+ self.assertEqual(user.pw_name, nm_expected_owner, f'file {file}')
+ self.assertEqual(group.gr_name, nm_expected_group, f'file {file}')
+
+ # Check wpa_supplicant configuration files
+ base_path = '/run/netplan'
+ files = glob.glob(f'{base_path}/wpa-*.conf')
+ for file in files:
+ res = os.stat(file)
+ user = pwd.getpwuid(res.st_uid)
+ group = grp.getgrgid(res.st_gid)
+ self.assertEqual(res.st_mode, wpa_expected_mode, f'file {file}')
+ self.assertEqual(user.pw_name, wpa_expected_owner, f'file {file}')
+ self.assertEqual(group.gr_name, wpa_expected_group, f'file {file}')
+
+ # Check systemd service unit files
+ base_path = '/run/systemd/system/'
+ files = glob.glob(f'{base_path}/netplan-*.service')
+ files += glob.glob(f'{base_path}/systemd-networkd-wait-online.service.d/*.conf')
+ for file in files:
+ res = os.stat(file)
+ user = pwd.getpwuid(res.st_uid)
+ group = grp.getgrgid(res.st_gid)
+ self.assertEqual(res.st_mode, sd_expected_mode, f'file {file}')
+ self.assertEqual(user.pw_name, sd_expected_owner, f'file {file}')
+ self.assertEqual(group.gr_name, sd_expected_group, f'file {file}')
+
+ # Check systemd-udevd files
+ udev_path = '/run/udev/rules.d'
+ link_path = '/run/systemd/network'
+ files = glob.glob(f'{udev_path}/*-netplan*.rules') + glob.glob(f'{link_path}/*.link')
+ for file in files:
+ res = os.stat(file)
+ user = pwd.getpwuid(res.st_uid)
+ group = grp.getgrgid(res.st_gid)
+ self.assertEqual(res.st_mode, udev_expected_mode, f'file {file}')
+ self.assertEqual(user.pw_name, udev_expected_owner, f'file {file}')
+ self.assertEqual(group.gr_name, udev_expected_group, f'file {file}')
+
def state(self, iface, state):
'''Tell generate_and_settle() to wait for a specific state'''
return iface + '/' + state
--
2.44.1

View File

@@ -0,0 +1,54 @@
SUMMARY = "The network configuration abstraction renderer"
DESCRIPTION = "Netplan is a utility for easily configuring networking on a \
linux system. You simply create a YAML description of the required network \
interfaces and what each should be configured to do. From this description \
Netplan will generate all the necessary configuration for your chosen renderer \
tool."
HOMEPAGE = "https://netplan.io"
SECTION = "net/misc"
LICENSE = "GPL-3.0-only"
LIC_FILES_CHKSUM = "file://COPYING;md5=d32239bcb673463ab874e80d47fae504"
inherit meson pkgconfig systemd python3targetconfig features_check
REQUIRED_DISTRO_FEATURES = "systemd"
SRC_URI = "git://github.com/CanonicalLtd/netplan.git;branch=main;protocol=https \
file://0001-meson.build-drop-unnecessary-build-dependencies.patch \
file://0002-meson.build-do-not-use-Werror.patch \
file://CVE-2022-4968.patch \
"
SRC_URI:append:libc-musl = " file://0001-don-t-fail-if-GLOB_BRACE-is-not-defined.patch"
SRC_URI:append:toolchain-clang = " file://0001-networkd.c-define-scope-specific-to-case-statement.patch"
SRCREV = "45f7cd1569896d9e316c130bf5c60b7ccfc8211d"
S = "${WORKDIR}/git"
DEPENDS = "glib-2.0 libyaml util-linux-libuuid \
systemd python3-cffi-native \
"
EXTRA_OEMESON = "-Dunit_testing=false"
RDEPENDS:${PN} = "python3-core python3-netifaces python3-pyyaml \
python3-dbus python3-rich python3-cffi \
python3-json python3-fcntl \
util-linux-libuuid libnetplan \
"
do_install:append() {
install -d -m 755 ${D}${sysconfdir}/netplan
}
PACKAGES += "${PN}-dbus libnetplan"
FILES:libnetplan = "${libdir}/libnetplan.so.*"
FILES:${PN} = "${sbindir} ${libexecdir}/netplan/generate \
${datadir}/netplan ${datadir}/bash-completion \
${systemd_unitdir} ${PYTHON_SITEPACKAGES_DIR} \
${sysconfdir}/netplan \
"
FILES:${PN}-dbus = "${libexecdir}/netplan/netplan-dbus ${datadir}/dbus-1"

View File

@@ -0,0 +1,58 @@
{
"general": {
"objectName": "TB_gateway",
"address": "192.168.188.181:1052",
"objectIdentifier": 599,
"maxApduLengthAccepted": 1024,
"segmentationSupported": "segmentedBoth",
"vendorIdentifier": 15
},
"devices": [
{
"deviceName": "BACnet Device ${objectName}",
"deviceType": "default",
"address": "192.168.188.181:10520",
"pollPeriod": 10000,
"attributes": [
{
"key": "temperature",
"type": "string",
"objectId": "analogOutput:1",
"propertyId": "presentValue"
}
],
"timeseries": [
{
"key": "state",
"type": "bool",
"objectId": "binaryValue:1",
"propertyId": "presentValue"
}
],
"attributeUpdates": [
{
"key": "brightness",
"requestType": "writeProperty",
"objectId": "analogOutput:1",
"propertyId": "presentValue"
}
],
"serverSideRpc": [
{
"method": "set_state",
"requestType": "writeProperty",
"requestTimeout": 10000,
"objectId": "binaryOutput:1",
"propertyId": "presentValue"
},
{
"method": "get_state",
"requestType": "readProperty",
"requestTimeout": 10000,
"objectId": "binaryOutput:1",
"propertyId": "presentValue"
}
]
}
]
}

View File

@@ -0,0 +1,53 @@
{
"name": "BLE Connector",
"rescanIntervalSeconds": 100,
"checkIntervalSeconds": 100,
"scanTimeSeconds": 5,
"passiveScanMode": true,
"devices": [
{
"name": "Temperature and humidity sensor",
"MACAddress": "4C:65:A8:DF:85:C0",
"addrType": "public",
"telemetry": [
{
"key": "temperature",
"method": "notify",
"characteristicUUID": "226CAA55-6476-4566-7562-66734470666D",
"byteFrom": 2,
"byteTo": 6
},
{
"key": "humidity",
"method": "notify",
"characteristicUUID": "226CAA55-6476-4566-7562-66734470666D",
"byteFrom": 9,
"byteTo": 13
}
],
"attributes": [
{
"key": "name",
"characteristicUUID": "00002A00-0000-1000-8000-00805F9B34FB",
"method": "read",
"byteFrom": 0,
"byteTo": -1
}
],
"attributeUpdates": [
{
"attributeOnThingsBoard": "sharedName",
"characteristicUUID": "00002A00-0000-1000-8000-00805F9B34FB"
}
],
"serverSideRpc": [
{
"methodRPC": "rpcMethod1",
"withResponse": true,
"characteristicUUID": "00002A00-0000-1000-8000-00805F9B34FB",
"methodProcessing": "read"
}
]
}
]
}

View File

@@ -0,0 +1,89 @@
{
"interface": "socketcan",
"channel": "vcan0",
"backend": {
"fd": true
},
"reconnectPeriod": 5,
"devices": [
{
"name": "Car",
"sendDataOnlyOnChange": false,
"enableUnknownRpc": true,
"strictEval": false,
"attributes": [
{
"key": "isDriverDoorOpened",
"nodeId": 41,
"command": "2:2:big:8717",
"value": "4:1:int",
"expression": "bool(value & 0b00000100)",
"polling": {
"type": "once",
"dataInHex": "AB CD AB CD"
}
}
],
"timeseries": [
{
"key": "rpm",
"nodeId": 1918,
"isExtendedId": true,
"command": "2:2:big:48059",
"value": "4:2:big:int",
"expression": "value / 4",
"polling": {
"type": "always",
"period": 5,
"dataInHex": "aaaa bbbb aaaa bbbb"
}
},
{
"key": "milliage",
"nodeId": 1918,
"isExtendedId": true,
"value": "4:2:little:int",
"expression": "value * 10",
"polling": {
"type": "always",
"period": 30,
"dataInHex": "aa bb cc dd ee ff aa bb"
}
}
],
"attributeUpdates": [
{
"attributeOnThingsBoard": "softwareVersion",
"nodeId": 64,
"isExtendedId": true,
"dataLength": 4,
"dataExpression": "value + 5",
"dataByteorder": "little"
}
],
"serverSideRpc": [
{
"method": "sendSameData",
"nodeId": 4,
"isExtendedId": true,
"isFd": true,
"bitrateSwitch": true,
"dataInHex": "aa bb cc dd ee ff aa bb aa bb cc d ee ff"
},
{
"method": "setLightLevel",
"nodeId": 5,
"dataLength": 2,
"dataByteorder": "little",
"dataBefore": "00AA"
},
{
"method": "setSpeed",
"nodeId": 16,
"dataAfter": "0102",
"dataExpression": "userSpeed if maxAllowedSpeed > userSpeed else maxAllowedSpeed"
}
]
}
]
}

View File

@@ -0,0 +1,33 @@
{
"name": "Custom serial connector",
"devices": [
{
"name": "CustomSerialDevice1",
"type": "default",
"port": "/dev/ttyUSB0",
"baudrate": 9600,
"converter": "CustomSerialUplinkConverter",
"telemetry": [
{
"type": "byte",
"key": "humidity",
"untilDelimiter": "\r"
}
],
"attributes":[
{
"key": "SerialNumber",
"type": "string",
"fromByte": 4,
"toByte": -1
}
],
"attributeUpdates": [
{
"attributeOnThingsBoard": "attr1",
"stringToDevice": "value = ${attr1}\n"
}
]
}
]
}

View File

@@ -0,0 +1,77 @@
[loggers]
keys=root, service, connector, converter, tb_connection, storage, extension
[handlers]
keys=consoleHandler, serviceHandler, connectorHandler, converterHandler, tb_connectionHandler, storageHandler, extensionHandler
[formatters]
keys=LogFormatter
[logger_root]
level=ERROR
handlers=consoleHandler
[logger_connector]
level=INFO
handlers=connectorHandler
formatter=LogFormatter
qualname=connector
[logger_storage]
level=INFO
handlers=storageHandler
formatter=LogFormatter
qualname=storage
[logger_tb_connection]
level=INFO
handlers=tb_connectionHandler
formatter=LogFormatter
qualname=tb_connection
[logger_service]
level=INFO
handlers=serviceHandler
formatter=LogFormatter
qualname=service
[logger_converter]
level=INFO
handlers=converterHandler
formatter=LogFormatter
qualname=converter
[logger_extension]
level=INFO
handlers=connectorHandler
formatter=LogFormatter
qualname=extension
[handler_consoleHandler]
class=StreamHandler
level=INFO
formatter=LogFormatter
args=(sys.stdout,)
[handler_connectorHandler]
level=INFO
class=logging.handlers.TimedRotatingFileHandler
formatter=LogFormatter
args=("./logs/connector.log", "d", 1, 7,)
[handler_storageHandler]
level=INFO
class=logging.handlers.TimedRotatingFileHandler
formatter=LogFormatter
args=("./logs/storage.log", "d", 1, 7,)
[handler_serviceHandler]
level=INFO
class=logging.handlers.TimedRotatingFileHandler
formatter=LogFormatter
args=("./logs/service.log", "d", 1, 7,)
[handler_converterHandler]
level=INFO
class=logging.handlers.TimedRotatingFileHandler
formatter=LogFormatter
args=("./logs/converter.log", "d", 1, 3,)
[handler_extensionHandler]
level=INFO
class=logging.handlers.TimedRotatingFileHandler
formatter=LogFormatter
args=("./logs/extension.log", "d", 1, 3,)
[handler_tb_connectionHandler]
level=INFO
class=logging.handlers.TimedRotatingFileHandler
formatter=LogFormatter
args=("./logs/tb_connection.log", "d", 1, 3,)
[formatter_LogFormatter]
format="%(asctime)s - %(levelname)s - [%(filename)s] - %(module)s - %(lineno)d - %(message)s"
datefmt="%Y-%m-%d %H:%M:%S"

View File

@@ -0,0 +1,169 @@
{
"server": {
"type": "tcp",
"host": "127.0.0.1",
"port": 5020,
"timeout": 35,
"method": "socket",
"byteOrder": "BIG",
"devices": [
{
"unitId": 1,
"deviceName": "Temp Sensor",
"attributesPollPeriod": 5000,
"timeseriesPollPeriod": 5000,
"sendDataOnlyOnChange": true,
"attributes": [
{
"tag": "string_read",
"type": "string",
"functionCode": 4,
"objectsCount": 4,
"address": 1
},
{
"tag": "bits_read",
"type": "bits",
"functionCode": 4,
"objectsCount": 1,
"address": 5
},
{
"tag": "8int_read",
"type": "8int",
"functionCode": 4,
"objectsCount": 1,
"address": 6
},
{
"tag": "16int_read",
"type": "16int",
"functionCode": 4,
"objectsCount": 1,
"address": 7
},
{
"tag": "32int_read_divider",
"type": "32int",
"functionCode": 4,
"objectsCount": 2,
"address": 8,
"divider": 10
},
{
"tag": "8int_read_multiplier",
"type": "8int",
"functionCode": 4,
"objectsCount": 1,
"address": 10,
"multiplier": 10
},
{
"tag": "32int_read",
"type": "32int",
"functionCode": 4,
"objectsCount": 2,
"address": 11
},
{
"tag": "64int_read",
"type": "64int",
"functionCode": 4,
"objectsCount": 4,
"address": 13
}
],
"timeseries": [
{
"tag": "8uint_read",
"type": "8uint",
"functionCode": 4,
"objectsCount": 1,
"address": 17
},
{
"tag": "16uint_read",
"type": "16uint",
"functionCode": 4,
"objectsCount": 2,
"address": 18
},
{
"tag": "32uint_read",
"type": "32uint",
"functionCode": 4,
"objectsCount": 4,
"address": 20
},
{
"tag": "64uint_read",
"type": "64uint",
"functionCode": 4,
"objectsCount": 1,
"address": 24
},
{
"tag": "16float_read",
"type": "16float",
"functionCode": 4,
"objectsCount": 1,
"address": 25
},
{
"tag": "32float_read",
"type": "32float",
"functionCode": 4,
"objectsCount": 2,
"address": 26
},
{
"tag": "64float_read",
"type": "64float",
"functionCode": 4,
"objectsCount": 4,
"address": 28
}
],
"attributeUpdates": [
{
"tag": "shared_attribute_write",
"type": "32int",
"functionCode": 6,
"objectsCount": 2,
"address": 29
}
],
"rpc": [
{
"tag": "setValue",
"type": "bits",
"functionCode": 5,
"objectsCount": 1,
"address": 31
},
{
"tag": "getValue",
"type": "bits",
"functionCode": 1,
"objectsCount": 1,
"address": 31
},
{
"tag": "setCPUFanSpeed",
"type": "32int",
"functionCode": 16,
"objectsCount": 2,
"address": 33
},
{
"tag":"getCPULoad",
"type": "32int",
"functionCode": 4,
"objectsCount": 2,
"address": 35
}
]
}
]
}
}

View File

@@ -0,0 +1,29 @@
{
"server": {
"name": "Modbus Default Server",
"type": "serial",
"method": "rtu",
"port": "/dev/ttyUSB0",
"baudrate": 19200,
"timeout": 35,
"devices": [
{
"unitId": 1,
"deviceName": "Temp Sensor",
"attributesPollPeriod": 5000,
"timeseriesPollPeriod": 5000,
"sendDataOnlyOnChange": true,
"attributes": [
{
"byteOrder": "BIG",
"tag": "test",
"type": "long",
"functionCode": 4,
"registerCount": 1,
"address": 4
}
]
}
]
}
}

View File

@@ -0,0 +1,132 @@
{
"broker": {
"name":"Default Local Broker",
"host":"127.0.0.1",
"port":1883,
"clientId": "ThingsBoard_gateway",
"security": {
"type": "basic",
"username": "user",
"password": "password"
}
},
"mapping": [
{
"topicFilter": "/sensor/data",
"converter": {
"type": "json",
"deviceNameJsonExpression": "${serialNumber}",
"deviceTypeJsonExpression": "${sensorType}",
"timeout": 60000,
"attributes": [
{
"type": "string",
"key": "model",
"value": "${sensorModel}"
},
{
"type": "string",
"key": "${sensorModel}",
"value": "on"
}
],
"timeseries": [
{
"type": "double",
"key": "temperature",
"value": "${temp}"
},
{
"type": "double",
"key": "humidity",
"value": "${hum}"
}
]
}
},
{
"topicFilter": "/sensor/+/data",
"converter": {
"type": "json",
"deviceNameTopicExpression": "(?<=sensor\/)(.*?)(?=\/data)",
"deviceTypeTopicExpression": "Thermometer",
"timeout": 60000,
"attributes": [
{
"type": "string",
"key": "model",
"value": "${sensorModel}"
}
],
"timeseries": [
{
"type": "double",
"key": "temperature",
"value": "${temp}"
},
{
"type": "double",
"key": "humidity",
"value": "${hum}"
}
]
}
},
{
"topicFilter": "/custom/sensors/+",
"converter": {
"type": "custom",
"extension": "CustomMqttUplinkConverter",
"extension-config": {
"temperatureBytes" : 2,
"humidityBytes" : 2,
"batteryLevelBytes" : 1
}
}
}
],
"connectRequests": [
{
"topicFilter": "sensor/connect",
"deviceNameJsonExpression": "${SerialNumber}"
},
{
"topicFilter": "sensor/+/connect",
"deviceNameTopicExpression": "(?<=sensor\/)(.*?)(?=\/connect)"
}
],
"disconnectRequests": [
{
"topicFilter": "sensor/disconnect",
"deviceNameJsonExpression": "${SerialNumber}"
},
{
"topicFilter": "sensor/+/disconnect",
"deviceNameTopicExpression": "(?<=sensor\/)(.*?)(?=\/disconnect)"
}
],
"attributeUpdates": [
{
"deviceNameFilter": "SmartMeter.*",
"attributeFilter": "uploadFrequency",
"topicExpression": "sensor/${deviceName}/${attributeKey}",
"valueExpression": "{\"${attributeKey}\":\"${attributeValue}\"}"
}
],
"serverSideRpc": [
{
"deviceNameFilter": ".*",
"methodFilter": "echo",
"requestTopicExpression": "sensor/${deviceName}/request/${methodName}/${requestId}",
"responseTopicExpression": "sensor/${deviceName}/response/${methodName}/${requestId}",
"responseTimeout": 10000,
"valueExpression": "${params}"
},
{
"deviceNameFilter": ".*",
"methodFilter": "no-reply",
"requestTopicExpression": "sensor/${deviceName}/request/${methodName}/${requestId}",
"valueExpression": "${params}"
}
]
}

View File

@@ -0,0 +1,54 @@
{
"connection": {
"str": "Driver={PostgreSQL};Server=localhost;Port=5432;Database=thingsboard;Uid=postgres;Pwd=postgres;",
"attributes": {
"autocommit": true,
"timeout": 0
},
"encoding": "utf-8",
"decoding": {
"char": "utf-8",
"wchar": "utf-8",
"metadata": "utf-16le"
},
"reconnect": true,
"reconnectPeriod": 60
},
"pyodbc": {
"pooling": false
},
"polling": {
"query": "SELECT bool_v, str_v, dbl_v, long_v, entity_id, ts FROM ts_kv WHERE ts > ? ORDER BY ts ASC LIMIT 10",
"period": 10,
"iterator": {
"column": "ts",
"query": "SELECT MIN(ts) - 1 FROM ts_kv",
"persistent": false
}
},
"mapping": {
"device": {
"type": "postgres",
"name": "'ODBC ' + entity_id"
},
"sendDataOnlyOnChange": false,
"attributes": "*",
"timeseries": [
{
"name": "value",
"value": "[i for i in [str_v, long_v, dbl_v,bool_v] if i is not None][0]"
}
]
},
"serverSideRpc": {
"enableUnknownRpc": false,
"overrideRpcConfig": true,
"methods": [
"procedureOne",
{
"name": "procedureTwo",
"args": [ "One", 2, 3.0 ]
}
]
}
}

View File

@@ -0,0 +1,49 @@
{
"server": {
"name": "OPC-UA Default Server",
"url": "localhost:4840/freeopcua/server/",
"timeoutInMillis": 5000,
"scanPeriodInMillis": 5000,
"disableSubscriptions":false,
"subCheckPeriodInMillis": 100,
"showMap": false,
"security": "Basic128Rsa15",
"identity": {
"type": "anonymous"
},
"mapping": [
{
"deviceNodePattern": "Root\\.Objects\\.Device1",
"deviceNamePattern": "Device ${Root\\.Objects\\.Device1\\.serialNumber}",
"attributes": [
{
"key": "temperature °C",
"path": "${ns=2;i=5}"
}
],
"timeseries": [
{
"key": "humidity",
"path": "${Root\\.Objects\\.Device1\\.TemperatureAndHumiditySensor\\.Humidity}"
},
{
"key": "batteryLevel",
"path": "${Battery\\.batteryLevel}"
}
],
"rpc_methods": [
{
"method": "multiply",
"arguments": [2, 4]
}
],
"attributes_updates": [
{
"attributeOnThingsBoard": "deviceName",
"attributeOnDevice": "Root\\.Objects\\.Device1\\.serialNumber"
}
]
}
]
}
}

View File

@@ -0,0 +1,146 @@
"job": "leader"
},
"allowRedirects": true,
"timeout": 0.5,
"scanPeriod": 5,
"converter": {
"type": "json",
"deviceNameJsonExpression": "SD8500",
"deviceTypeJsonExpression": "SD",
"attributes": [
{
"key": "serialNumber",
"type": "string",
"value": "${serial}"
}
],
"telemetry": [
{
"key": "Maintainer",
"type": "string",
"value": "${Developer}"
}
]
}
},
{
"url": "get_info",
"httpMethod": "GET",
"httpHeaders": {
"ACCEPT": "application/json"
},
"allowRedirects": true,
"timeout": 0.5,
"scanPeriod": 100,
"converter": {
"type": "custom",
"deviceNameJsonExpression": "SD8500",
"deviceTypeJsonExpression": "SD",
"extension": "CustomRequestUplinkConverter",
"extension-config": [
{
"key": "Totaliser",
"type": "float",
"fromByte": 0,
"toByte": 4,
"byteorder": "big",
"signed": true,
"multiplier": 1
},
{
"key": "Flow",
"type": "int",
"fromByte": 4,
"toByte": 6,
"byteorder": "big",
"signed": true,
"multiplier": 0.01
},
{
"key": "Temperature",
"type": "int",
"fromByte": 8,
"toByte": 10,
"byteorder": "big",
"signed": true,
"multiplier": 0.01
},
{
"key": "Pressure",
"type": "int",
"fromByte": 12,
"toByte": 14,
"byteorder": "big",
"signed": true,
"multiplier": 0.01
},
{
"key": "deviceStatus",
"type": "int",
"byteAddress": 15,
"fromBit": 4,
"toBit": 8,
"byteorder": "big",
"signed": false
},
{
"key": "OUT2",
"type": "int",
"byteAddress": 15,
"fromBit": 1,
"toBit": 2,
"byteorder": "big"
},
{
"key": "OUT1",
"type": "int",
"byteAddress": 15,
"fromBit": 0,
"toBit": 1,
"byteorder": "big"
}
]
}
}
],
"attributeUpdates": [
{
"httpMethod": "POST",
"httpHeaders": {
"CONTENT-TYPE": "application/json"
},
"timeout": 0.5,
"tries": 3,
"allowRedirects": true,
"deviceNameFilter": "SD.*",
"attributeFilter": "send_data",
"requestUrlExpression": "sensor/${deviceName}/${attributeKey}",
"valueExpression": "{\"${attributeKey}\":\"${attributeValue}\"}"
}
],
"serverSideRpc": [
{
"deviceNameFilter": ".*",
"methodFilter": "echo",
"requestUrlExpression": "sensor/${deviceName}/request/${methodName}/${requestId}",
"responseTimeout": 1,
"httpMethod": "GET",
"valueExpression": "${params}",
"timeout": 0.5,
"tries": 3,
"httpHeaders": {
"Content-Type": "application/json"
}
},
{
"deviceNameFilter": ".*",
"methodFilter": "no-reply",
"requestUrlExpression": "sensor/${deviceName}/request/${methodName}/${requestId}",
"httpMethod": "POST",
"valueExpression": "${params}",
"httpHeaders": {
"Content-Type": "application/json"
}
}
]
}

View File

@@ -0,0 +1,152 @@
{
"host": "127.0.0.1",
"port": "5000",
"mapping":[
{
"endpoint": "/device1",
"HTTPMethods": [
"POST"
],
"security":
{
"type": "basic",
"username": "user",
"password": "passwd"
},
"converter": {
"type": "json",
"deviceNameExpression": "Device ${name}",
"deviceTypeExpression": "default",
"attributes": [
{
"type": "string",
"key": "model",
"value": "${sensorModel}"
}
],
"timeseries": [
{
"type": "double",
"key": "${sensorModel}",
"value": "${temp}"
},
{
"type": "double",
"key": "humidity",
"value": "${hum}"
}
]
}
},
{
"endpoint": "/anon1",
"HTTPMethods": [
"GET",
"POST"
],
"security":
{
"type": "anonymous"
},
"converter": {
"type": "json",
"deviceNameExpression": "Device 2",
"deviceTypeExpression": "default",
"attributes": [
{
"type": "string",
"key": "model",
"value": "Model2"
}
],
"timeseries": [
{
"type": "double",
"key": "temperature",
"value": "${temp}"
},
{
"type": "double",
"key": "humidity",
"value": "${hum}"
}
]
}
},
{
"endpoint": "/anon2",
"HTTPMethods": [
"POST"
],
"security":
{
"type": "anonymous"
},
"converter": {
"type": "custom",
"deviceNameExpression": "SuperAnonDevice",
"deviceTypeExpression": "default",
"extension": "CustomRestUplinkConverter",
"extension-config": [
{
"key": "Totaliser",
"datatype": "float",
"fromByte": 0,
"toByte": 4,
"byteorder": "big",
"signed": true,
"multiplier": 1
}]
}
}
],
"attributeUpdates": [
{
"HTTPMethod": "POST",
"SSLVerify": false,
"httpHeaders": {
"CONTENT-TYPE": "application/json"
},
"security": {
"type": "basic",
"username": "user",
"password": "passwd"
},
"timeout": 0.5,
"tries": 3,
"allowRedirects": true,
"deviceNameFilter": ".*REST$",
"attributeFilter": "data",
"requestUrlExpression": "sensor/${deviceName}/${attributeKey}",
"valueExpression": "{\"${attributeKey}\":\"${attributeValue}\"}"
}
],
"serverSideRpc": [
{
"deviceNameFilter": ".*",
"methodFilter": "echo",
"requestUrlExpression": "http://127.0.0.1:5001/${deviceName}",
"responseTimeout": 1,
"HTTPMethod": "GET",
"valueExpression": "${params}",
"timeout": 0.5,
"tries": 3,
"httpHeaders": {
"Content-Type": "application/json"
},
"security": {
"type": "anonymous"
}
},
{
"deviceNameFilter": ".*",
"methodFilter": "no-reply",
"requestUrlExpression": "sensor/${deviceName}/request/${methodName}/${requestId}",
"HTTPMethod": "POST",
"valueExpression": "${params}",
"httpHeaders": {
"Content-Type": "application/json"
}
}
]
}

View File

@@ -0,0 +1,138 @@
{
"devices": [
{
"deviceName": "SNMP router",
"deviceType": "snmp",
"ip": "snmp.live.gambitcommunications.com",
"port": 161,
"pollPeriod": 5000,
"community": "public",
"attributes": [
{
"key": "ReceivedFromGet",
"method": "get",
"oid": "1.3.6.1.2.1.1.1.0",
"timeout": 6
},
{
"key": "ReceivedFromMultiGet",
"method": "multiget",
"oid": [
"1.3.6.1.2.1.1.1.0",
"1.3.6.1.2.1.1.2.0"
],
"timeout": 6
},
{
"key": "ReceivedFromGetNext",
"method": "getnext",
"oid": "1.3.6.1.2.1.1.1.0",
"timeout": 6
},
{
"key": "ReceivedFromMultiWalk",
"method": "multiwalk",
"oid": [
"1.3.6.1.2.1.1.1.0",
"1.3.6.0.1.2.1"
]
},
{
"key": "ReceivedFromBulkWalk",
"method": "bulkwalk",
"oid": [
"1.3.6.1.2.1.1.1.0",
"1.3.6.1.2.1.1.2.0"
]
},
{
"key": "ReceivedFromBulkGet",
"method": "bulkget",
"scalarOid": [
"1.3.6.1.2.1.1.1.0",
"1.3.6.1.2.1.1.2.0"
],
"repeatingOid": [
"1.3.6.1.2.1.1.1.0",
"1.3.6.1.2.1.1.2.0"
],
"maxListSize": 10
}
],
"telemetry": [
{
"key": "ReceivedFromWalk",
"community": "private",
"method": "walk",
"oid": "1.3.6.1.2.1.1.1.0"
},
{
"key": "ReceivedFromTable",
"method": "table",
"oid": "1.3.6.1.2.1.1"
}
],
"attributeUpdateRequests": [
{
"attributeFilter": "dataToSet",
"method": "set",
"oid": "1.3.6.1.2.1.1.1.0"
},
{
"attributeFilter": "dataToMultiSet",
"method": "multiset",
"mappings": {
"1.2.3": "10",
"2.3.4": "${attribute}"
}
}
],
"serverSideRpcRequests": [
{
"requestFilter": "setData",
"method": "set",
"oid": "1.3.6.1.2.1.1.1.0"
},
{
"requestFilter": "multiSetData",
"method": "multiset"
},
{
"requestFilter": "getData",
"method": "get",
"oid": "1.3.6.1.2.1.1.1.0"
},
{
"requestFilter": "runBulkWalk",
"method": "bulkwalk",
"oid": [
"1.3.6.1.2.1.1.1.0",
"1.3.6.1.2.1.1.2.0"
]
}
]
},
{
"deviceName": "SNMP router",
"deviceType": "snmp",
"ip": "127.0.0.1",
"pollPeriod": 5000,
"community": "public",
"converter": "CustomSNMPConverter",
"attributes": [
{
"key": "ReceivedFromGetWithCustomConverter",
"method": "get",
"oid": "1.3.6.1.2.1.1.1.0"
}
],
"telemetry": [
{
"key": "ReceivedFromTableWithCustomConverter",
"method": "table",
"oid": "1.3.6.1.2.1.1.1.0"
}
]
}
]
}

View File

@@ -0,0 +1,66 @@
thingsboard:
host: demo.thingsboard.io
port: 1883
remoteConfiguration: false
security:
accessToken: PUT_YOUR_GW_ACCESS_TOKEN_HERE
storage:
type: memory
read_records_count: 100
max_records_count: 100000
# type: file
# data_folder_path: ./data/
# max_file_count: 10
# max_read_records_count: 10
# max_records_per_file: 10000
connectors:
-
name: MQTT Broker Connector
type: mqtt
configuration: mqtt.json
# -
# name: Modbus Connector
# type: modbus
# configuration: modbus.json
#
# -
# name: Modbus Connector
# type: modbus
# configuration: modbus_serial.json
#
# -
# name: OPC-UA Connector
# type: opcua
# configuration: opcua.json
#
# -
# name: BLE Connector
# type: ble
# configuration: ble.json
#
# -
# name: REQUEST Connector
# type: request
# configuration: request.json
#
# -
# name: CAN Connector
# type: can
# configuration: can.json
#
# -
# name: BACnet Connector
# type: bacnet
# configuration: bacnet.json
#
# -
# name: ODBC Connector
# type: odbc
# configuration: odbc.json
#
# -
# name: Custom Serial Connector
# type: serial
# configuration: custom_serial.json
# class: CustomSerialConnector

View File

@@ -0,0 +1,13 @@
[Unit]
Description = Systemd service for Thingsboard Gateway
After = network.target
[Service]
ExecStart = /usr/bin/python3 /usr/bin/thingsboard-gateway
ExecStop = /bin/kill -INT $MAINPID
ExecReload = /bin/kill -TERM $MAINPID
Restart = always
Type = simple
[Install]
WantedBy=multi-user.target

View File

@@ -0,0 +1,67 @@
SUMMARY = "Open-source IoT platform for data collection, processing, visualization, and device management"
DESCRIPTION = "\
The Thingsboard IoT Gateway is an open-source solution that allows you \
to integrate devices connected to legacy and third-party systems with Thingsboard."
HOMEPAGE = "https://thingsboard.io/"
LICENSE = "Apache-2.0"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/Apache-2.0;md5=89aea4e17d99a7cacdbeed46a0096b10"
SRC_URI[sha256sum] = "fc24bb674308f05d963a1dbed8d0b38ead77424ad7cf032a2652732af48f1336"
inherit pypi setuptools3
PYPI_PACKAGE = "thingsboard-gateway"
RDEPENDS:${PN} += " python3-jsonpath-rw \
python3-regex \
python3-paho-mqtt \
python3-pyyaml \
python3-simplejson \
python3-requests \
python3-pip \
python3-pyrsistent \
"
SRC_URI += "file://bacnet.json \
file://ble.json \
file://can.json \
file://custom_serial.json \
file://modbus.json \
file://modbus_serial.json \
file://mqtt.json \
file://opcua.json \
file://odbc.json \
file://request.json \
file://rest.json \
file://snmp.json \
file://tb_gateway.yaml \
file://logs.conf \
file://thingsboard-gateway.service \
"
inherit systemd
SYSTEMD_PACKAGES = "${PN}"
SYSTEMD_SERVICE:${PN} = "thingsboard-gateway.service"
FILES:${PN} += "/etc \
/lib \
/usr \
"
do_install:append(){
install -d ${D}${sysconfdir}/thingsboard-gateway/config
for file in $(find ${WORKDIR} -maxdepth 1 -type f -name *.json); do
install -m 0644 "$file" ${D}${sysconfdir}/thingsboard-gateway/config
done
install -m 0644 ${WORKDIR}/tb_gateway.yaml ${D}${sysconfdir}/thingsboard-gateway/config
install -m 0644 ${WORKDIR}/logs.conf ${D}${sysconfdir}/thingsboard-gateway/config
install -d ${D}${systemd_unitdir}/system/
install -m 0644 ${WORKDIR}/thingsboard-gateway.service ${D}${systemd_system_unitdir}/thingsboard-gateway.service
}