mirror of
https://github.com/Telecominfraproject/wlan-ap.git
synced 2025-10-29 01:22:25 +00:00
1214 lines
27 KiB
Diff
1214 lines
27 KiB
Diff
From 08809a60a8f2c065a38c24fcdbd69b939e5c29d9 Mon Sep 17 00:00:00 2001
|
|
From: John Crispin <john@phrozen.org>
|
|
Date: Fri, 13 Aug 2021 08:46:57 +0200
|
|
Subject: [PATCH 24/27] uvol: backport package
|
|
|
|
Signed-off-by: John Crispin <john@phrozen.org>
|
|
---
|
|
package/system/uvol/Makefile | 77 ++++
|
|
package/system/uvol/files/autopart.defaults | 127 ++++++
|
|
package/system/uvol/files/common.sh | 83 ++++
|
|
package/system/uvol/files/lvm.sh | 435 ++++++++++++++++++++
|
|
package/system/uvol/files/ubi.sh | 337 +++++++++++++++
|
|
package/system/uvol/files/uvol | 52 +++
|
|
package/system/uvol/files/uvol.defaults | 3 +
|
|
package/system/uvol/files/uvol.init | 23 ++
|
|
8 files changed, 1137 insertions(+)
|
|
create mode 100644 package/system/uvol/Makefile
|
|
create mode 100644 package/system/uvol/files/autopart.defaults
|
|
create mode 100644 package/system/uvol/files/common.sh
|
|
create mode 100644 package/system/uvol/files/lvm.sh
|
|
create mode 100644 package/system/uvol/files/ubi.sh
|
|
create mode 100644 package/system/uvol/files/uvol
|
|
create mode 100644 package/system/uvol/files/uvol.defaults
|
|
create mode 100644 package/system/uvol/files/uvol.init
|
|
|
|
diff --git a/package/system/uvol/Makefile b/package/system/uvol/Makefile
|
|
new file mode 100644
|
|
index 0000000000..bd70410c5e
|
|
--- /dev/null
|
|
+++ b/package/system/uvol/Makefile
|
|
@@ -0,0 +1,77 @@
|
|
+include $(TOPDIR)/rules.mk
|
|
+
|
|
+PKG_NAME:=uvol
|
|
+PKG_VERSION:=0.4
|
|
+PKG_RELEASE:=$(AUTORELEASE)
|
|
+
|
|
+PKG_MAINTAINER:=Daniel Golle <daniel@makrotopia.org>
|
|
+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:=+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
|
|
+ DEPENDS:=+blockd
|
|
+ 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)/etc/init.d $(1)/usr/libexec/uvol $(1)/usr/sbin $(1)/lib/functions $(1)/etc/uci-defaults
|
|
+ $(INSTALL_BIN) ./files/uvol.init $(1)/etc/init.d/uvol
|
|
+ $(INSTALL_BIN) ./files/common.sh $(1)/lib/functions/uvol.sh
|
|
+ $(INSTALL_BIN) ./files/ubi.sh $(1)/usr/libexec/uvol/20-ubi.sh
|
|
+ $(INSTALL_BIN) ./files/lvm.sh $(1)/usr/libexec/uvol/50-lvm.sh
|
|
+ $(INSTALL_BIN) ./files/uvol $(1)/usr/sbin
|
|
+ $(INSTALL_BIN) ./files/uvol.defaults $(1)/etc/uci-defaults/90-uvol-restore-uci
|
|
+endef
|
|
+
|
|
+$(eval $(call BuildPackage,autopart))
|
|
+$(eval $(call BuildPackage,uvol))
|
|
diff --git a/package/system/uvol/files/autopart.defaults b/package/system/uvol/files/autopart.defaults
|
|
new file mode 100644
|
|
index 0000000000..870cd44156
|
|
--- /dev/null
|
|
+++ b/package/system/uvol/files/autopart.defaults
|
|
@@ -0,0 +1,127 @@
|
|
+#!/bin/sh
|
|
+
|
|
+. /lib/functions.sh
|
|
+. /lib/upgrade/common.sh
|
|
+. /usr/share/libubox/jshn.sh
|
|
+
|
|
+OWRT_VOLUMES=owrt-volumes
|
|
+
|
|
+load_partitions() {
|
|
+ local dev="$1"
|
|
+ json_init
|
|
+ json_load "$(sfdisk -J "$dev" 2>/dev/null)"
|
|
+ json_select "partitiontable" || return 1
|
|
+ return 0
|
|
+}
|
|
+
|
|
+get_partition_by_name_gpt() {
|
|
+ local label part parts node name
|
|
+ json_get_vars label
|
|
+ [ "$label" = "gpt" ] || return
|
|
+ json_select "partitions" || return
|
|
+ json_get_keys parts
|
|
+ for part in $parts; do
|
|
+ json_select "$part"
|
|
+ json_get_vars node name
|
|
+ if [ "$1" = "$name" ]; then
|
|
+ echo "$node"
|
|
+ break
|
|
+ fi
|
|
+ json_select ..
|
|
+ done
|
|
+ json_select ..
|
|
+}
|
|
+
|
|
+get_partition_by_type_mbr() {
|
|
+ local label part parts node type
|
|
+ json_get_vars label
|
|
+ [ "$label" = "dos" ] || return
|
|
+ json_select "partitions" || return
|
|
+ json_get_keys parts
|
|
+ for part in $parts; do
|
|
+ json_select "$part"
|
|
+ json_get_vars node type
|
|
+ if [ "$1" = "$type" ]; then
|
|
+ echo "$node"
|
|
+ break
|
|
+ fi
|
|
+ json_select ..
|
|
+ done
|
|
+ json_select ..
|
|
+}
|
|
+
|
|
+part_fixup() {
|
|
+ echo "write" | sfdisk --force -q -w never "$1" 1>/dev/null 2>/dev/null
|
|
+}
|
|
+
|
|
+get_free_area() {
|
|
+ local found=
|
|
+ sfdisk -q -F "$1" 2>/dev/null | while read -r start end sectors size; do
|
|
+ case $start in
|
|
+ *"Unpartitioned"* | *"Units:"* | *"Sector"* | *"Start"* )
|
|
+ continue
|
|
+ ;;
|
|
+ [0-9]*)
|
|
+ case "$size" in
|
|
+ *"M")
|
|
+ [ "${size%%M}" -lt 100 ] && continue
|
|
+ ;;
|
|
+ *"G" | *"T")
|
|
+ ;;
|
|
+ *"k" | *"b")
|
|
+ continue
|
|
+ ;;
|
|
+ esac
|
|
+ [ "$found" ] || echo "start=$start, size=$((end - start))"
|
|
+ found=1
|
|
+ ;;
|
|
+ esac
|
|
+ done
|
|
+}
|
|
+
|
|
+create_lvm_part() {
|
|
+ local disk="$1"
|
|
+ local freepart
|
|
+
|
|
+ freepart="$(get_free_area "$disk")"
|
|
+ if [ "$freepart" ]; then
|
|
+ echo "$freepart, type=lvm, name=$OWRT_VOLUMES" | sfdisk --force -w never -a "$disk" || return 1
|
|
+ partx -a "$disk" 1>/dev/null 2>/dev/null || true
|
|
+ return 0
|
|
+ else
|
|
+ return 1
|
|
+ fi
|
|
+}
|
|
+
|
|
+lvm_init() {
|
|
+ lvm pvcreate -f "$1"
|
|
+ lvm vgcreate "$2" "$1"
|
|
+ lvm vgs
|
|
+}
|
|
+
|
|
+autopart_init() {
|
|
+ local diskdev
|
|
+ local lvmpart
|
|
+ local diskserial diskhash
|
|
+
|
|
+ export_bootdevice && export_partdevice diskdev 0
|
|
+
|
|
+ [ "$diskdev" ] || return
|
|
+
|
|
+ [ -e "/sys/class/block/$diskdev/device/serial" ] && diskserial="$(cat "/sys/class/block/$diskdev/device/serial")"
|
|
+ [ -e "/sys/class/block/$diskdev/device/cid" ] && diskserial="$diskserial$(cat "/sys/class/block/$diskdev/device/cid")"
|
|
+ [ "$diskserial" ] || diskserial="$(cat /proc/sys/kernel/random/uuid)"
|
|
+ diskhash="$(echo "$diskserial" | sha256sum | cut -d' ' -f1)"
|
|
+
|
|
+ part_fixup "/dev/$diskdev"
|
|
+ create_lvm_part "/dev/$diskdev" || return
|
|
+ load_partitions "/dev/$diskdev" || return
|
|
+ lvmpart="$(get_partition_by_name_gpt "$OWRT_VOLUMES")"
|
|
+ [ "$lvmpart" ] || lvmpart="$(get_partition_by_type_mbr "8e")"
|
|
+ [ "$lvmpart" ] || return
|
|
+
|
|
+ lvm_init "$lvmpart" "${OWRT_VOLUMES}-${diskhash:0:16}"
|
|
+}
|
|
+
|
|
+autopart_init
|
|
+exit 0
|
|
diff --git a/package/system/uvol/files/common.sh b/package/system/uvol/files/common.sh
|
|
new file mode 100644
|
|
index 0000000000..e3b554e180
|
|
--- /dev/null
|
|
+++ b/package/system/uvol/files/common.sh
|
|
@@ -0,0 +1,83 @@
|
|
+#!/bin/sh
|
|
+
|
|
+UCI_SPOOLDIR="/var/spool/uvol"
|
|
+
|
|
+_uvol_init_spooldir() {
|
|
+ [ ! -d "$(dirname "$UCI_SPOOLDIR")" ] && mkdir -p "$(dirname "$UCI_SPOOLDIR")"
|
|
+ mkdir -m 0700 -p "$UCI_SPOOLDIR"
|
|
+}
|
|
+
|
|
+uvol_uci_add() {
|
|
+ local volname="$1"
|
|
+ local devname="$2"
|
|
+ local mode="$3"
|
|
+ local autofs=0
|
|
+ local target="/var/run/uvol/$volname"
|
|
+ local uuid uciname
|
|
+
|
|
+ [ "$mode" = "ro" ] && autofs=1
|
|
+ uciname="${volname//[-.]/_}"
|
|
+ uciname="${uciname//[!([:alnum:]_)]}"
|
|
+ uuid="$(/sbin/block info | grep "^$2" | xargs -n 1 echo | grep "^UUID=.*")"
|
|
+ [ "$uuid" ] || return 22
|
|
+ uuid="${uuid:5}"
|
|
+
|
|
+ case "$uciname" in
|
|
+ "_uxc")
|
|
+ target="/var/state/uxc"
|
|
+ ;;
|
|
+ "_"*)
|
|
+ return 1
|
|
+ ;;
|
|
+ esac
|
|
+
|
|
+ _uvol_init_spooldir
|
|
+ if [ -e "${UCI_SPOOLDIR}/remove-$1" ]; then
|
|
+ rm "${UCI_SPOOLDIR}/remove-$1"
|
|
+ fi
|
|
+
|
|
+ cat >"${UCI_SPOOLDIR}/add-$1" <<EOF
|
|
+set fstab.$uciname=mount
|
|
+set fstab.$uciname.uuid=$uuid
|
|
+set fstab.$uciname.target=$target
|
|
+set fstab.$uciname.options=$mode
|
|
+set fstab.$uciname.autofs=$autofs
|
|
+set fstab.$uciname.enabled=1
|
|
+EOF
|
|
+}
|
|
+
|
|
+uvol_uci_remove() {
|
|
+ local volname="$1"
|
|
+ local uciname
|
|
+
|
|
+ uciname="${volname//-/_}"
|
|
+ uciname="${uciname//[!([:alnum:]_)]}"
|
|
+ if [ -e "${UCI_SPOOLDIR}/add-$1" ]; then
|
|
+ rm "${UCI_SPOOLDIR}/add-$1"
|
|
+ return
|
|
+ fi
|
|
+ _uvol_init_spooldir
|
|
+ cat >"${UCI_SPOOLDIR}/remove-$1" <<EOF
|
|
+delete fstab.$uciname
|
|
+EOF
|
|
+}
|
|
+
|
|
+uvol_uci_commit() {
|
|
+ local volname="$1"
|
|
+ local ucibatch
|
|
+
|
|
+ for ucibatch in "${UCI_SPOOLDIR}/"*"-$volname"${volname+*} ; do
|
|
+ [ -e "$ucibatch" ] || break
|
|
+ uci batch < "$ucibatch"
|
|
+ [ $? -eq 0 ] && rm "$ucibatch"
|
|
+ done
|
|
+
|
|
+ uci commit fstab
|
|
+ return $?
|
|
+}
|
|
+
|
|
+uvol_uci_init() {
|
|
+ uci -q get fstab.@uvol[0] && return
|
|
+ uci add fstab uvol
|
|
+ uci set fstab.@uvol[-1].initialized=1
|
|
+}
|
|
diff --git a/package/system/uvol/files/lvm.sh b/package/system/uvol/files/lvm.sh
|
|
new file mode 100644
|
|
index 0000000000..95281194ba
|
|
--- /dev/null
|
|
+++ b/package/system/uvol/files/lvm.sh
|
|
@@ -0,0 +1,435 @@
|
|
+#!/bin/sh
|
|
+
|
|
+cmd="$1"
|
|
+shift
|
|
+
|
|
+if [ "$cmd" = "name" ]; then
|
|
+ echo "LVM"
|
|
+ return 0
|
|
+fi
|
|
+
|
|
+command -v lvm >/dev/null || return 1
|
|
+
|
|
+. /lib/functions.sh
|
|
+. /lib/functions/uvol.sh
|
|
+. /lib/upgrade/common.sh
|
|
+. /usr/share/libubox/jshn.sh
|
|
+
|
|
+export_bootdevice
|
|
+[ "$BOOTDEV_MAJOR" ] || return 1
|
|
+export_partdevice rootdev 0
|
|
+[ "$rootdev" ] || return 1
|
|
+
|
|
+case "$rootdev" in
|
|
+ mtd*|\
|
|
+ ram*|\
|
|
+ ubi*)
|
|
+ return 1
|
|
+esac
|
|
+
|
|
+lvm_cmd() {
|
|
+ local cmd="$1"
|
|
+ shift
|
|
+ LVM_SUPPRESS_FD_WARNINGS=1 lvm "$cmd" "$@"
|
|
+ return $?
|
|
+}
|
|
+
|
|
+pvs() {
|
|
+ lvm_cmd pvs --reportformat json --units b "$@"
|
|
+}
|
|
+
|
|
+vgs() {
|
|
+ lvm_cmd vgs --reportformat json --units b "$@"
|
|
+}
|
|
+
|
|
+lvs() {
|
|
+ lvm_cmd lvs --reportformat json --units b "$@"
|
|
+}
|
|
+
|
|
+freebytes() {
|
|
+ echo $((vg_free_count * vg_extent_size))
|
|
+}
|
|
+
|
|
+totalbytes() {
|
|
+ echo $((vg_extent_count * vg_extent_size))
|
|
+}
|
|
+
|
|
+existvol() {
|
|
+ [ "$1" ] || return 1
|
|
+ test -e "/dev/$vg_name/ro_$1" || test -e "/dev/$vg_name/rw_$1"
|
|
+ return $?
|
|
+}
|
|
+
|
|
+vg_name=
|
|
+exportpv() {
|
|
+ local reports rep pv pvs
|
|
+ vg_name=
|
|
+ json_init
|
|
+ json_load "$(pvs -o vg_name -S "pv_name=~^/dev/$rootdev.*\$")"
|
|
+ json_select report
|
|
+ json_get_keys reports
|
|
+ for rep in $reports; do
|
|
+ json_select "$rep"
|
|
+ json_select pv
|
|
+ json_get_keys pvs
|
|
+ for pv in $pvs; do
|
|
+ json_select "$pv"
|
|
+ json_get_vars vg_name
|
|
+ json_select ..
|
|
+ break
|
|
+ done
|
|
+ json_select ..
|
|
+ break
|
|
+ done
|
|
+}
|
|
+
|
|
+vg_extent_size=
|
|
+vg_extent_count=
|
|
+vg_free_count=
|
|
+exportvg() {
|
|
+ local reports rep vg vgs
|
|
+ vg_extent_size=
|
|
+ vg_extent_count=
|
|
+ vg_free_count=
|
|
+ json_init
|
|
+ json_load "$(vgs -o vg_extent_size,vg_extent_count,vg_free_count -S "vg_name=$vg_name")"
|
|
+ json_select report
|
|
+ json_get_keys reports
|
|
+ for rep in $reports; do
|
|
+ json_select "$rep"
|
|
+ json_select vg
|
|
+ json_get_keys vgs
|
|
+ for vg in $vgs; do
|
|
+ json_select "$vg"
|
|
+ json_get_vars vg_extent_size vg_extent_count vg_free_count
|
|
+ vg_extent_size=${vg_extent_size%B}
|
|
+ json_select ..
|
|
+ break
|
|
+ done
|
|
+ json_select ..
|
|
+ break
|
|
+ done
|
|
+}
|
|
+
|
|
+lv_active=
|
|
+lv_name=
|
|
+lv_full_name=
|
|
+lv_path=
|
|
+lv_dm_path=
|
|
+lv_size=
|
|
+exportlv() {
|
|
+ local reports rep lv lvs
|
|
+ lv_active=
|
|
+ lv_name=
|
|
+ lv_full_name=
|
|
+ lv_path=
|
|
+ lv_dm_path=
|
|
+ lv_size=
|
|
+ json_init
|
|
+
|
|
+ json_load "$(lvs -o lv_active,lv_name,lv_full_name,lv_size,lv_path,lv_dm_path -S "lv_name=~^[rw][owp]_$1\$ && vg_name=$vg_name")"
|
|
+ json_select report
|
|
+ json_get_keys reports
|
|
+ for rep in $reports; do
|
|
+ json_select "$rep"
|
|
+ json_select lv
|
|
+ json_get_keys lvs
|
|
+ for lv in $lvs; do
|
|
+ json_select "$lv"
|
|
+ json_get_vars lv_active lv_name lv_full_name lv_size lv_path lv_dm_path
|
|
+ lv_size=${lv_size%B}
|
|
+ json_select ..
|
|
+ break
|
|
+ done
|
|
+ json_select ..
|
|
+ break
|
|
+ done
|
|
+}
|
|
+
|
|
+getdev() {
|
|
+ local dms dm_name
|
|
+
|
|
+ for dms in /sys/devices/virtual/block/dm-* ; do
|
|
+ [ "$dms" = "/sys/devices/virtual/block/dm-*" ] && break
|
|
+ read -r dm_name < "$dms/dm/name"
|
|
+ [ $(basename "$lv_dm_path") = "$dm_name" ] && echo "$(basename "$dms")"
|
|
+ done
|
|
+}
|
|
+
|
|
+getuserdev() {
|
|
+ local dms dm_name
|
|
+ existvol "$1" || return 1
|
|
+ exportlv "$1"
|
|
+ getdev "$@"
|
|
+}
|
|
+
|
|
+getsize() {
|
|
+ exportlv "$1"
|
|
+ [ "$lv_size" ] && echo "$lv_size"
|
|
+}
|
|
+
|
|
+activatevol() {
|
|
+ exportlv "$1"
|
|
+ [ "$lv_path" ] || return 2
|
|
+ case "$lv_path" in
|
|
+ /dev/*/wo_*|\
|
|
+ /dev/*/wp_*)
|
|
+ return 22
|
|
+ ;;
|
|
+ *)
|
|
+ uvol_uci_commit "$1"
|
|
+ [ "$lv_active" = "active" ] && return 0
|
|
+ lvm_cmd lvchange -k n "$lv_full_name" || return $?
|
|
+ lvm_cmd lvchange -a y "$lv_full_name" || return $?
|
|
+ return 0
|
|
+ ;;
|
|
+ esac
|
|
+}
|
|
+
|
|
+disactivatevol() {
|
|
+ exportlv "$1"
|
|
+ local devname
|
|
+ [ "$lv_path" ] || return 2
|
|
+ case "$lv_path" in
|
|
+ /dev/*/wo_*|\
|
|
+ /dev/*/wp_*)
|
|
+ return 22
|
|
+ ;;
|
|
+ *)
|
|
+ [ "$lv_active" = "active" ] || return 0
|
|
+ devname="$(getdev "$1")"
|
|
+ [ "$devname" ] && /sbin/block umount "$devname"
|
|
+ lvm_cmd lvchange -a n "$lv_full_name"
|
|
+ lvm_cmd lvchange -k y "$lv_full_name" || return $?
|
|
+ return 0
|
|
+ ;;
|
|
+ esac
|
|
+}
|
|
+
|
|
+getstatus() {
|
|
+ exportlv "$1"
|
|
+ [ "$lv_full_name" ] || return 2
|
|
+ existvol "$1" || return 1
|
|
+ return 0
|
|
+}
|
|
+
|
|
+createvol() {
|
|
+ local mode lvmode ret
|
|
+ local volsize=$(($2))
|
|
+ [ "$volsize" ] || return 22
|
|
+ exportlv "$1"
|
|
+ [ "$lv_size" ] && return 17
|
|
+ size_ext=$((volsize / vg_extent_size))
|
|
+ [ $((size_ext * vg_extent_size)) -lt $volsize ] && size_ext=$((size_ext + 1))
|
|
+
|
|
+ case "$3" in
|
|
+ ro|wo)
|
|
+ lvmode=r
|
|
+ mode=wo
|
|
+ ;;
|
|
+ rw)
|
|
+ lvmode=rw
|
|
+ mode=wp
|
|
+ ;;
|
|
+ *)
|
|
+ return 22
|
|
+ ;;
|
|
+ esac
|
|
+
|
|
+ lvm_cmd lvcreate -p "$lvmode" -a n -y -W n -Z n -n "${mode}_$1" -l "$size_ext" "$vg_name" || return $?
|
|
+ ret=$?
|
|
+ if [ ! $ret -eq 0 ] || [ "$lvmode" = "r" ]; then
|
|
+ return $ret
|
|
+ fi
|
|
+ exportlv "$1"
|
|
+ [ "$lv_full_name" ] || return 22
|
|
+ lvm_cmd lvchange -a y "$lv_full_name" || return $?
|
|
+ if [ "$lv_size" -gt $(( 100 * 1024 * 1024 )) ]; then
|
|
+ mkfs.f2fs -f -l "$1" "$lv_path"
|
|
+ ret=$?
|
|
+ [ $ret != 0 ] && [ $ret != 134 ] && {
|
|
+ lvm_cmd lvchange -a n "$lv_full_name" || return $?
|
|
+ return $ret
|
|
+ }
|
|
+ else
|
|
+ mke2fs -F -L "$1" "$lv_path" || {
|
|
+ ret=$?
|
|
+ lvm_cmd lvchange -a n "$lv_full_name" || return $?
|
|
+ return $ret
|
|
+ }
|
|
+ fi
|
|
+ uvol_uci_add "$1" "/dev/$(getdev "$1")" "rw"
|
|
+ lvm_cmd lvchange -a n "$lv_full_name" || return $?
|
|
+ lvm_cmd lvrename "$vg_name" "wp_$1" "rw_$1" || return $?
|
|
+ return 0
|
|
+}
|
|
+
|
|
+removevol() {
|
|
+ exportlv "$1"
|
|
+ [ "$lv_full_name" ] || return 2
|
|
+ [ "$lv_active" = "active" ] && return 16
|
|
+ lvm_cmd lvremove -y "$lv_full_name" || return $?
|
|
+ uvol_uci_remove "$1"
|
|
+ uvol_uci_commit "$1"
|
|
+}
|
|
+
|
|
+updatevol() {
|
|
+ exportlv "$1"
|
|
+ [ "$lv_full_name" ] || return 2
|
|
+ [ "$lv_size" -ge "$2" ] || return 27
|
|
+ case "$lv_path" in
|
|
+ /dev/*/wo_*)
|
|
+ lvm_cmd lvchange -p rw "$lv_full_name" || return $?
|
|
+ lvm_cmd lvchange -a y "$lv_full_name" || return $?
|
|
+ dd of="$lv_path"
|
|
+ uvol_uci_add "$1" "/dev/$(getdev "$1")" "ro"
|
|
+ lvm_cmd lvchange -a n "$lv_full_name" || return $?
|
|
+ lvm_cmd lvchange -p r "$lv_full_name" || return $?
|
|
+ lvm_cmd lvrename "$lv_full_name" "${lv_full_name%%/*}/ro_$1" || return $?
|
|
+ return 0
|
|
+ ;;
|
|
+ default)
|
|
+ return 22
|
|
+ ;;
|
|
+ esac
|
|
+}
|
|
+
|
|
+listvols() {
|
|
+ local reports rep lv lvs lv_name lv_size lv_mode volname
|
|
+ volname=${1:-.*}
|
|
+ json_init
|
|
+ json_load "$(lvs -o lv_name,lv_size -S "lv_name=~^[rw][owp]_$volname\$ && vg_name=$vg_name")"
|
|
+ json_select report
|
|
+ json_get_keys reports
|
|
+ for rep in $reports; do
|
|
+ json_select "$rep"
|
|
+ json_select lv
|
|
+ json_get_keys lvs
|
|
+ for lv in $lvs; do
|
|
+ json_select "$lv"
|
|
+ json_get_vars lv_name lv_size
|
|
+ lv_mode="${lv_name:0:2}"
|
|
+ lv_name="${lv_name:3}"
|
|
+ lv_size=${lv_size%B}
|
|
+ echo "$lv_name $lv_mode $lv_size"
|
|
+ json_select ..
|
|
+ done
|
|
+ json_select ..
|
|
+ break
|
|
+ done
|
|
+}
|
|
+
|
|
+
|
|
+detect() {
|
|
+ local reports rep lv lvs lv_name lv_full_name lv_mode volname devname lv_skip_activation
|
|
+ local temp_up=""
|
|
+
|
|
+ json_init
|
|
+ json_load "$(lvs -o lv_full_name -S "lv_name=~^[rw][owp]_.*\$ && vg_name=$vg_name && lv_skip_activation!=0")"
|
|
+ json_select report
|
|
+ json_get_keys reports
|
|
+ for rep in $reports; do
|
|
+ json_select "$rep"
|
|
+ json_select lv
|
|
+ json_get_keys lvs
|
|
+ for lv in $lvs; do
|
|
+ json_select "$lv"
|
|
+ json_get_vars lv_full_name
|
|
+ echo "lvchange -a y $lv_full_name"
|
|
+ lvm_cmd lvchange -k n "$lv_full_name"
|
|
+ lvm_cmd lvchange -a y "$lv_full_name"
|
|
+ temp_up="$temp_up $lv_full_name"
|
|
+ json_select ..
|
|
+ done
|
|
+ json_select ..
|
|
+ break
|
|
+ done
|
|
+ sleep 1
|
|
+
|
|
+ uvol_uci_init
|
|
+
|
|
+ json_init
|
|
+ json_load "$(lvs -o lv_name,lv_dm_path -S "lv_name=~^[rw][owp]_.*\$ && vg_name=$vg_name")"
|
|
+ json_select report
|
|
+ json_get_keys reports
|
|
+ for rep in $reports; do
|
|
+ json_select "$rep"
|
|
+ json_select lv
|
|
+ json_get_keys lvs
|
|
+ for lv in $lvs; do
|
|
+ json_select "$lv"
|
|
+ json_get_vars lv_name lv_dm_path
|
|
+ lv_mode="${lv_name:0:2}"
|
|
+ lv_name="${lv_name:3}"
|
|
+ echo uvol_uci_add "$lv_name" "/dev/$(getdev "$lv_name")" "$lv_mode"
|
|
+ uvol_uci_add "$lv_name" "/dev/$(getdev "$lv_name")" "$lv_mode"
|
|
+ json_select ..
|
|
+ done
|
|
+ json_select ..
|
|
+ break
|
|
+ done
|
|
+
|
|
+ uvol_uci_commit
|
|
+
|
|
+ for lv_full_name in $temp_up; do
|
|
+ echo "lvchange -a n $lv_full_name"
|
|
+ lvm_cmd lvchange -a n "$lv_full_name"
|
|
+ lvm_cmd lvchange -k y "$lv_full_name"
|
|
+ done
|
|
+}
|
|
+
|
|
+boot() {
|
|
+ true ; # nothing to do, lvm does it all for us
|
|
+}
|
|
+
|
|
+exportpv
|
|
+exportvg
|
|
+
|
|
+case "$cmd" in
|
|
+ align)
|
|
+ echo "$vg_extent_size"
|
|
+ ;;
|
|
+ free)
|
|
+ freebytes
|
|
+ ;;
|
|
+ total)
|
|
+ totalbytes
|
|
+ ;;
|
|
+ detect)
|
|
+ detect
|
|
+ ;;
|
|
+ boot)
|
|
+ boot
|
|
+ ;;
|
|
+ list)
|
|
+ listvols "$@"
|
|
+ ;;
|
|
+ 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/package/system/uvol/files/ubi.sh b/package/system/uvol/files/ubi.sh
|
|
new file mode 100644
|
|
index 0000000000..b0b363d7ed
|
|
--- /dev/null
|
|
+++ b/package/system/uvol/files/ubi.sh
|
|
@@ -0,0 +1,337 @@
|
|
+#!/bin/sh
|
|
+
|
|
+cmd="$1"
|
|
+shift
|
|
+
|
|
+if [ "$cmd" = "name" ]; then
|
|
+ echo "UBI"
|
|
+ return 0
|
|
+fi
|
|
+
|
|
+test -e /sys/class/ubi/version || return 0
|
|
+read -r 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 -r ebsize < "/sys/devices/virtual/ubi/${ubidev}/eraseblock_size"
|
|
+
|
|
+. /lib/functions/uvol.sh
|
|
+
|
|
+freebytes() {
|
|
+ read -r availeb < "/sys/devices/virtual/ubi/${ubidev}/avail_eraseblocks"
|
|
+ echo $((availeb * ebsize))
|
|
+}
|
|
+
|
|
+totalbytes() {
|
|
+ read -r totaleb < "/sys/devices/virtual/ubi/${ubidev}/total_eraseblocks"
|
|
+ echo $((totaleb * ebsize))
|
|
+}
|
|
+
|
|
+getdev() {
|
|
+ local voldir volname
|
|
+ for voldir in "/sys/devices/virtual/ubi/${ubidev}/${ubidev}_"*; do
|
|
+ read -r volname < "${voldir}/name"
|
|
+ case "$volname" in
|
|
+ uvol-[rw][owpd]-$1)
|
|
+ basename "$voldir"
|
|
+ break
|
|
+ ;;
|
|
+ *)
|
|
+ continue
|
|
+ ;;
|
|
+ esac
|
|
+ done
|
|
+}
|
|
+
|
|
+vol_is_mode() {
|
|
+ local voldev="$1"
|
|
+ local volname
|
|
+ read -r volname < "/sys/devices/virtual/ubi/${ubidev}/${voldev}/name"
|
|
+ case "$volname" in
|
|
+ uvol-$2-*)
|
|
+ return 0
|
|
+ ;;
|
|
+ esac
|
|
+ return 1
|
|
+}
|
|
+
|
|
+getstatus() {
|
|
+ local voldev
|
|
+ voldev="$(getdev "$@")"
|
|
+ [ "$voldev" ] || return 2
|
|
+ vol_is_mode "$voldev" wo && return 22
|
|
+ vol_is_mode "$voldev" wp && return 16
|
|
+ vol_is_mode "$voldev" wd && return 1
|
|
+ vol_is_mode "$voldev" ro && [ ! -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
|
|
+ voldev="$(getdev "$@")"
|
|
+ [ "$voldev" ] || return 2
|
|
+ if vol_is_mode "$voldev" ro ; then
|
|
+ echo "/dev/ubiblock${voldev:3}"
|
|
+ elif vol_is_mode "$voldev" rw ; then
|
|
+ echo "/dev/$voldev"
|
|
+ fi
|
|
+}
|
|
+
|
|
+mkubifs() {
|
|
+ local tmp_mp
|
|
+ tmp_mp="$(mktemp -d)"
|
|
+ mount -t ubifs "$1" "$tmp_mp" || return $?
|
|
+ umount "$tmp_mp" || return $?
|
|
+ rmdir "$tmp_mp" || return $?
|
|
+ return 0
|
|
+}
|
|
+
|
|
+createvol() {
|
|
+ local mode ret voldev
|
|
+ voldev=$(getdev "$@")
|
|
+ [ "$voldev" ] && return 17
|
|
+ case "$3" in
|
|
+ ro|wo)
|
|
+ mode=wo
|
|
+ ;;
|
|
+ rw)
|
|
+ mode=wp
|
|
+ ;;
|
|
+ *)
|
|
+ return 22
|
|
+ ;;
|
|
+ esac
|
|
+ ubimkvol "/dev/$ubidev" -N "uvol-$mode-$1" -s "$2" || return $?
|
|
+ ret=$?
|
|
+ [ $ret -eq 0 ] || return $ret
|
|
+ voldev="$(getdev "$@")"
|
|
+ ubiupdatevol -t "/dev/$voldev" || return $?
|
|
+ [ "$mode" = "wp" ] || return 0
|
|
+ mkubifs "/dev/$voldev" || return $?
|
|
+ uvol_uci_add "$1" "/dev/$voldev" "rw"
|
|
+ ubirename "/dev/$ubidev" "uvol-wp-$1" "uvol-wd-$1" || return $?
|
|
+}
|
|
+
|
|
+removevol() {
|
|
+ local voldev volnum
|
|
+ voldev=$(getdev "$@")
|
|
+ [ "$voldev" ] || return 2
|
|
+ vol_is_mode "$voldev" rw && return 16
|
|
+ vol_is_mode "$voldev" ro && return 16
|
|
+ volnum="${voldev#${ubidev}_}"
|
|
+ ubirmvol "/dev/$ubidev" -n "$volnum" || return $?
|
|
+ uvol_uci_remove "$1"
|
|
+ uvol_uci_commit "$1"
|
|
+}
|
|
+
|
|
+block_hotplug() {
|
|
+ export ACTION="$1"
|
|
+ export DEVNAME="$2"
|
|
+ /sbin/block hotplug
|
|
+}
|
|
+
|
|
+activatevol() {
|
|
+ local voldev
|
|
+ voldev="$(getdev "$@")"
|
|
+ [ "$voldev" ] || return 2
|
|
+ vol_is_mode "$voldev" rw && return 0
|
|
+ vol_is_mode "$voldev" ro && return 0
|
|
+ vol_is_mode "$voldev" wo && return 22
|
|
+ vol_is_mode "$voldev" wp && return 16
|
|
+ uvol_uci_commit "$1"
|
|
+ if vol_is_mode "$voldev" rd; then
|
|
+ ubirename "/dev/$ubidev" "uvol-rd-$1" "uvol-ro-$1" || return $?
|
|
+ ubiblock --create "/dev/$voldev" || return $?
|
|
+ return 0
|
|
+ elif vol_is_mode "$voldev" wd; then
|
|
+ ubirename "/dev/$ubidev" "uvol-wd-$1" "uvol-rw-$1" || return $?
|
|
+ block_hotplug add "$voldev"
|
|
+ return 0
|
|
+ fi
|
|
+}
|
|
+
|
|
+disactivatevol() {
|
|
+ local voldev
|
|
+ voldev="$(getdev "$@")"
|
|
+ [ "$voldev" ] || return 2
|
|
+ vol_is_mode "$voldev" rd && return 0
|
|
+ vol_is_mode "$voldev" wd && return 0
|
|
+ vol_is_mode "$voldev" wo && return 22
|
|
+ vol_is_mode "$voldev" wp && return 16
|
|
+ if vol_is_mode "$voldev" ro; then
|
|
+ /sbin/block umount "ubiblock${voldev:3}"
|
|
+ ubiblock --remove "/dev/$voldev"
|
|
+ ubirename "/dev/$ubidev" "uvol-ro-$1" "uvol-rd-$1" || return $?
|
|
+ return 0
|
|
+ elif vol_is_mode "$voldev" rw; then
|
|
+ /sbin/block umount "$voldev"
|
|
+ ubirename "/dev/$ubidev" "uvol-rw-$1" "uvol-wd-$1" || return $?
|
|
+ block_hotplug remove "$voldev"
|
|
+ return 0
|
|
+ fi
|
|
+}
|
|
+
|
|
+updatevol() {
|
|
+ local voldev
|
|
+ voldev="$(getdev "$@")"
|
|
+ [ "$voldev" ] || return 2
|
|
+ [ "$2" ] || return 22
|
|
+ vol_is_mode "$voldev" wo || return 22
|
|
+ ubiupdatevol -s "$2" "/dev/$voldev" -
|
|
+ ubiblock --create "/dev/$voldev"
|
|
+ uvol_uci_add "$1" "/dev/ubiblock${voldev:3}" "ro"
|
|
+ ubiblock --remove "/dev/$voldev"
|
|
+ ubirename "/dev/$ubidev" "uvol-wo-$1" "uvol-rd-$1"
|
|
+}
|
|
+
|
|
+listvols() {
|
|
+ local volname volmode volsize
|
|
+ for voldir in "/sys/devices/virtual/ubi/${ubidev}/${ubidev}_"*; do
|
|
+ read -r volname < "$voldir/name"
|
|
+ case "$volname" in
|
|
+ uvol-[rw][wod]*)
|
|
+ read -r volsize < "$voldir/data_bytes"
|
|
+ ;;
|
|
+ *)
|
|
+ continue
|
|
+ ;;
|
|
+ esac
|
|
+ volmode="${volname:5:2}"
|
|
+ volname="${volname:8}"
|
|
+ echo "$volname $volmode $volsize"
|
|
+ done
|
|
+}
|
|
+
|
|
+bootvols() {
|
|
+ local volname volmode volsize voldev fstype
|
|
+ for voldir in "/sys/devices/virtual/ubi/${ubidev}/${ubidev}_"*; do
|
|
+ read -r volname < "$voldir/name"
|
|
+ voldev="$(basename "$voldir")"
|
|
+ fstype=
|
|
+ case "$volname" in
|
|
+ uvol-ro-*)
|
|
+ ubiblock --create "/dev/$voldev" || return $?
|
|
+ ;;
|
|
+ *)
|
|
+ continue
|
|
+ ;;
|
|
+ esac
|
|
+ volmode="${volname:5:2}"
|
|
+ volname="${volname:8}"
|
|
+ done
|
|
+}
|
|
+
|
|
+detect() {
|
|
+ local volname voldev volmode voldev fstype tmpdev=""
|
|
+ for voldir in "/sys/devices/virtual/ubi/${ubidev}/${ubidev}_"*; do
|
|
+ read -r volname < "$voldir/name"
|
|
+ voldev="$(basename "$voldir")"
|
|
+ fstype=
|
|
+ case "$volname" in
|
|
+ uvol-r[od]-*)
|
|
+ if ! [ -e "/dev/ubiblock${voldev:3}" ]; then
|
|
+ ubiblock --create "/dev/$voldev" || return $?
|
|
+ fi
|
|
+ case "$volname" in
|
|
+ uvol-rd-*)
|
|
+ tmpdev="$tmpdev $voldev"
|
|
+ ;;
|
|
+ esac
|
|
+ ;;
|
|
+ *)
|
|
+ continue
|
|
+ ;;
|
|
+ esac
|
|
+ volmode="${volname:5:2}"
|
|
+ volname="${volname:8}"
|
|
+ done
|
|
+
|
|
+ uvol_uci_init
|
|
+
|
|
+ for voldir in "/sys/devices/virtual/ubi/${ubidev}/${ubidev}_"*; do
|
|
+ read -r volname < "$voldir/name"
|
|
+ voldev="$(basename "$voldir")"
|
|
+ case "$volname" in
|
|
+ uvol-[rw][wod]*)
|
|
+ true
|
|
+ ;;
|
|
+ *)
|
|
+ continue
|
|
+ ;;
|
|
+ esac
|
|
+ volmode="${volname:5:2}"
|
|
+ volname="${volname:8}"
|
|
+ case "$volmode" in
|
|
+ "ro" | "rd")
|
|
+ uvol_uci_add "$volname" "/dev/ubiblock${voldev:3}" "ro"
|
|
+ ;;
|
|
+ "rw" | "wd")
|
|
+ uvol_uci_add "$volname" "/dev/${voldev}" "rw"
|
|
+ ;;
|
|
+ esac
|
|
+ done
|
|
+
|
|
+ uvol_uci_commit
|
|
+
|
|
+ for voldev in $tmpdev ; do
|
|
+ ubiblock --remove "/dev/$voldev" || return $?
|
|
+ done
|
|
+}
|
|
+
|
|
+case "$cmd" in
|
|
+ align)
|
|
+ echo "$ebsize"
|
|
+ ;;
|
|
+ free)
|
|
+ freebytes
|
|
+ ;;
|
|
+ total)
|
|
+ totalbytes
|
|
+ ;;
|
|
+ detect)
|
|
+ detect
|
|
+ ;;
|
|
+ boot)
|
|
+ bootvols
|
|
+ ;;
|
|
+ list)
|
|
+ listvols "$@"
|
|
+ ;;
|
|
+ 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/package/system/uvol/files/uvol b/package/system/uvol/files/uvol
|
|
new file mode 100644
|
|
index 0000000000..4ecd2e165a
|
|
--- /dev/null
|
|
+++ b/package/system/uvol/files/uvol
|
|
@@ -0,0 +1,52 @@
|
|
+#!/bin/sh
|
|
+
|
|
+# uvol prototype
|
|
+# future development roadmap (aka. to-do):
|
|
+# * re-implement in C (use libubox, execve lvm/ubi*)
|
|
+# * hash to validate volume while writing
|
|
+# * add atomic batch processing for use by container/package manager
|
|
+
|
|
+if [ -z "$1" ]; then cat <<EOF
|
|
+uvol storage volume manager
|
|
+
|
|
+syntax: uvol command ...
|
|
+
|
|
+commands:
|
|
+ boot get active volumes ready (called on boot)
|
|
+ free show number of bytes available
|
|
+ total show total number of bytes
|
|
+ align show sector size in bytes
|
|
+ list [volname] list volumes
|
|
+ create volname size type create new volume
|
|
+ size: in bytes
|
|
+ type: 'ro' or 'rw'
|
|
+ remove volname delete volume
|
|
+ device volname show block device for mounting
|
|
+ size volname show size of volume
|
|
+ up volname get volume ready for mounting
|
|
+ down volname take volume down after unmounting
|
|
+ status volname return status of volume
|
|
+ return code: 0 - volume is ready for use
|
|
+ 1 - volume is not ready for use
|
|
+ 2 - volume doesn'y exist
|
|
+ write volname size write to volume from stdin, size in bytes
|
|
+EOF
|
|
+ return 22
|
|
+fi
|
|
+
|
|
+uvol_backend=
|
|
+backends_tried=
|
|
+
|
|
+for backend in /usr/libexec/uvol/*.sh; do
|
|
+ total=$($backend total)
|
|
+ backends_tried="$backends_tried $($backend name)"
|
|
+ [ "$total" ] && uvol_backend=$backend
|
|
+done
|
|
+
|
|
+if [ -z "$uvol_backend" ]; then
|
|
+ echo "No backend available. (tried:$backends_tried)"
|
|
+ echo "To setup devices with block storage install 'autopart'."
|
|
+ return 2
|
|
+fi
|
|
+
|
|
+flock -x /tmp/run/uvol.lock "$uvol_backend" "$@"
|
|
diff --git a/package/system/uvol/files/uvol.defaults b/package/system/uvol/files/uvol.defaults
|
|
new file mode 100644
|
|
index 0000000000..cbd53a3e4e
|
|
--- /dev/null
|
|
+++ b/package/system/uvol/files/uvol.defaults
|
|
@@ -0,0 +1,3 @@
|
|
+#!/bin/sh
|
|
+
|
|
+uci -q get fstab.@uvol[0].initialized >/dev/null || uvol detect || true
|
|
diff --git a/package/system/uvol/files/uvol.init b/package/system/uvol/files/uvol.init
|
|
new file mode 100644
|
|
index 0000000000..1f6e2aac08
|
|
--- /dev/null
|
|
+++ b/package/system/uvol/files/uvol.init
|
|
@@ -0,0 +1,23 @@
|
|
+#!/bin/sh /etc/rc.common
|
|
+
|
|
+START=99
|
|
+USE_PROCD=1
|
|
+NAME=uvol
|
|
+PROG=/usr/sbin/uvol
|
|
+
|
|
+start_service() {
|
|
+ [ "${__BOOT_UVOL}" = "1" ] && return 0
|
|
+ procd_open_instance "$NAME"
|
|
+ procd_set_param command "$PROG" boot
|
|
+ procd_close_instance
|
|
+}
|
|
+
|
|
+boot() {
|
|
+ __BOOT_UVOL=1
|
|
+ start
|
|
+}
|
|
+
|
|
+service_triggers() {
|
|
+ procd_add_raw_trigger "mount.ready" 200 /etc/init.d/uvol start
|
|
+}
|
|
+
|
|
--
|
|
2.25.1
|
|
|