Skip to content

Warn before the root drive fills up

This guide creates a script that checks the usage of the root partition. When usage reaches a threshold, the script sends a desktop notification. A systemd user timer runs the script every hour. Filling the boot drive completely can make the system unbootable, so this check helps you act early.

Set the threshold in the script. A value between 75 and 90 percent is a good default. Use a lower value for small drives and a higher value for very large drives.

  • libnotify, which provides the notify-send command used for desktop notifications.
  • A desktop session with a notification daemon. The breeze icons are optional, the script runs without them.
  1. Create the script in ~/.local/bin:

    Terminal window
    mkdir -p ~/.local/bin
    touch ~/.local/bin/check_disk.sh
  2. Open ~/.local/bin/check_disk.sh in a text editor and paste the script below.

    #!/bin/bash
    #
    # location of all check_disk related files
    #
    # this script's location
    # cat ~/.local/bin/check_disk.sh
    #
    # other check_disk related file locations
    #
    # cat ~/.config/systemd/user/check_disk.service
    # cat ~/.config/systemd/user/check_disk.timer
    # cat ~/.local/state/check_disk.log
    # Delete old ~/.local/state/check_disk.log if it exceeds 1MB in size to conserve space
    find ~/.local/state/check_disk.log -size +1M -delete
    # Adjust threshold percentage to trigger alerts (75%-90% range recommended)
    # Temporarily lower the threshold to one (1) to test the scripts functionality
    THRESHOLD=80
    # Calculate the current percentage of used space on the /root partition
    PERCENTAGE=$(df -h / | awk 'NR==2 {print $5}' | sed 's/%//')
    # Check if disk usage exceeds the assigned percentage threshold
    if [ "$PERCENTAGE" -ge "$THRESHOLD" ]
    then
    # If disk free space is becoming problematic display a "Disk Space Alert"
    MESSAGE="WARNING: Disk usage on root partition is at ${PERCENTAGE}%!"
    # Calculate the estimated free space remaining on the /root partition (BTRFS file system specific)
    FREESPACE="$(btrfs filesystem usage / 2> /dev/null | grep -i 'Free (estimated):' | awk '{print $3}')"
    # WARNING=... embeds a "warning" icon in the first desktop notification
    # Error suppressed if the KDE Breeze icon set isn't present on the users system
    WARNING=/usr/share/icons/breeze/emblems/24/emblem-warning.svg 2>/dev/null || true
    # IMPORTANT=... embeds an "important" icon in the second desktop notification
    # Error suppressed if the KDE Breeze icon set isn't present on the users system
    IMPORTANT=/usr/share/icons/breeze/emblems/24/emblem-important.svg 2>/dev/null || true
    # Send a persistent desktop notification if drive usage percentage exceeds specified threshold
    notify-send -u critical -i "$WARNING" "Disk Space Alert" "$MESSAGE"
    # Pause 5 seconds before issuing a second disk space remaining notification
    sleep 5
    # Send a fleeting desktop notification of estimated disk space remaining (BTRFS file system specific)
    notify-send -i "$IMPORTANT" "$FREESPACE" "space remaining on /root partition"
    echo "The check_disk timer was last executed on $(date +"%Y-%m-%d_%H:%M:%S") - drive capacity $PERCENTAGE % full" >> ~/.local/state/check_disk.log
    # If disk usage exceeds the script's assigned threshold write supplemental warnings to the ~/.local/state/check_disk.log file
    echo -e "WARNING ... free space on the root partition has reached a dangerous level - $(date +"%Y-%m-%d_%H:%M:%S") \nNOTIFICATION ... steps must be taken to free up additional space or a system failure may occur" >> ~/.local/state/check_disk.log
    # In terminal output a "Disk Space Alert" when threshold is exceeded
    echo "$MESSAGE"
    else
    # create a timestamped log entry - including drive usage statistics at that time the script was run
    echo "The check_disk timer was last executed on $(date +"%Y-%m-%d_%H:%M:%S") - drive capacity $PERCENTAGE % full" >> ~/.local/state/check_disk.log
    # In terminal display the percentage of used disk space and notify that current free space is sufficient
    echo -e "The root partition is currently filled to $PERCENTAGE% of the drive's capacity \nThere is an adequate amount of free space on your system partition"
    fi
  3. Make the script executable:

    Terminal window
    chmod +x ~/.local/bin/check_disk.sh

The service and timer are user units. They go in ~/.config/systemd/user/.

  1. Create both files:

    Terminal window
    mkdir -p ~/.config/systemd/user
    touch ~/.config/systemd/user/check_disk.service
    touch ~/.config/systemd/user/check_disk.timer
  2. Paste the service below into ~/.config/systemd/user/check_disk.service. %h expands to your home directory, so the path works without hard-coding it.

    # locations of all check_disk related files
    #
    # this systemd service file
    # cat ~/.config/systemd/user/check_disk.service
    #
    # other check_disk related files
    #
    # cat ~/.config/systemd/user/check_disk.timer
    # cat ~/.local/bin/check_disk.sh
    # cat ~/.local/state/check_disk.log
    #
    # systemctl commands for managing the check_disk.timer & check_disk.service
    #
    # systemctl --user enable --now check_disk.timer
    # systemctl --user disable --now check_disk.timer
    # systemctl --user stop check_disk.timer
    # systemctl --user restart check_disk.timer
    # systemctl --user status check_disk.timer
    # systemctl --user daemon-reload (run command after altering check_disk.timer or check_disk.service)
    # systemctl --user status check_disk.service
    #
    # do not enable or start the check_disk.service, the timer unit handles this operation
    [Unit]
    Description=Service to check free disk space hourly
    [Service]
    # %h expands to the path of the user's home directory
    ExecStart=%h/.local/bin/check_disk.sh
  3. Paste the timer below into ~/.config/systemd/user/check_disk.timer. It runs at the start of every hour, and once shortly after boot.

    # locations of all check_disk related files
    #
    # this systemd timer file
    # cat ~/.config/systemd/user/check_disk.timer
    #
    # other check_disk related files
    #
    # cat ~/.config/systemd/user/check_disk.service
    # cat ~/.local/bin/check_disk.sh
    # cat ~/.local/state/check_disk.log
    #
    # systemctl commands related to check_disk.timer & check_disk.service
    #
    # systemctl --user enable --now check_disk.timer
    # systemctl --user disable --now check_disk.timer
    # systemctl --user daemon-reload (run command after altering check_disk.timer or check_disk.service)
    # systemctl --user restart check_disk.timer
    # systemctl --user stop check_disk.timer
    # systemctl --user --all list-timers
    # systemctl --user status check_disk.timer
    # systemctl --user status check_disk.service
    [Unit]
    Description=Check free disk space hourly
    [Timer]
    OnCalendar=*-*-* *:00:00
    AccuracySec=5m
    Persistent=true
    Unit=check_disk.service
    OnBootSec=180
    [Install]
    WantedBy=timers.target
  4. Reload the user daemon, then enable and start the timer:

    Terminal window
    systemctl --user daemon-reload
    systemctl --user enable --now check_disk.timer
  5. Check that the timer runs:

    Terminal window
    systemctl --user status check_disk.timer

Set THRESHOLD to 1 in the script for a test. Every run then shows a warning. Set it back to a real value afterwards.

  1. Stop the hourly checks:

    Terminal window
    systemctl --user stop check_disk.timer
  2. Start them again:

    Terminal window
    systemctl --user restart check_disk.timer
  3. The timer also starts again after a reboot.

Each run appends a line to ~/.local/state/check_disk.log. The log is deleted when it grows past 1 MB.

If the service fails with Neither a valid executable name nor an absolute path, use the %h form from step 2 of the service. This error was reported with ~/.local/bin/check_disk.sh in ExecStart=.

If the notifications do not appear, check that libnotify is installed and that a notification daemon runs in your session. A forum reply suggested setting DBUS_SESSION_BUS_ADDRESS in the script. Another reply noted that user units normally inherit the session bus, so the variable is not needed for a user timer.

An automatic installer exists that creates these files and can update them. It is a remote script, so read it before you run it. The installer replaces any changes you made to the files.


Source: How to write a script, service, and timer to help prevent a drive being filled to capacity