Skip to content

Instantly share code, notes, and snippets.

@mqu
Last active October 3, 2023 14:43
Show Gist options
  • Save mqu/8632432 to your computer and use it in GitHub Desktop.
Save mqu/8632432 to your computer and use it in GitHub Desktop.
usb-auto-backup script - a script connected to UDEV daemon, running rsync backup when user insert USB drive.
TODO :
- manage user notification ; notify-send not really working ; current alternative either.
- display hostid used to customize usb backup script.
INSTALL
- copy usb-auto-backup script to /usr/local/bin,
- create an partition on an USB drive named "backup" ; get id (/dev/sddX) -> will be needed in udev.rules
- identity your drive information for UDEV-rules using : udevadm info -a -p $(udevadm info -q path -n /dev/sdXX)
- create an UDEV rule : /etc/udev/rules.d/99-usb-auto-backup.rules like this one :
"KERNEL=="sd?5", ACTION=="add", ATTRS{serial}=="XXXXXXX", ATTRS{manufacturer}=="XXXXXXXX", ATTRS{product}=="XXXXXXX*", RUN+="/usr/local/bin/usb-auto-backup --fork %k"
keywords : usb, udev, linux, backup, rsync, udev-rules.
#!/bin/bash
# author : Marc Quinton / 01.2014
# USB auto Backup
#
# a script linked to UDEV making backups on USB drives run just after insertion.
#
# keywords : usb, udev, linux, backup, rsync, udev-rules.
#
# usage :
# - create a partition named "backup"
# - query info from your drive with : udevadm info -a -p $(udevadm info -q path -n /dev/sdXX)
# - put udev rule : /etc/udev/rules.d/99-usb-auto-backup.rules
# "KERNEL=="sd?5", ACTION=="add", ATTRS{serial}=="XXXXXXX", ATTRS{manufacturer}=="XXXXXXXX", ATTRS{product}=="XXXXXXX*", RUN+="/usr/local/bin/usb-auto-backup --fork %k"
# - write your rsync job below.
#
# Debug :
# - log info : tail -200 /var/log/syslog | grep -i backup
#
# links :
# - http://hackaday.com/2009/09/18/how-to-write-udev-rules/
# - http://doc.ubuntu-fr.org/udev
#
# script sequence :
# - user plug USB drive
# - udev rule runs /usr/local/bin/usb-auto-backup with --fork opt
# - usb-auto-backup forks and sleep for 1 second waiting for drive to be mounted
# - get mount dir for backup_name
# - try to run mount-point/bin/usb-auto-backup
# - usb-auto-backup starts it jobs.
#
prog_name='usb-auto-backup'
backup_name="backup" # partition name
# get information from your mother board to identify your computer based on hardware
dmi-info () {
# motherboard identification : /sys/devices/virtual/dmi/id/ - interesting fields examples from my board.
# product_name : MS-7641
# board_vendor : MSI
# board_name : 760GM-P23(FX) (MS-7641)
# board_asset_tag : To Be Filled By O.E.M.
# board_serial : To be filled by O.E.M.
# product_uuid : 00000000-0000-0000-0000-8C89A5C637AF
dir=/sys/devices/virtual/dmi/id
cat ${dir}/$1 | sed -e 's# *$##' -e 's# +# #'
}
# get information on running system based on hardware and hostname.
# usage :
# case `sys-info` in
# MSI*/hostnane)
# - make some action
# ;;
# Asus/XXX/*)
# - make other action
# ;;
# *)
# - default action
# echo you should configure an action for `sys-info`
# ;;
# esac
sys-info () {
# printf "%s/%s/%s\n" `dmi-info board_vendor` `dmi-info product_name` `dmi-info board_name`
printf "%s/%s/%s/%s\n" "`dmi-info board_vendor`" "`dmi-info product_name`" "`dmi-info board_name`" "`hostname`"
}
# send-notify allow to send message to desktop users.
# but send-notify won't be able to notify users whenn run from daemons as root user.
# alt-notify-send is an alternative way to send notifications.
alt-notify-send () {
user=`whoami`
pids=`pgrep -u $user gnome-panel`
title=$1
text=$2
timeout=$3
logger "${prog_name} : $text"
return 0
if [ -z "$title" ]; then
echo You need to give me a title >&2
exit 1
fi
if [ -z "$text" ]; then
text=$title
fi
if [ -z "$timeout" ]; then
timeout=60000
fi
# FIXME: need to work on this.
# now, there is multiple notification for one message.
for LINE in $(find /proc/ -maxdepth 2 -name environ -exec grep -z "^DBUS_SESSION_BUS_ADDRESS" {} \; | sort -uz | tr '\0' '\n' | grep -v 'guid='); do
eval $LINE
notify-send -u low -t $timeout "$title" "$text"
done;
}
# notification with original send-notify command ; won't work with daemon process (from UDEV)
alt-notify-send-xx () {
title=$1
msg=$2
timeout=$3
notify-send -t $timeout "$title" "$msg"
}
# ---------------------------------------------------------------------------------------------------
# main entry
# UDEV script won't be able to see mount points,
# need to fork and wait some time before mount point is available.
if [ "$1" == "--fork" ]; then
# When run from udev, we fork to return udev rules and wait for mounts.
shift # remove $1 (--fork)
bash $0 $* & # run in backgroud (fork)
exit 0
else
# now, we are in the forked process ; just sleep some time waiting for mounts.
sleep 2
# where backup partition is mounted
mount=`cat /proc/mounts | grep "${backup_name}" | cut -f 2 -d ' '`
# debug : which script is running (/usr/local/bin/usb-auto-backup ; mount/bin/usb-auto-backup
logger "${prog_name} running from $0"
# if [ $0 == "/usr/local/bin/usb-auto-backup" && -x ${mount}/bin/usb-auto-backup ]; then
# exec ${mount}/bin/usb-auto-backup $*
# fi
case `sys-info` in
# this part need user customisation.
# machine maison/bureau : MSI/MS-7641/760GM-P23(FX) (MS-7641)/raring
MSI/MS-7641/760GM-P23*)
logger "${prog_name} maison/bureau"
destdir=${mount}/marc/
logfile=${destdir}/marc-backup.log
exclude=$destdir/exclude.rsync
alt-notify-send "${prog_name}" 'la sauvegarde va commencer'
sleep 1
alt-notify-send "${prog_name}" 'début sauvegarde images'
# backup /extra/images, /home/marc to destdir.
rsync -avz --exclude '*~' --exclude '*.NEF' --exclude '*.nef' --inplace --delete /extra/images ${destdir} > $logfile
alt-notify-send "${prog_name}" 'début sauvegarde /home'
rsync -avz --exclude '*~' --inplace --delete --delete-excluded --exclude-from=${exclude} /home/marc ${destdir}/home >> $logfile
alt-notify-send "${prog_name} : fin de la sauvegarde log : ${logfile}" 0
echo "fin de la sauvegarde" >> $logfile
exit 0
;;
# pc portable Acer / maison : Acer/Aspire 7720/Poyang/portable-pangolin
Acer*Aspire*7720*)
logger "${prog_name} portable Acer"
destdir=${mount}/tine/
logfile=${destdir}/tine-backup.log
exclude=$destdir/exclude.rsync
alt-notify-send "${prog_name}" 'la sauvegarde va commencer'
sleep 1
# backup /home to destdir.
alt-notify-send "${prog_name}" 'début sauvegarde images'
rsync -avz --exclude '*~' --inplace --delete -delete-excluded --exclude-from=${exclude} /home/ ${destdir}/home >> $logfile
exit 0
;;
*)
id=`sys-info`
echo "machine non supportée ; à configurer ($id)"
exit 1
;;
esac
fi
# ------------------------------------------------------------------------------------------------------------------
# docs :
#
# rsync options
# -a archive mode, equal to -rlptgoD
# -r recursive
# -l copy symlinks as symlinks
# -p preserve permissions
# -t preserve modification times
# -g preserve group
# -o preserve owner (super-user only)
# -D preserve device files (super-user only) and special files
# -v increase verbosity
# -b make backups
# -u skip files that are newer on the receiver
# -z compress file data during the transfer
# --backup-dir=DIR make backups into hierarchy based in DIR
# --delete delete extraneous files from dest dirs
@G-eos
Copy link

G-eos commented Feb 28, 2016

Hello Does it works ? the fork seems not operate and systemd kill the script :-(
Thanks in advance

@G-eos
Copy link

G-eos commented Feb 28, 2016

After some digging. Doing like this is not the good way.
Look at here: https://forums.opensuse.org/showthread.php/485261-Script-run-from-udev-rule-gets-killed-shortly-after-start
-> Use udev and systemd to build a simple "service"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment