summaryrefslogtreecommitdiffstats
path: root/modules/fs/path.inc
diff options
context:
space:
mode:
Diffstat (limited to 'modules/fs/path.inc')
-rw-r--r--modules/fs/path.inc112
1 files changed, 112 insertions, 0 deletions
diff --git a/modules/fs/path.inc b/modules/fs/path.inc
new file mode 100644
index 0000000..f3a041b
--- /dev/null
+++ b/modules/fs/path.inc
@@ -0,0 +1,112 @@
+#!/bin/ash
+
+DM_STATE_FILE="/run/openslx/dmsetup.state"
+readonly DM_STATE_FILE
+
+# Return the device corresponding to the given path, or
+# empty if it's not mounted from a device (tmpfs, cifs, ...)
+fs_path_getdev() {
+ local _dev
+ _dev="$( df -P "$1" | awk '$1 ~ "^/dev/" {print $1}' )"
+ [ -n "$_dev" ] || return 1
+ [ -b "$_dev" ] || return 1
+ printf "%s" "$_dev"
+}
+
+# Return base mount point of given path
+# eg. call with "/mnt/nfs/temp/data", returns "/mnt/nfs"
+fs_path_getmountpoint() {
+ local _mp
+ _mp="$( df -P "$1" | awk '$6 ~ "^/" {print $6}' )"
+ [ -n "$_mp" ] || return 1
+ [ -d "$_mp" ] || return 1
+ printf "%s" "$_mp"
+}
+
+# Get fstype of given directory
+fs_path_gettype() {
+ local _mp
+ _mp="$( df -P "$1" | awk '$6 ~ "^/" {print $6}' )"
+ [ -n "$_mp" ] || return 1
+ [ -d "$_mp" ] || return 1
+ awk '$2 == "'"$_mp"'" {print $3}' '/proc/mounts'
+}
+
+# Helper to check whether given directory resides in RAM, either
+# by being mounted as tmpfs or not mounted at all in which case
+# we assume the same. Returns 0 if so, 1 if otherwise backed,
+# 2 when errors occur.
+fs_path_isvolatile() {
+ [ -z "$1" ] && return 2
+ local _dev _mp
+ _dev="$(fs_path_getdev "$1")"
+ [ -z "$_dev" ] && return 0 # No result, assume tmpfs
+ [ "$_dev" = "${_dev#/dev/zram}" ] || return 0 # zram is in RAM, like tmpfs
+ [ "$_dev" != "${_dev#/dev/mapper/}" ] || return 1 # Doesn't start with /dev/mapper, assume some kind of storage
+ [ -s "$DM_STATE_FILE" ] || return 2 # No point in continuing
+ _mp="$(fs_path_getmountpoint "$1")"
+ [ -z "$_mp" ] && return 2
+ # it is a device mapper device, check if it was setup in dracut's initramfs.
+ grep -qE "^$( regex_escape "${_dev}" )\s+$( regex_escape "${_mp}" )\s+type=0" "$DM_STATE_FILE"
+}
+
+# Return free/total space at given path, in KiB.
+# If the given path is backed by a thin pool, snapshot, etc.
+# it returns a conservative estimate, considering the remaining
+# space of the backing device.
+# Returns "<free> <total>"
+fs_path_space() {
+ [ -z "$1" ] && return 1
+ local _free _total _dev _type _id _name _bs _tmp _tfree _ttotal
+ _type="$( fs_path_gettype "$1" )"
+ [ -z "$_type" ] && return 1
+ _free="$( df -P "$1" | awk '$6 ~ "^/" {print $4 " " $2}' )"
+ case "$_type" in # EASY!
+ tmpfs|nfs*|cifs)
+ printf "%s" "$_free"
+ return
+ esac
+ _dev="$( fs_path_getdev "$1" )"
+ if [ "$_dev" = "${_dev#/dev/mapper/}" ]; then # does *NOT* start with /dev/mapper, assume not device mapped
+ # In case we start using aufs again, check if it needs special handling...
+ printf "%s" "$_free"
+ return
+ fi
+ # Split, since we might need to do Min()
+ _total="${_free#* }"
+ _free="${_free% *}"
+ _type="$( dmsetup status "$_dev" | awk '{print $3}' )"
+ _tfree=0
+ _ttotal=0
+ case "$_type" in
+ snapshot)
+ # Field 4 is used/total in sectors of 512 byte, so divide by two for KiB
+ _tmp="$( dmsetup status "$_dev" | awk '{split($4, a, "/"); print (a[2] - a[1]) / 2 " " a[2] / 2}' )"
+ _tfree="${_tmp% *}"
+ _ttotal="${_tmp#* }"
+ ;;
+ thin)
+ # Determine matching pool
+ _id="$( dmsetup table "$_dev" | awk '{print $4}' )"
+ if [ -n "$_id" ]; then
+ _name="$( cat "/sys/dev/block/${_id}/dm/name" )"
+ if [ -n "$_name" ]; then
+ # Get data block size (in sectors of 512 byte)
+ _bs="$( dmsetup table "$_name" | awk '{print $6}' )"
+ if [ "$_bs" -gt 0 ]; then
+ # Field 6 is used/total (in data blocks), so transform into KiB
+ _tmp="$( dmsetup status "$_name" | awk -v "bs=$_bs" '{split($6, a, "/"); print ((a[2] - a[1]) / 2) * bs " " (a[2] / 2) * bs}' )"
+ _tfree="${_tmp% *}"
+ _ttotal="${_tmp#* }"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ if [ "$_tfree" -ge 0 ] && [ "$_ttotal" -gt 0 ]; then
+ [ "$_tfree" -lt "$_free" ] && _free="$_tfree"
+ [ "$_ttotal" -lt "$_total" ] && _total="$_ttotal"
+ fi
+ printf "%s" "$_free $_total"
+}
+