packages/utils/uvol/files/lvm.sh
Daniel Golle 1337c44026
uvol: fix list output on LVM backend
'uvol list' was broken when introducing support for the hidden volumes.
Fix that by not using 'continue' keyword to break the loop (as that
lead to skipping 'json_select ..') and using if-clause instead.

Signed-off-by: Daniel Golle <daniel@makrotopia.org>
2022-03-22 14:19:35 +00:00

460 lines
8.6 KiB
Bash

#!/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() {
vg_name=
config_load fstab
local uvolsect="$(config_foreach echo uvol)"
[ -n "$uvolsect" ] && config_get vg_name "$uvolsect" vg_name
[ -n "$vg_name" ] && return
local reports rep pv pvs
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" ] && 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" ] && umount "/dev/$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 json_output json_notfirst
if [ "$1" = "-j" ]; then
json_output=1
echo "["
shift
fi
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}
if [ "${lv_name:0:1}" != "." ]; then
if [ "$json_output" = "1" ]; then
[ "$json_notfirst" = "1" ] && echo ","
echo -e "\t{"
echo -e "\t\t\"name\": \"$lv_name\","
echo -e "\t\t\"mode\": \"$lv_mode\","
echo -e "\t\t\"size\": $lv_size"
echo -n -e "\t}"
json_notfirst=1
else
echo "$lv_name $lv_mode $lv_size"
fi
fi
json_select ..
done
json_select ..
break
done
if [ "$json_output" = "1" ]; then
[ "$json_notfirst" = "1" ] && echo
echo "]"
fi
}
detect() {
local reports rep lv lvs lv_name lv_full_name lv_mode volname devname
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