#!/usr/bin/env bash # # status of mounted filesystems in 2 steps # 1. use "df" for general fs except zfs, squashfs, tmpfs, devtmpfs and overlay # 2. use "zpool" for ZFS pools # + displays name, filesystem type, used blocks and inodes or pool health when relevant # + custom warn threshold for blocks # + warn threshold for inodes (80%), flashing danger threshold for health, blocks (95%) and inodes (90%) # # requirements: sudo apt install coreutils # optionnal: sudo apt install zfsutils-linux # GENERAL ########################################################### # locale env unset LC_ALL export LC_MESSAGES=C # check if module was disabled module_disable=${module_filesystem_disable:=0} if (($module_disable == 1)); then exit 1 fi # colors c_txt=${c_txt:="39"} c_txt_emphase=${c_txt_emphase:="35"} c_txt_deco=${c_txt_deco:="97"} c_txt_invert=${c_txt_invert:="30"} c_bg=${c_bg_sec:="47"} c_danger=${c_danger:="31"} c_warning=${c_warning:="33"} c_success=${c_success:="32"} c_title=${c_title:="${c_bg};1;${c_txt_invert}m"} # OPTIONS ########################################################### # max usage warning threshold max_usage=${module_filesystem_max_usage:="85"} # disable ZFS section zfs_disable=${module_filesystem_zfs_disable:=0} # PREPARATIONS ###################################################### # disk usage: ignore zfs, squashfs & tmpfs, standard error output because of a bug with /run/user/1000/doc dfcmd=$(/usr/bin/df -H -x zfs -x squashfs -x tmpfs -x devtmpfs -x overlay --output 2>/dev/null) mapfile -t dfoutput < <(echo "$dfcmd" | tail -n+2) # determine best width for the bar largesttarget=$(echo "$dfcmd" | awk '{if (length ($12)>max) max=length($12)} END {print max}') if [[ $((largesttarget+30)) -gt 50 ]]; then bar_width=$((largesttarget+30)) else bar_width="50" fi # OUTPUT ############################################################ # general filesystems linecounter=0 if [[ "${dfoutput[@]}" ]]; then # output header echo -e "\n\e[${c_title} Filesystem usage \e[0m\n" # output filesystem status except ZFS for line in "${dfoutput[@]}"; do # parse df output diskid=$(echo "$line" | awk '{print $12}') diskused=$(echo "$line" | awk '{print $10}'| sed 's/%//') disktotal=$(echo "$line" | awk '{print $7}') fsformat=$(echo "$line" | awk '{print $2}') inodesused=$(echo "$line" | awk '{print $6}'| sed 's/%//') inodestotal=$(echo "$line" | awk '{print $3}') # bar & blocks coloration, danger red above 95% if [[ "${diskused}" -ge "95" ]]; then barcolor="\e[1;${c_danger}m" blockscolor="\e[1;${c_danger}m" flashing="\e[5m" elif [ "${diskused}" -ge "${max_usage}" ]; then barcolor="\e[1;${c_warning}m" blockscolor="\e[1;${c_warning}m" flashing="" else barcolor="\e[1;${c_success}m" blockscolor="\e[${c_txt}m" flashing="" fi # print colored bar until used_width used_width=$(((diskused*$bar_width)/100)) bar="[${barcolor}" for ((i=0; i<$used_width; i++)); do bar+="=" done # print dimmmed bar until end bar+="\e[${c_txt}m\e[0m" for ((i=$used_width; i<$bar_width; i++)); do bar+="=" done bar+="\e[0m]" # print blocks usage line & bar padding=$((bar_width-28)) if [[ $linecounter -ge 1 ]] then echo -e "\n" fi echo "${line}" | printf "\e[1;${c_txt_emphase}m%-${padding}s\e[0m${blockscolor}%+3s%% used ${flashing}blocks\e[0m out of %+4s\n" $diskid $diskused $disktotal | sed 's/^/ /' echo -e "${bar}" | sed 's/^/ /' # print filesystem type & inodes usage line if [[ ! "$inodesused" == "-" ]] then padding=$((bar_width-34)) # inodes coloration, danger red above 90% if [[ "${inodesused}" -ge "90" ]]; then inodescolor="\e[1;${c_danger}m" flashing="\e[5m" elif [[ "${inodesused}" -ge "80" ]]; then inodescolor="\e[1;${c_warning}m" flashing="" else inodescolor="\e[${c_txt}m" flashing="" fi echo "${line}" | printf "Type: %-${padding}s${inodescolor}%+3s%% used ${flashing}inodes\e[0m out of %+4s\n" $fsformat $inodesused $inodestotal | sed 's/^/ /' else echo "${line}" | printf "Type: %-10s\n" $fsformat | sed 's/^/ /' fi linecounter=$((linecounter+1)) done else echo " no general filesystem available, ZFS expected in next section" fi # check if ZFS section was disabled if [[ $zfs_disable == 1 ]]; then exit 1 fi # output ZFS header echo -e "\n\e[${c_title} Zpool usage \e[0m\n" # check if zpool is available if ! command -v zpool 1> /dev/null; then echo " no ZFS tools available" exit 1 fi # ZFS zpool usage & health status zlistcmd=$(zpool list -o name,cap,size,health 2> /dev/null) if [[ $zlistcmd == "no pools available" ]]; then echo " no ZFS pool available" else mapfile -t zpools < <(echo "$zlistcmd" | tail -n+2) # determine best width for the bar largesttarget=$(echo "zlistcmd" | awk '{if (length ($1)>max) max=length($1)} END {print max}') if [[ $((largesttarget+30)) -gt 50 ]]; then bar_width=$((largesttarget+30)) else bar_width="50" fi linecounter=0 for line in "${zpools[@]}"; do # parse zpool list output poolid=$(echo "$line" | awk '{print $1}') poolused=$(echo "$line" | awk '{print $2}'| sed 's/%//') pooltotal=$(echo "$line" | awk '{print $3}') poolhealth=$(echo "$line" | awk '{print $4}') # bar & pools coloration, danger red above 95% if [[ "${poolused}" -ge "95" ]]; then barcolor="\e[1;${c_danger}m" poolscolor="\e[1;${c_danger}m" flashing="\e[5m" elif [[ "${poolused}" -ge "${max_usage}" ]]; then barcolor="\e[1;${c_warning}m" poolscolor="\e[1;${c_warning}m" flashing="" else barcolor="\e[1;${c_success}m" poolscolor="\e[${c_txt}m" flashing="" fi # print colored bar until used_width used_width=$(((poolused*$bar_width)/100)) bar="[${barcolor}" for ((i=0; i<$used_width; i++)); do bar+="=" done # print dimmmed bar until end bar+="\e[${c_txt}m\e[0m" for ((i=$used_width; i<$bar_width; i++)); do bar+="=" done bar+="\e[0m]" # print pool usage line & bar padding=$((bar_width-29)) if [[ $linecounter -ge 1 ]] then echo -e "\n" fi echo "${line}" | printf "\e[1;${c_txt_emphase}m%-${padding}s\e[0m${poolscolor}%+3s%% used ${flashing}blocks\e[0m out of %+5s\n" $poolid $poolused $pooltotal | sed 's/^/ /' echo -e "${bar}" | sed 's/^/ /' # print pool health line padding=$((bar_width-34)) # health coloration, danger red for FAULTED if [[ "${poolhealth}" == "FAULTED" ]]; then healthcolor="\e[1;${c_danger}m" flashing="\e[5m" elif [[ "${poolhealth}" == "OFFLINE" ]] || [[ "${poolhealth}" == "UNAVAIL" ]] || [[ "${poolhealth}" == "REMOVED" ]] || [[ "${poolhealth}" == "DEGRADED" ]]; then healthcolor="\e[1;${c_warning}m" flashing="" else healthcolor="\e[${c_txt}m" flashing="" fi padding=$((bar_width-17)) text="health" echo "${line}" | printf "%+${padding}s status: ${healthcolor}${flashing}%+8s\e[0m\n" $text ${poolhealth,,} | sed 's/^/ /' linecounter=$((linecounter+1)) done fi