File: //usr/local/ssl/sbin/prl_fstat
#!/bin/bash
#
# prl_fstat - gather mounted filesystems statistics
#
# (c) 2015. Parallels IP Holdings GmbH. All rights reserved.
# SCSI host index -> bus name mapping
declare -a HOST_BUS_MAP
# SCSI bus name -> starting host offset mapping
declare -A BUS_OFFSET_MAP
init_scsi_disk_types() {
for host in $(find /sys/class/scsi_host/ -type l); do
local bus_type="-"
local tmp="$(basename "$(readlink "$host")")"
local index=${tmp#host}
case "$(cat "$host"/proc_name)" in
BusLogic)
# only BusLogic SCSI interface is available for
# Linux guests
bus_type="scsi"
;;
ata*)
bus_type="ide"
;;
sata|ahci)
bus_type="sata"
;;
esac
HOST_BUS_MAP[$index]="$bus_type"
done
BUS_OFFSET_MAP[ide]=${#HOST_BUS_MAP[@]}
BUS_OFFSET_MAP[sata]=${#HOST_BUS_MAP[@]}
BUS_OFFSET_MAP[scsi]=${#HOST_BUS_MAP[@]}
BUS_OFFSET_MAP[-]=${#HOST_BUS_MAP[@]}
for host in "${!HOST_BUS_MAP[@]}"; do
bus=${HOST_BUS_MAP[$host]}
[[ ${BUS_OFFSET_MAP[$bus]} -gt $host ]] \
&& BUS_OFFSET_MAP[$bus]=$host
done
}
get_disk_interface() {
IFS=: read -a hctl <<< \
"$(basename "$(readlink /sys/block/"$1"/device)")"
local bus="${HOST_BUS_MAP[${hctl[0]}]}"
local offset="${BUS_OFFSET_MAP[$bus]}"
local position=""
case $bus in
sata)
position="$((${hctl[0]}-$offset))"
;;
scsi)
position="${hctl[2]}"
;;
ide)
position="$(((${hctl[0]} - $offset) * 2 + ${hctl[2]}))"
esac
echo -n "$bus$position"
}
get_swap_stats() {
echo "$(cat /proc/swaps | tail -n +2 | awk '{print $1,$3,$4}')" | \
while read dev total used; do
local name="$(lsblk --output NAME --nodeps --noheadings --raw \
"$dev" 2>/dev/null)"
[[ $? -ne 0 ]] && exit 2
if [ "$name" == "$1" ]; then
echo "$total $(($total - $used))"
break
fi
done
}
get_excluded_block_devices() {
local excluded=""
local block=0
while read major name; do
if [[ $major == Block ]]; then
block=1
continue
fi
if [[ $block -eq 1 && -n $name && $name != sd ]]; then
[[ -n $excluded ]] && excluded+=","
excluded+="$major"
fi
[[ $major == Character ]] && block=0
done <<< "$(cat /proc/devices)"
echo "$excluded"
}
get_fs_statistics() {
LANG=C
local -A mounted # device -> mountpoint
local -A disks # mountpoint -> "disk1 disk2 disk3"
init_scsi_disk_types &>/dev/null
local output="$(lsblk --exclude "$(get_excluded_block_devices)"\
--output NAME,MOUNTPOINT --noheadings --raw 2>/dev/null)"
[[ $? -ne 0 ]] && exit 1
local cur=""
while read name mountpoint; do
if [[ $name =~ ^sd[[:alpha:]]{1,2}$ ]]; then
cur="$name"
fi
if [[ -n "$mountpoint" ]]; then
mounted[$name]="$mountpoint"
local iface="$(get_disk_interface $cur)"
[[ "$iface" != - ]] && \
disks[$mountpoint]+="$iface "
fi
done <<< "$output"
for device in ${!mounted[@]}; do
local stats="0 0"
if [ "${mounted[$device]}" == "[SWAP]" ]; then
stats="$(get_swap_stats "$device")"
else
local tmp="$(stat --file-system --printf="%s %b %f" \
"${mounted[$device]}")"
read -a usage <<< "$tmp"
stats="$((${usage[0]}*${usage[1]}/1024)) \
$((${usage[0]}*${usage[2]}/1024))"
fi
tmp=${disks[${mounted[$device]}]}
[[ -n "$tmp" ]] && echo $device $stats $tmp
done
}
[[ -z "$(which lsblk)" ]] && exit 3
[[ -z "$(ls /sys/block/)" ]] && exit 4
get_fs_statistics
exit 0