#!/bin/bash # Script to check comprehensive disk statistics # Author: Alex@portalZINE.de # Date: 25.11.2025 ##################################### # CONFIGURATION ##################################### DEFAULT_DEVICE="/dev/sda1" # Default device to monitor # Ntfy Configuration NTFY_URL="https://your-ntfy-server.com/topic" # Leave the ":", when using a token NTFY_TOKEN=":your_token_here" # NTFY_TOKEN="user:password" NTFY_TITLE="Whatever Title You Want" ##################################### # Initialize output variable OUTPUT="" # Function to add to output add_output() { OUTPUT="${OUTPUT}${1}\n" } # Function to display usage usage() { cat << EOF Usage: $(basename "$0") [OPTIONS] [DEVICE] Check comprehensive disk statistics for a device. OPTIONS: -h, --help Show this help message -d, --device DEVICE Specify device to check (e.g., /dev/sda1) -q, --quiet Quiet mode - minimal output -v, --verbose Verbose mode - show all available stats -s, --section NAME Show only specific section(s) (comma-separated) -l, --list-sections List all available sections and exit -n, --ntfy Send notification via ntfy (no console output) --ntfy-always Send ntfy notification AND show console output AVAILABLE SECTIONS: all Show all sections (default) basic Basic disk usage (size, used, available) inodes Inode usage statistics filesystem Filesystem information (type, blocks) mount Mount options device Device information (lsblk output) io I/O statistics (reads, writes, sectors) analysis Usage analysis and warnings consumers Top space consumers (largest directories) ARGUMENTS: DEVICE Device to check (default: $DEFAULT_DEVICE) NTFY CONFIGURATION: Configure ntfy settings at the top of the script: - NTFY_URL Ntfy server URL - NTFY_TOKEN Authentication token - NTFY_TITLE Notification title EXAMPLES: $(basename "$0") # Check default device ($DEFAULT_DEVICE) $(basename "$0") /dev/sdb1 # Check /dev/sdb1 $(basename "$0") -d /dev/nvme0n1p1 # Check NVMe device $(basename "$0") --quiet /dev/sda2 # Quiet mode for /dev/sda2 $(basename "$0") -s basic # Show only basic usage $(basename "$0") -s basic,analysis # Show basic usage and analysis $(basename "$0") -s io,consumers /dev/sdb1 # Show I/O stats and top consumers $(basename "$0") --list-sections # List all available sections $(basename "$0") --ntfy # Send notification only (no output) $(basename "$0") --ntfy-always # Send notification AND show output EOF exit 0 } # Function to list all available sections list_sections() { cat << EOF Available Sections: =================== all - Show all sections (default behavior) basic - Basic disk usage information • Filesystem name • Total size • Used space • Available space • Usage percentage • Mount point inodes - Inode usage statistics • Total inodes • Used inodes • Free inodes • Inode usage percentage filesystem - Filesystem information • Filesystem type (ext4, xfs, etc.) • Block size • Total blocks • Free blocks • Available blocks mount - Mount options • Full mount command output • Mount flags (rw, relatime, etc.) device - Device information • Device name • Size • Type • Filesystem type • Mount point • Label • UUID io - I/O statistics • Read operations • Write operations • Sectors read/written • Read/write time • I/O operations in progress • Extended iostat (verbose mode only) analysis - Usage analysis • Disk space status (OK/WARNING/CRITICAL) • Inode status (OK/WARNING/CRITICAL) • Threshold-based alerts consumers - Top space consumers • Largest directories on the partition • Top 10 (normal) or top 20 (verbose) • Human-readable sizes Usage Examples: $(basename "$0") -s basic # Just the essentials $(basename "$0") -s basic,analysis # Quick health check $(basename "$0") -s io # I/O performance only $(basename "$0") -s all # Everything (same as no -s flag) EOF exit 0 } # Parse command line arguments DEVICE="" QUIET_MODE=false VERBOSE_MODE=false SECTIONS="" NTFY_MODE=false NTFY_ALWAYS=false while [[ $# -gt 0 ]]; do case $1 in -h|--help) usage ;; -l|--list-sections) list_sections ;; -d|--device) DEVICE="$2" shift 2 ;; -q|--quiet) QUIET_MODE=true shift ;; -v|--verbose) VERBOSE_MODE=true shift ;; -s|--section) SECTIONS="$2" shift 2 ;; -n|--ntfy) NTFY_MODE=true shift ;; --ntfy-always) NTFY_ALWAYS=true shift ;; -*) echo "Error: Unknown option: $1" echo "Use -h or --help for usage information" exit 1 ;; *) # Assume it's a device path if [ -z "$DEVICE" ]; then DEVICE="$1" else echo "Error: Multiple devices specified" exit 1 fi shift ;; esac done # Use default device if none specified if [ -z "$DEVICE" ]; then DEVICE="$DEFAULT_DEVICE" fi # Function to check if a section should be displayed should_show_section() { local section=$1 # If no sections specified, show all if [ -z "$SECTIONS" ]; then return 0 fi # If 'all' is specified, show everything if [[ ",$SECTIONS," == *",all,"* ]]; then return 0 fi # Check if section is in the comma-separated list if [[ ",$SECTIONS," == *",$section,"* ]]; then return 0 fi return 1 } add_output "========================================" add_output "Disk Statistics Report for $DEVICE" add_output "========================================" if [ "$QUIET_MODE" = false ]; then add_output "Report generated: $(date '+%Y-%m-%d %H:%M:%S')" fi add_output "" # Check if device exists if [ ! -b "$DEVICE" ]; then echo "Error: $DEVICE does not exist or is not a block device" exit 1 fi # Get mount point MOUNT_POINT=$(df "$DEVICE" 2>/dev/null | awk 'NR==2 {print $6}') if [ -z "$MOUNT_POINT" ]; then echo "Error: $DEVICE is not mounted" exit 1 fi # Quiet mode - show only essential info if [ "$QUIET_MODE" = true ]; then QUIET_INFO=$(df -h "$DEVICE" | awk 'NR==2 { print "Device: " $1 print "Size: " $2 print "Used: " $3 print "Available: " $4 print "Usage: " $5 print "Mount: " $6 }') add_output "$QUIET_INFO" USAGE_PERCENT=$(df "$DEVICE" | awk 'NR==2 {print $5}' | sed 's/%//') if [ "$USAGE_PERCENT" -ge 90 ]; then add_output "Status: ⚠️ CRITICAL (${USAGE_PERCENT}%)" elif [ "$USAGE_PERCENT" -ge 80 ]; then add_output "Status: ⚠️ WARNING (${USAGE_PERCENT}%)" else add_output "Status: ✓ OK (${USAGE_PERCENT}%)" fi # Print all output at once echo -e "$OUTPUT" exit 0 fi if should_show_section "basic"; then add_output "========== BASIC DISK USAGE ==========" BASIC_USAGE=$(df -h "$DEVICE" | awk 'NR==2 { print " Filesystem: " $1 print " Total Size: " $2 print " Used: " $3 print " Available: " $4 print " Usage: " $5 print " Mount Point: " $6 }') add_output "$BASIC_USAGE" add_output "" fi if should_show_section "inodes"; then add_output "========== INODE USAGE ==========" INODE_USAGE=$(df -hi "$DEVICE" | awk 'NR==2 { print " Total Inodes: " $2 print " Used Inodes: " $3 print " Free Inodes: " $4 print " Inode Usage: " $5 }') add_output "$INODE_USAGE" add_output "" fi if should_show_section "filesystem"; then add_output "========== FILESYSTEM INFORMATION ==========" # Filesystem type FS_TYPE=$(df -T "$DEVICE" | awk 'NR==2 {print $2}') add_output " Filesystem Type: $FS_TYPE" # Block size information BLOCK_SIZE=$(stat -f -c %s "$MOUNT_POINT" 2>/dev/null) if [ -n "$BLOCK_SIZE" ]; then add_output " Block Size: $BLOCK_SIZE bytes" fi # Total blocks TOTAL_BLOCKS=$(stat -f -c %b "$MOUNT_POINT" 2>/dev/null) FREE_BLOCKS=$(stat -f -c %f "$MOUNT_POINT" 2>/dev/null) AVAIL_BLOCKS=$(stat -f -c %a "$MOUNT_POINT" 2>/dev/null) if [ -n "$TOTAL_BLOCKS" ]; then add_output " Total Blocks: $TOTAL_BLOCKS" add_output " Free Blocks: $FREE_BLOCKS" add_output " Available: $AVAIL_BLOCKS" fi add_output "" fi if should_show_section "mount"; then add_output "========== MOUNT OPTIONS ==========" MOUNT_INFO=$(mount | grep "$DEVICE") if [ -n "$MOUNT_INFO" ]; then add_output " $MOUNT_INFO" fi add_output "" fi if should_show_section "device"; then add_output "========== DISK DEVICE INFO ==========" if command -v lsblk &> /dev/null; then LSBLK_INFO=$(lsblk "$DEVICE" -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINT,LABEL,UUID 2>/dev/null | sed 's/^/ /') add_output "$LSBLK_INFO" fi add_output "" fi if should_show_section "io"; then add_output "========== I/O STATISTICS ==========" if [ -f /proc/diskstats ]; then # Extract device name without /dev/ prefix DEVICE_NAME=$(basename "$DEVICE") # Extract stats for the device DISK_STATS=$(grep " $DEVICE_NAME " /proc/diskstats) if [ -n "$DISK_STATS" ]; then IO_STATS=$(echo "$DISK_STATS" | awk '{ print " Device: " $3 print " Reads: " $4 print " Reads Merged: " $5 print " Sectors Read: " $6 print " Read Time (ms): " $7 print " Writes: " $8 print " Writes Merged: " $9 print " Sectors Written: " $10 print " Write Time (ms): " $11 print " I/Os in Progress:" $12 print " I/O Time (ms): " $13 }') add_output "$IO_STATS" fi fi # iostat if available - show in verbose mode or if explicitly installed if command -v iostat &> /dev/null && [ "$VERBOSE_MODE" = true ]; then add_output "" add_output " Extended I/O Stats:" IOSTAT_INFO=$(iostat -x "$DEVICE" 1 1 2>/dev/null | tail -n +4 | sed 's/^/ /') add_output "$IOSTAT_INFO" fi add_output "" fi if should_show_section "analysis"; then add_output "========== USAGE ANALYSIS ==========" # Get usage percentage as a number USAGE_PERCENT=$(df "$DEVICE" | awk 'NR==2 {print $5}' | sed 's/%//') INODE_PERCENT=$(df -i "$DEVICE" | awk 'NR==2 {print $5}' | sed 's/%//') # Disk space warning add_output " Disk Space Status:" if [ "$USAGE_PERCENT" -ge 90 ]; then add_output " ⚠️ CRITICAL: Disk usage is critically high (${USAGE_PERCENT}%)!" elif [ "$USAGE_PERCENT" -ge 80 ]; then add_output " ⚠️ WARNING: Disk usage is high (${USAGE_PERCENT}%)" elif [ "$USAGE_PERCENT" -ge 70 ]; then add_output " ⚡ NOTICE: Disk usage is moderate (${USAGE_PERCENT}%)" else add_output " ✓ OK: Disk usage is within normal range (${USAGE_PERCENT}%)" fi # Inode warning add_output "" add_output " Inode Status:" if [ "$INODE_PERCENT" -ge 90 ]; then add_output " ⚠️ CRITICAL: Inode usage is critically high (${INODE_PERCENT}%)!" elif [ "$INODE_PERCENT" -ge 80 ]; then add_output " ⚠️ WARNING: Inode usage is high (${INODE_PERCENT}%)" else add_output " ✓ OK: Inode usage is within normal range (${INODE_PERCENT}%)" fi add_output "" fi if should_show_section "consumers"; then add_output "========== TOP SPACE CONSUMERS ==========" if [ -d "$MOUNT_POINT" ]; then add_output " Largest directories in $MOUNT_POINT:" if [ "$VERBOSE_MODE" = true ]; then # Show top 20 in verbose mode TOP_DIRS=$(du -h "$MOUNT_POINT" --max-depth=1 2>/dev/null | sort -rh | head -20 | sed 's/^/ /') else # Show top 10 in normal mode TOP_DIRS=$(du -h "$MOUNT_POINT" --max-depth=1 2>/dev/null | sort -rh | head -10 | sed 's/^/ /') fi add_output "$TOP_DIRS" fi add_output "" fi add_output "========================================" add_output "Report completed: $(date '+%Y-%m-%d %H:%M:%S')" add_output "========================================" # Function to send ntfy notification send_ntfy() { local message="$1" local priority="${2:-default}" local tags="${3:-}" if [ -z "$NTFY_URL" ] || [ -z "$NTFY_TOKEN" ]; then echo "Error: Ntfy configuration is incomplete" return 1 fi local curl_args=(-u "$NTFY_TOKEN") if [ -n "$NTFY_TITLE" ]; then curl_args+=(-H "Title: $NTFY_TITLE") fi if [ -n "$priority" ] && [ "$priority" != "default" ]; then curl_args+=(-H "Priority: $priority") fi if [ -n "$tags" ]; then curl_args+=(-H "Tags: $tags") fi curl_args+=(-d "$message" "$NTFY_URL") curl -s "${curl_args[@]}" > /dev/null return $? } # Prepare notification if ntfy is enabled if [ "$NTFY_MODE" = true ] || [ "$NTFY_ALWAYS" = true ]; then # Get key metrics for determining priority USAGE_PERCENT=$(df "$DEVICE" | awk 'NR==2 {print $5}' | sed 's/%//') INODE_PERCENT=$(df -i "$DEVICE" | awk 'NR==2 {print $5}' | sed 's/%//') # Determine priority and tags based on usage PRIORITY="default" TAGS="white_check_mark" if [ "$USAGE_PERCENT" -ge 90 ] || [ "$INODE_PERCENT" -ge 90 ]; then PRIORITY="urgent" TAGS="warning,skull" elif [ "$USAGE_PERCENT" -ge 80 ] || [ "$INODE_PERCENT" -ge 80 ]; then PRIORITY="high" TAGS="warning" elif [ "$USAGE_PERCENT" -ge 70 ] || [ "$INODE_PERCENT" -ge 70 ]; then PRIORITY="default" TAGS="zap" fi # Send the full output as notification NTFY_MESSAGE=$(echo -e "$OUTPUT") # Send notification if send_ntfy "$NTFY_MESSAGE" "$PRIORITY" "$TAGS"; then if [ "$NTFY_MODE" = true ]; then echo "Notification sent successfully to ntfy" exit 0 fi else echo "Error: Failed to send ntfy notification" if [ "$NTFY_MODE" = true ]; then exit 1 fi fi fi # Print all output at once at the end (unless ntfy-only mode) if [ "$NTFY_MODE" = false ]; then echo -e "$OUTPUT" fi