rss logo

Bash script to automated Email Notification when a USB Device is Connected

Linux terminal logo

On a Debian GNU/Linux system, I've been working on a solution to notify users by e-mail when a USB hard disk drive is connected. The aim is to inform the system administrator that the USB drive is successfully connected.

Installing and configuring msmtp

Here's an example with msmtp, which will send e-mails via the mail.std.rocks relay on SSL port 465.

  • Install msmtp:
root@host:~# apt update && apt install msmtp
  • Edit the /etc/msmtprc file:
account STD
#Mail Server :
host mail.std.rocks
port 465
from backup@std.rocks
#LOGIN / PASSWORD
user backup@std.rocks
password MyWeakPassword

auth on
tls on
tls_starttls on
tls_trust_file /etc/ssl/certs/ca-certificates.crt
tls_certcheck off
logfile /var/log/msmtp.log

account default : STD

udev

udev is a device manager for GNU/Linux systems that dynamically manages devices and their corresponding device nodes in the system. It stands for "userspace device" and operates in user space rather than kernel space. It will allow us to run a script when a USB disk device is connected.

Note: let's say the disk we want to monitor is /dev/sda
  • For your information, we can display all the attributes of the /dev/sda device:
root@host:~# udevadm info --attribute-walk --path=$(udevadm info --query=path --name=/dev/sda)
  • Create a file /etc/udev/rules.d/10_usb-disk.rules:
ACTION=="add", SUBSYSTEM=="block", SUBSYSTEMS=="usb", RUN{program}+="/usr/local/sbin/mail_usb_disk.sh"
  • Reload udev rules and configuration:
root@host:~# udevadm control --reload

Bash script

  • Create the file /usr/local/sbin/mail_usb_disk.sh:
root@host:~# touch /usr/local/sbin/mail_usb_disk.sh && chmod +x /usr/local/sbin/mail_usb_disk.sh
  • Edit /usr/local/sbin/mail_usb_disk.sh:
I've noticed that the script is executed twice when a USB device is plugged in. To avoid sending two e-mails, the script creates a file /tmp/udev_time and then compares the creation time with the current time. If the time difference is greater than 10 seconds, the email will be sent.
Edit 2023/07/01: I haven't tested this, but some people say it could be solved by adding ENV{DEVTYPE}=="usb_device" to the rule.
#! /bin/sh

MAIL_ADDRESS="backup@std.rocks"
DATE=$(/bin/date "+%Y-%m-%dT%H:%M:%S")

UDEV_TIME="$(/bin/date --date="$(stat /tmp/udev_time | grep Modif | sed 's/Modif.*: //')" +%s)" #get /tmp/udev_time creation time
touch /tmp/udev_time
CUR_TIME="$(/bin/date +%s)"

#difference between current time and /tmp/udev_time creation time
TIME_DIFF=$(( (CUR_TIME - UDEV_TIME) ))

#Function
mailto () {
        LANG=C
        rm -f /tmp/mail_usb_disk.header
        echo "From: $MAIL_ADDRESS" >> /tmp/mail_usb_disk.header
        echo "To: $MAIL_ADDRESS" >> /tmp/mail_usb_disk.header
        echo "Date: "`/bin/date -R` >> /tmp/mail_usb_disk.header
        echo "Subject: Disk has been plugged in" >> /tmp/mail_usb_disk.header
        echo "Content-type: text/plain; charset=utf-8" >> /tmp/mail_usb_disk.header
        echo "" >> /tmp/mail_usb_disk.header
        echo "Disk has been plugged in" >> /tmp/mail_usb_disk.header
        cat /tmp/mail_usb_disk.header | /usr/bin/msmtp -f "$MAIL_ADDRESS" "$MAIL_CLIENT"
        rm -f /tmp/mail_usb_disk.header
}

#Send email if time difference is greater than 10s
if [ "$TIME_DIFF" -gt 10 ]; then
	mailto
fi