From 312594f869cc5b068f014274e689e2fb230cd9d7 Mon Sep 17 00:00:00 2001 From: Daniel Golle Date: Sat, 10 Apr 2021 04:04:09 +0100 Subject: [PATCH] uvol: add new package uvol is a wrapper-script which allows automated handling of storage volumes. uvol currently comes with backend support for LVM2 and UBI, covering practically all options for storage large enough to be managed (NAND, SPI-NAND, eMMC, SATA, NVME, virtio-blk, ...). Signed-off-by: Daniel Golle --- utils/ap_config/Makefile | 37 ++++ utils/ap_config/git-src | 1 + utils/autopart/Makefile | 40 ---- utils/modbus-utils/Makefile | 42 ++++ utils/uvol/Makefile | 73 +++++++ .../autopart => uvol/files/autopart.defaults} | 0 utils/uvol/files/lvm.sh | 195 ++++++++++++++++++ utils/uvol/files/ubi.sh | 160 ++++++++++++++ utils/uvol/files/uvol | 9 + 9 files changed, 517 insertions(+), 40 deletions(-) create mode 100644 utils/ap_config/Makefile create mode 120000 utils/ap_config/git-src delete mode 100644 utils/autopart/Makefile create mode 100644 utils/modbus-utils/Makefile create mode 100644 utils/uvol/Makefile rename utils/{autopart/files/autopart => uvol/files/autopart.defaults} (100%) create mode 100644 utils/uvol/files/lvm.sh create mode 100644 utils/uvol/files/ubi.sh create mode 100644 utils/uvol/files/uvol diff --git a/utils/ap_config/Makefile b/utils/ap_config/Makefile new file mode 100644 index 000000000..2d09dc90c --- /dev/null +++ b/utils/ap_config/Makefile @@ -0,0 +1,37 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=ap_config +PKG_VERSION:=2021-03-21 +PKG_RELEASE:=1 + +PKG_BUILD_PARALLEL:=1 +PKG_INSTALL:=1 + +include $(INCLUDE_DIR)/package.mk + +define Package/ac_server + SECTION:=utils + CATEGORY:=Utilities + TITLE:=ac_server + DEPENDS:=+libaxl +libopenssl +libmariadbclient +endef + +define Package/ac_client + SECTION:=utils + CATEGORY:=Utilities + TITLE:=ac_client + DEPENDS:=+libaxl +libopenssl +endef + +define Package/ac_server/install + $(INSTALL_DIR) $(1)/usr/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/ac_server $(1)/usr/sbin +endef + +define Package/ap_client/install + $(INSTALL_DIR) $(1)/usr/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/ac_client $(1)/usr/sbin +endef + +$(eval $(call BuildPackage,ac_server)) +$(eval $(call BuildPackage,ac_client)) diff --git a/utils/ap_config/git-src b/utils/ap_config/git-src new file mode 120000 index 000000000..c2296c4a5 --- /dev/null +++ b/utils/ap_config/git-src @@ -0,0 +1 @@ +/usr/src/ap_config/.git \ No newline at end of file diff --git a/utils/autopart/Makefile b/utils/autopart/Makefile deleted file mode 100644 index dcd211ba8..000000000 --- a/utils/autopart/Makefile +++ /dev/null @@ -1,40 +0,0 @@ -include $(TOPDIR)/rules.mk - -PKG_NAME:=autopart -PKG_VERSION:=0.1 -PKG_RELEASE:=$(AUTORELEASE) - -PKG_MAINTAINER:=Daniel Golle -PKG_LICENSE:=GPL-2.0-or-later - -include $(INCLUDE_DIR)/package.mk - -define Package/autopart - SECTION:=utils - CATEGORY:=Utilities - SUBMENU:=Disc - TITLE:=Automatically initialize LVM partition - DEPENDS:=+lvm2 +partx-utils +sfdisk - PKGARCH=all -endef - -define Package/autopart/description - Automatically allocate the GPT partition for LVM and initialize it - on first boot. -endef - -define Build/Prepare -endef - -define Build/Configure -endef - -define Build/Compile -endef - -define Package/autopart/install - $(INSTALL_DIR) $(1)/etc/uci-defaults - $(INSTALL_BIN) ./files/autopart $(1)/etc/uci-defaults/30-autopart -endef - -$(eval $(call BuildPackage,autopart)) diff --git a/utils/modbus-utils/Makefile b/utils/modbus-utils/Makefile new file mode 100644 index 000000000..2894439fe --- /dev/null +++ b/utils/modbus-utils/Makefile @@ -0,0 +1,42 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=modbus-utils + +PKG_VERSION:=2013-07-31 +PKG_RELEASE=$(PKG_SOURCE_VERSION) + +PKG_SOURCE_PROTO:=git +PKG_SOURCE_URL:=https://github.com/Krzysztow/modbus-utils.git +PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION) +PKG_SOURCE_VERSION:=c569dc0a11a1bedf3a8080fe4a1696de93e386ab +# PKG_MIRROR_HASH:=3aed4146e06bd9f9bcc271824c6b1d75d1fc2a0bd980f2b729c3b4755c6f70a8 +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2 + +PKG_FIXUP:=autoreconf +PKG_BUILD_PARALLEL:=1 +PKG_INSTALL:=1 + +PKG_MAINTAINER:=Daniel Golle + +# supposed based on statement that source is based on libmodbus testcases +PKG_LICENSE:=GPL-3.0+ LGPL-2.1+ + +include $(INCLUDE_DIR)/package.mk +include $(INCLUDE_DIR)/nls.mk + +define Package/modbus-utils + SECTION:=utils + CATEGORY:=Utilities + TITLE:=Modbus client/server utils + DEPENDS:=+libmodbus +endef + +define Package/modbus-utils/description +endef + +define Package/modbus-utils/install + $(INSTALL_DIR) $(1)/usr/bin +# $(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/bin/mbrecorder $(1)/usr/bin/ +endef + +$(eval $(call BuildPackage,modbus-utils)) diff --git a/utils/uvol/Makefile b/utils/uvol/Makefile new file mode 100644 index 000000000..64fb0238d --- /dev/null +++ b/utils/uvol/Makefile @@ -0,0 +1,73 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=uvol +PKG_VERSION:=0.2 +PKG_RELEASE:=$(AUTORELEASE) + +PKG_MAINTAINER:=Daniel Golle +PKG_LICENSE:=GPL-2.0-or-later + +include $(INCLUDE_DIR)/package.mk + +define Package/autopart + SECTION:=utils + CATEGORY:=Utilities + SUBMENU:=Disc + TITLE:=Automatically initialize LVM partition + DEPENDS:=+lvm2 +partx-utils +sfdisk + PKGARCH=all +endef + +define Package/autopart/description + Automatically allocate the GPT partition for LVM and initialize it + on first boot. +endef + +define Package/uvol + SECTION:=utils + CATEGORY:=Utilities + SUBMENU:=Disc + TITLE:=OpenWrt UBI/LVM volume abstraction + PKGARCH=all +endef + +define Package/uvol/description + 'uvol' is tool to automate storage volume handling on embedded + devices in a generic way. + Also install the 'autopart' package to easily make use of 'uvol' on + block-storage based devices. + + Examples: + uvol create example_volume_1 256MiB rw + uvol up example_volume_1 + uvol device example_volume_1 + + uvol create example_volume_2 9812733 ro + cat example_volume_2.squashfs | uvol write example_volume_2 9812733 + uvol up example_volume_2 + uvol device example_volume_2 +endef + +define Build/Prepare +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/autopart/install + $(INSTALL_DIR) $(1)/etc/uci-defaults + $(INSTALL_BIN) ./files/autopart.defaults $(1)/etc/uci-defaults/30-autopart +endef + +define Package/uvol/install + $(INSTALL_DIR) $(1)/usr/sbin $(1)/usr/libexec/uvol + $(INSTALL_BIN) ./files/uvol $(1)/usr/sbin + $(INSTALL_BIN) ./files/ubi.sh $(1)/usr/libexec/uvol/20-ubi.sh + $(INSTALL_BIN) ./files/lvm.sh $(1)/usr/libexec/uvol/50-lvm.sh +endef + +$(eval $(call BuildPackage,autopart)) +$(eval $(call BuildPackage,uvol)) diff --git a/utils/autopart/files/autopart b/utils/uvol/files/autopart.defaults similarity index 100% rename from utils/autopart/files/autopart rename to utils/uvol/files/autopart.defaults diff --git a/utils/uvol/files/lvm.sh b/utils/uvol/files/lvm.sh new file mode 100644 index 000000000..540fe39e9 --- /dev/null +++ b/utils/uvol/files/lvm.sh @@ -0,0 +1,195 @@ +#!/bin/sh + +command -v lvm || return 1 + +. /lib/functions.sh +. /lib/upgrade/common.sh + +export_bootdevice +[ "$BOOTDEV_MAJOR" ] || return 1 +export_partdevice rootdev 0 +[ "$rootdev" ] || return 1 +LVM_SUPPRESS_FD_WARNINGS=1 + +case "$rootdev" in + mtd*|\ + ram*|\ + ubi*) + return 1 +esac + +lvs() { + local cmd="$1" + local cb="$2" + local param="${3:+-S vg_name=${vgname} -S lv_name=~^r[ow]_$3\$}" + local oIFS="$IFS" + IFS=" " + set -- $(LVM_SUPPRESS_FD_WARNINGS=1 $cmd -c $param) + [ "$1" ] || { + IFS="$oIFS" + return 1 + } + IFS=":" + set -- $1 + IFS="$oIFS" + $cb "$@" +} + +pvvars() { + case "${1:5}" in + "$rootdev"*) + partdev="$1" + vgname="$2" + ;; + esac +} + +vgvars() { + [ "$1" = "$vgname" ] || return + vgbs="${13}" + vgts="${14}" + vgus="${15}" + vgfs="${16}" +} + +lvvars() { + lvpath="$1" + lvsize=$(( 512 * $7 )) +} + +freebytes() { + echo $((vgfs * vgbs * 1024)) +} + +totalbytes() { + echo $((vgts * vgbs * 1024)) +} + +existvol() { + [ "$1" ] || return 1 + test -e "/dev/$vgname/ro_$1" || test -e "/dev/$vgname/rw_$1" + return $? +} + +getlvname() { + lvs lvdisplay lvvars "$1" + + [ "$lvpath" ] && echo ${lvpath:5} +} + +getdev() { + existvol "$1" || return 1 + readlink /dev/$(getlvname "$1") +} + +getsize() { + lvs lvdisplay lvvars "$1" + [ "$lvsize" ] && echo $lvsize +} + +activatevol() { + LVM_SUPPRESS_FD_WARNINGS=1 lvchange -a y "$(getlvname "$1")" +} + +disactivatevol() { + existvol "$1" || return 1 + LVM_SUPPRESS_FD_WARNINGS=1 lvchange -a n "$(getlvname "$1")" +} + +getstatus() { + lvs lvdisplay lvvars "$1" + [ "$lvsize" ] || return 2 + existvol "$1" || return 1 + return 0 +} + +createvol() { + local mode ret lvname + case "$3" in + ro) + mode=r + ;; + rw) + mode=rw + ;; + *) + return 22 + ;; + esac + + LVM_SUPPRESS_FD_WARNINGS=1 lvcreate -p $mode -a n -y -W n -Z n -n "${3}_${1}" -L "$2" $vgname + ret=$? + if [ ! $ret -eq 0 ] || [ "$mode" = "r" ]; then + return $ret + fi + lvs lvdisplay lvvars "$1" + [ "$lvpath" ] || return 22 + lvname=${lvpath:5} + LVM_SUPPRESS_FD_WARNINGS=1 lvchange -a y /dev/$lvname || return 1 + if [ $lvsize -gt $(( 100 * 1024 * 1024 )) ]; then + mkfs.f2fs -f -l "$1" $lvpath || return 1 + else + mke2fs -F -L "$1" $lvpath || return 1 + fi + return 0 +} + +removevol() { + local lvname="$(getlvname "$1")" + [ "$lvname" ] || return 2 + LVM_SUPPRESS_FD_WARNINGS=1 lvremove -y "$(getlvname "$1")" +} + +updatevol() { + lvs lvdisplay lvvars "$1" + [ "$lvpath" ] || return 2 + [ $lvsize -ge $2 ] || return 27 + LVM_SUPPRESS_FD_WARNINGS=1 lvchange -a y -p rw ${lvpath:5} + dd of=$lvpath + case "$lvpath" in + /dev/*/ro_*) + LVM_SUPPRESS_FD_WARNINGS=1 lvchange -p r ${lvpath:5} + ;; + esac +} + +lvs pvdisplay pvvars +lvs vgdisplay vgvars +cmd="$1" +shift +case "$cmd" in + free) + freebytes + ;; + total) + totalbytes + ;; + create) + createvol "$@" + ;; + remove) + removevol "$@" + ;; + device) + getdev "$@" + ;; + size) + getsize "$@" + ;; + up) + activatevol "$@" + ;; + down) + disactivatevol "$@" + ;; + status) + getstatus "$@" + ;; + write) + updatevol "$@" + ;; + *) + echo "unknown command" + return 1 + ;; +esac diff --git a/utils/uvol/files/ubi.sh b/utils/uvol/files/ubi.sh new file mode 100644 index 000000000..f2f2ab224 --- /dev/null +++ b/utils/uvol/files/ubi.sh @@ -0,0 +1,160 @@ +#!/bin/sh + +test -e /sys/class/ubi/version || return 0 +read ubiver < /sys/class/ubi/version +[ "$ubiver" = "1" ] || return 1 +test -e /sys/devices/virtual/ubi || return 0 + +ubidev=$(ls -1 /sys/devices/virtual/ubi | head -n 1) + +read ebsize < "/sys/devices/virtual/ubi/${ubidev}/eraseblock_size" + +freebytes() { + read availeb < "/sys/devices/virtual/ubi/${ubidev}/avail_eraseblocks" + echo $((availeb * ebsize)) +} + +totalbytes() { + read totaleb < "/sys/devices/virtual/ubi/${ubidev}/total_eraseblocks" + echo $((totaleb * ebsize)) +} + +getdev() { + local voldir volname devname + for voldir in /sys/devices/virtual/ubi/${ubidev}/${ubidev}_*; do + read volname < "${voldir}/name" + [ "$volname" = "uvol-ro-$1" ] || [ "$volname" = "uvol-rw-$1" ] || continue + basename "$voldir" + done +} + +needs_ubiblock() { + local voldev="$1" + local volname + read volname < "/sys/devices/virtual/ubi/${ubidev}/${voldev}/name" + case "$volname" in + uvol-ro-*) + return 0 + ;; + esac + return 1 +} + +getstatus() { + local voldev=$(getdev "$@") + [ "$voldev" ] || return 2 + needs_ubiblock $voldev && [ ! -e "/dev/ubiblock${voldev:3}" ] && return 1 + return 0 +} + +getsize() { + local voldev + voldev=$(getdev "$@") + [ "$voldev" ] || return 2 + cat /sys/devices/virtual/ubi/${ubidev}/${voldev}/data_bytes +} + +getuserdev() { + local voldev=$(getdev "$@") + [ "$voldev" ] || return 2 + if needs_ubiblock $voldev ; then + echo "/dev/ubiblock${voldev:3}" + else + echo "/dev/$voldev" + fi +} + +createvol() { + local mode + local existdev=$(getdev "$1") + [ "$existdev" ] && return 17 + case "$3" in + ro) + mode=ro + ;; + rw) + mode=rw + ;; + *) + return 22 + ;; + esac + ubimkvol /dev/$ubidev -N "uvol-$mode-$1" -s "$2" +} + +removevol() { + local voldev=$(getdev "$@") + [ "$voldev" ] || return 2 + local volnum=${voldev#${ubidev}_} + ubirmvol /dev/$ubidev -n $volnum +} + +activatevol() { + local voldev=$(getdev "$@") + [ "$voldev" ] || return 2 + needs_ubiblock $voldev || return 0 + [ -e "/dev/ubiblock${voldev:3}" ] && return 0 + ubiblock --create /dev/$voldev +} + +disactivatevol() { + local voldev=$(getdev "$@") + [ "$voldev" ] || return 2 + needs_ubiblock $voldev || return 0 + [ -e "/dev/ubiblock${voldev:3}" ] || return 0 + ubiblock --remove /dev/$voldev +} + +updatevol() { + local voldev=$(getdev "$@") + [ "$voldev" ] || return 2 + [ "$2" ] || return 22 + needs_ubiblock $voldev || return 22 + ubiupdatevol -s $2 /dev/$voldev - +} + +getstatus() { + local voldev=$(getdev "$@") + [ "$voldev" ] || return 2 + needs_ubiblock $voldev && [ ! -e "/dev/ubiblock${voldev:3}" ] && return 1 + return 0 +} + +cmd="$1" +shift +case "$cmd" in + free) + freebytes + ;; + total) + totalbytes + ;; + create) + createvol "$@" + ;; + remove) + removevol "$@" + ;; + device) + getuserdev "$@" + ;; + size) + getsize "$@" + ;; + up) + activatevol "$@" + ;; + down) + disactivatevol "$@" + ;; + status) + getstatus "$@" + ;; + write) + updatevol "$@" + ;; + *) + echo "unknown command" + return 1 + ;; +esac diff --git a/utils/uvol/files/uvol b/utils/uvol/files/uvol new file mode 100644 index 000000000..89c6518c8 --- /dev/null +++ b/utils/uvol/files/uvol @@ -0,0 +1,9 @@ +#!/bin/sh + +uvol_backend= +for backend in /usr/libexec/uvol/*.sh; do + total=$($backend total) + [ "$total" ] && uvol_backend=$backend +done + +flock -x /tmp/run/uvol.lock $uvol_backend "$@"