#!/bin/bash # Fred Denis -- May 31st 2021 # nfs-status.sh - list NFS status (healthy, hung, not mounted, in fstab or not) # Copyright (C) 2021 Fred Denis # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # # # More info and git repo: https://github.com/freddenis/oracle-scripts # # The current script version is 20211117 # # History : # # 20211117 - Fred Denis - Fixed the tput error when the script is executed on many hosts with dcli for example # 20211111 - Fred Denis - GPLv3 licence # 20210531 - Fred Denis - Initial release # set -o pipefail # # Variables # TS="date "+%Y-%m-%d_%H%M%S"" # A timestamp for a nice outut in a logfile declare -A tab_nfs # Mounted NFS declare -A tab_fstab # NFS defined in fstab declare -A all_nfs # All the NFS (mounted + fstab) declare -i nb_hung=0 # An integer to count how many NFS are hung declare -i col_fs=0 # An integer for the FS column size declare -i col_mount=0 # An integer for the mount column size declare -i col_status=11 # An integer for the mount column size declare -i col_fstab=8 # An integer for is in fstab or not column SHOW="False" # Show the umount command for the hung NFS ? (-s/--show) UMOUNT="False" # Umount the NFS ? (-u/--umount) PMOUNT="False" # Mount the umounted NFS ? (-m/--mount) PURPLE=35 RED=31 GREEN=32 BLUE=34 [[ $(id -u) == "0" ]] && IAMROOT="True" || IAMROOT="False" # If UTF8, we show a nice checkmark when NFS is in fstab, if not we just write "yes/no" if [[ $(locale charmap) == "UTF-8" ]]; then CHECKMARK="\xE2\x9C\x94" C_RIGHT=3 BADMARK="xxx" B_RIGHT=2 else CHECKMARK="yes" C_RIGHT=1 BADMARK=" no" B_RIGHT=2 fi # fstab -- same on all Unix except Solaris; use -f/--fstab for other locations FSTAB="/etc/fstab" if [[ $(uname) == "SunOS" ]]; then FSTAB="/etc/vfstab" fi # To avoid a bad error when the script is executed on many hosts with dcli for example if [[ -z "${TERM}" || "${TERM}" == "dumb" ]]; then export TERM="xterm"; fi # # Just print a "-" line # print_a_line() { for i in $(seq 1 $1); do printf "\033[1;37m%s\033[m" "-" done printf "\n" } # # Usage function # usage() { printf "\n\033[1;37m%-8s\033[m\n" "NAME" ; cat << END $(basename $0) - show a status of the NFS (hung, healthy, not mounted, not in fstab, etc ...) END printf "\n\033[1;37m%-8s\033[m\n" "SYNOPSIS" ; cat << END $0 &2 exit 864 fi # eval set -- "${options}" # while true; do case "$1" in -s | --show ) SHOW="True" ; shift ;; -m | --mount ) PMOUNT="True" ; shift ;; -u | --umount ) UMOUNT="True" ; shift ;; -f | --fstab ) FSTAB="$2" ; shift 2 ;; -h | --help ) usage ; shift ;; -- ) shift ; break ;; esac done # # Get the NFS defined in fstab -- if possible # if [[ -r "${FSTAB}" ]]; then for X in $(cat /etc/fstab | grep -v "^#" | grep -v "^$" | grep nfs | awk '{print $1"|"$2}' | sort | uniq); do FS=$(echo ${X} | awk -F "|" '{print $1}') MOUNT=$(echo ${X} | awk -F "|" '{print $2}') tab_fstab[${X}]="${X}" all_nfs[${X}]="${X}" if (( ${#FS} > $col_fs )); then col_fs=${#FS} ; fi if (( ${#MOUNT} > $col_mount )); then col_mount=${#MOUNT}; fi done SHOWFSTAB="True" else SHOWFSTAB="False" # We cannot read fstab so we ignore it (then non root users can use the script as well just without this feature) fi # # Get the infos about hung/healthy NFS # for NFS in $(mount -t nfs | awk '{print $1"|"$3}' | sort); do FS=$(echo ${NFS} | awk -F "|" '{print $1}') MOUNT=$(echo ${NFS} | awk -F "|" '{print $2}') printf "%-60s" "Checking ${MOUNT} . . ." tput hpa 0 read -t1 < <(stat -t "${MOUNT}" 2>&-) if [[ $? -ne 0 ]]; then ((nb_hung++)) tab_nfs[${NFS}]="Hung" else tab_nfs[${NFS}]="Healthy" fi all_nfs[${NFS}]="${NFS}" ; if (( ${#FS} > $col_fs )); then col_fs=${#FS} ; fi if (( ${#MOUNT} > $col_mount )); then col_mount=${#MOUNT}; fi done # # Make a nice table with infos collected above # line_size=$(( col_fs+col_mount+col_status+col_fstab+13 )) # Header print_a_line ${line_size} printf " %-${col_mount}s |" "Mount Point" printf " %-${col_fs}s |" "NFS" printf " %-${col_status}s |" "Status" printf " %-${col_fstab}s |" "in fstab" printf "\n" print_a_line ${line_size} # Add the not mounted status here in a dedicated loop as the next one making the table body is executed into () so in a subshell # and then the show mount commands would not work for X in ${!all_nfs[@]}; do if [[ -z "${tab_nfs[${X}]}" ]] ; then STATUS_COLOR="${PURPLE}"; tab_nfs[${X}]="Not Mounted"; fi done # Table body (for X in ${!all_nfs[@]}; do if [[ "${tab_nfs[${X}]}" == "Not Mounted" ]]; then STATUS_COLOR="${PURPLE}" ; fi if [[ "${tab_nfs[${X}]}" == "Healthy" ]] ; then STATUS_COLOR="${GREEN}" ; fi if [[ "${tab_nfs[${X}]}" == "Hung" ]] ; then STATUS_COLOR="${RED}" ; fi FS=$(echo ${X} | awk -F "|" '{print $1}') MOUNT=$(echo ${X} | awk -F "|" '{print $2}') printf " %-${col_mount}s |" "${MOUNT}" printf " %-${col_fs}s |" "${FS}" printf "\033[1;${STATUS_COLOR}m %-${col_status}s \033[m |" "${tab_nfs[${X}]}" if [[ "${SHOWFSTAB}" == "True" ]]; then if [[ -z "${tab_fstab[${X}]}" ]]; then # Not in fstab printf "\033[1;${RED}m ${BADMARK} %-${B_RIGHT}s\033[m |" else # In fstab printf "\033[1;${GREEN}m ${CHECKMARK} %-${C_RIGHT}s\033[m |" fi else # We were unable to read fstab printf "\033[1;${BLUE}m %-4s \033[m |" "n/a" fi printf "\n" done) | sort # Footer print_a_line ${line_size} # # If we have found hung NFS, show how to umount them # if (( ${nb_hung} > 0 )); then printf "%s\n\n" "Hung NFS can be umount using: umount -f -l ; use --show to generate the umount commands" fi # # Show the NFS commands to umount the hung NFS ? # if [[ "${SHOW}" == "True" ]]; then (for X in ${!all_nfs[@]}; do MOUNT=$(echo ${X} | awk -F "|" '{print $2}') if [[ "${tab_nfs[${X}]}" == "Hung" ]]; then printf "%s\n" "umount -f -l ${MOUNT}" fi if [[ "${tab_nfs[${X}]}" == "Not Mounted" ]]; then printf "%s\n" "mount ${MOUNT}" fi done) | sort fi # # Automatically umount the hung NFS ? # if [[ "${UMOUNT}" == "True" ]]; then if [[ "${IAMROOT}" == "True" ]]; then for X in ${!all_nfs[@]}; do MOUNT=$(echo ${X} | awk -F "|" '{print $2}') if [[ "${tab_nfs[${X}]}" == "Hung" ]]; then printf "%-60s" "Umounting ${MOUNT} . . ." tput hpa 0 printf "%s\n" "umount -f -l ${MOUNT}" | bash fi done else printf "\033[1;33m%s\033[m\n" "$($TS) [WARNING] Only root can umount the NFS, skipping." ;>&2 fi fi # # Automatically mount the umounted NFS ? # if [[ "${PMOUNT}" == "True" ]]; then if [[ "${IAMROOT}" == "True" ]]; then for X in ${!all_nfs[@]}; do MOUNT=$(echo ${X} | awk -F "|" '{print $2}') if [[ "${tab_nfs[${X}]}" == "Not Mounted" ]]; then printf "%-60s" "Mounting ${MOUNT} . . ." tput hpa 0 printf "%s\n" "mount ${MOUNT}" | bash fi done else printf "\033[1;33m%s\033[m\n" "$($TS) [WARNING] Only root can mount the NFS, skipping." ;>&2 fi fi # # Exit with number of hung NFS # exit "${nb_hung}"