inotifydev (Source)

#!/bin/bash
##---------------------------------------------------------------------------##
#
#   Script:  inotifydev
#   Author:  Brian <genius@groupbcl.ca> :)
#   Date:    August 2017
#
#   Using 'inotifywait,' watches /dev for device files being created and
#   removed, usually in response to a USB device being connected and dis-
#   connected. When a device appears, this script searches the directory in
#   which it was started for a script named 'inotifydev-X-device', where X
#   is the name of the device that appeared (e.g. 'inotifydev-ttyUSB0-device'
#   for a serial device.) If no file with that name is present, it searches
#   for a generic script by trimming the last character off the name (e.g.
#   'inotifydev-ttyUSB-device'.) The search continues until it gets a match
#   or only one charcter remains; that is it will search down to
#   'inotifydev-tt-device' but not to 'inotifydev-t-device.')
#
#   If a matching script name is found, it is called with two parameters:
#   'CREATE' or 'DELETE' and the device name (without the leading /dev/).
#
#   "inotifydev" is intended to be run at startup. For systemd setups, put
#   the following text into /etc/systemd/system/inotifydev.service, then
#   run "systemctl enable inotifydev" (or run "inotifydev --install" to
#   have this script to the work for you):
#
#       [Unit]
#       After=network-online.target
#
#       [Service]
#       Type=simple
#       ExecStart=/usr/local/bin/inotifydev start
#       ExecStop=/usr/local/bin/inotifydev stop
#       Restart=on-failure
#
#       [Install]
#       WantedBy=multi-user.target
#
#   The "inotifydev --install" function can also set up a System V init
#   script on systems descended from Red Hat or Debian.
#
##---------------------------------------------------------------------------##
#   BUUS: This script is part of Brian's Useful Utilities Set
##---------------------------------------------------------------------------##
EXEC_DN="$(dirname $0)"
[ -d /run ] && RUN_DN='/run/inotifydev'
[ -d /var/run ] && RUN_DN='/var/run/inotifydev'
[ "$RUN_DN" ] || RUN_DN='/tmp/inotifydev'
[ -d $RUN_DN ] || mkdir $RUN_DN
PIPE_FN="$RUN_DN/inotifydev.pipe"
PID_FN="$RUN_DN/inotifydev.pid"
INOTIFYWAIT_PID_FN="$RUN_DN/inotifydev-inotifywait.pid"

##---------------------------------------------------------------------------##
#   startup - start inotifydev
##---------------------------------------------------------------------------##
function startup {
    # If we're not running under systemd, we need to add our own timestamps
    # to the log file lines
    ADD_TIMESTAMPS=false
    [ "$1" == '--background' ] && ADD_TIMESTAMPS=true

    # At startup, look for inotifydev-*-device files. If devics enamed
    # in the file exist, run the script with CREATE and the device name
    ls -l $EXEC_DN/inotifydev-*-device &>/dev/null
    if [ $? == 0 ]
    then
        for SCRIPT_FN in $EXEC_DN/inotifydev-*-device
        do
            DEVICE_TYPE="$(basename $SCRIPT_FN)"
            DEVICE_TYPE="${DEVICE_TYPE#inotifydev-}"
            DEVICE_TYPE="${DEVICE_TYPE%-device}"
            echo $SCRIPT_FN $DEVICE_TYPE
            ls /dev/${DEVICE_TYPE}* &>/dev/null
            if [ $? == 0 ]
            then
                ls /dev/${DEVICE_TYPE}* | while read DEV
                do
                    DEVICE="${DEV#/dev/}"
                    $ADD_TIMESTAMPS && TIMESTAMP="$(date +'%F %T')  "
                    echo "${TIMESTAMP}Run $SCRIPT_FN CREATE $DEVICE"
                    $SCRIPT_FN CREATE $DEVICE &
                done
            fi
        done
    fi

    # Create a pipe and start inotifwait on it
    mknod $PIPE_FN p
    inotifywait -qm -e create -e delete /dev >$PIPE_FN 2>/dev/null &
    echo $! >$INOTIFYWAIT_PID_FN
    $ADD_TIMESTAMPS && TIMESTAMP="$(date +'%F %T')  "
    echo "${TIMESTAMP}Created pipe file $PIPE_FN and started inotifywait on PID $!"

    # Wait for create and delete events in /dev. As each new device appears
    # or disappears, launch a handler script for it, if one exists.
    cat $PIPE_FN | while read LINE
    do
        ACTION="${LINE:6:6}"
        DEVICE="${LINE:13}"
        L=${#DEVICE}
        while [ $L -gt 1 ]
        do
            SCRIPT_FN="inotifydev-${DEVICE:0:$L}-device"
            [ -x "$EXEC_DN/$SCRIPT_FN" -o -L "$EXEC_DN/$SCRIPT_FN" ] && L=0
            L=$((L-1))
            [ $L == 1 ] && SCRIPT_FN=""
        done
        $ADD_TIMESTAMPS && TIMESTAMP="$(date +'%F %T')  "
        if [ "$SCRIPT_FN" ]
        then
            echo "${TIMESTAMP}Run $EXEC_DN/$SCRIPT_FN $ACTION $DEVICE"
            $EXEC_DN/$SCRIPT_FN $ACTION $DEVICE &
        else
            echo "${TIMESTAMP}$ACTION: No inotifydev device script found for $DEVICE"
        fi
    done
    $ADD_TIMESTAMPS && TIMESTAMP="$(date +'%F %T')  "
    echo "${TIMESTAMP}Pipe was closed; shutting down"
}


##---------------------------------------------------------------------------##
#   startup_bg: start a new instance of inotifydev in the background, for
#   systems that are running System V init scripts.
##---------------------------------------------------------------------------##
function startup_bg {
    # Rotate the log files
    cd /var/log
    [ -f inotifydev.log.9.bz2 ] && rm -f inotifydev.log.9.bz2
    for N in 8 7 6 5 4 3 2
    do
        [ -f inotifydev.log.$N.bz2 ] &&
            mv inotifydev.log.$N.bz2 inotifydev.log.$((N+1)).bz2 
    done
    if [ -f inotifydev.log.1 ]
    then
        mv inotifydev.log.1 inotifydev.log.2
        bzip2 inotifydev.log.2
    fi
    [ -f inotifydev.log ] && mv inotifydev.log inotifydev.log.1

    # Now start a new instance in the background
    nohup $0 start --background </dev/null &>/var/log/inotifydev.log &
    echo $! >$PID_FN
    # (Red Hat's startup functions really want a PID file in /var/run)
    [ -d /var/run -a ! -f /var/run/inotifydev.pid ] &&
        ln $PID_FN  /var/run/inotifydev.pid
}


##---------------------------------------------------------------------------##
#   shutdown - stop inotifydev
##---------------------------------------------------------------------------##
function shutdown {
    if [ -f $INOTIFYWAIT_PID_FN ]
    then
        kill $(< $INOTIFYWAIT_PID_FN)
    else
        echo "INOTIFYWAIT_PID_FN file not found; attempting to locate and kill inotifywait"
        INOTIFYWAIT_PID="$(ps -ef | grep -v awk | awk '/inotifywait -qm/{ print $2 }')"
        [ "$INOTIFYWAIT_PID" ] && kill $INOTIFYWAIT_PID
    fi
    rm -f $PIPE_FN $INOTIFYWAIT_PID_FN $PID_FN
}


##---------------------------------------------------------------------------##
#   install - set up inotifydev in a System V or systemd environment
##---------------------------------------------------------------------------##
function __install_die { echo "inotifydev: $1"; exit 1; }

function __install_sys_v {
    INSTALL_TYPE=sys_v
    INIT_SCRIPT='/etc/init.d/inotifydev'
    [ -f "$INIT_SCRIPT" -o -L "$INIT_SCRIPT" ] &&
        __install_die "inotifydev appears to be installed already (found $INIT_SCRIPT)"

    # Ensure the needed utilities are in place for the install
    which base64 &>/dev/null || __install_die echo "install failed; cannot find base64"
    which chkconfig &>/dev/null && CONFIG_CMD=chkconfig
    which update-rc.d &>/dev/null && CONFIG_CMD=update-rc.d
    [ "$CONFIG_CMD" ] || __install_die "cannot determine System V setup script:" \
        "not RedHat (chkconfg) or Debian (update-rc.d)"

    # Extract the init script from this file
    echo "Setting up /etc/init.d/inotifydev"
    sed '1,/^# \/etc\/init.d\/inotifydev/d; s/^# //' $0 |
        base64 -d | gunzip >$INIT_SCRIPT
    chmod +x $SCRIPT_FN

    # Update the System V startup links
    echo "Running $CONFIG_CMD"
    [ "$CONFIG_CMD" == 'RedHat' ] && chkconfig --add inotifydev
    [ "$CONFIG_CMD" == 'Debian' ] && update-rc.d inotifydev start 27 3 4 5 stop 73 0 1 6
}

function __install_systemd {
    INSTALL_TYPE=systemd
    SERVICE_FN="/etc/systemd/system/inotifydev.service"
    [ -f $SERVICE_FN ] &&
        __install_die "inotifydev appears to be installed already (found $SERVICE_FN)"
    echo "Setting up service file $SERVICE_FN"
    UNIT_START="$(grep -n '^#[[:space:]]*\[Unit\]$' /usr/local/bin/inotifydev | cut -f1 -d:)"
    UNIT_STOP="$(grep -n '^#[[:space:]]*WantedBy=' /usr/local/bin/inotifydev | cut -f1 -d:)"
    sed "1,$((UNIT_START-1))d; $((UNIT_STOP+1)),\$d; s/^#[[:space:]]*//" $0 >$SERVICE_FN
    systemctl enable inotifydev
    echo "Starting inotifydev"
    systemctl start inotifydev
    [ $? == 0 ] && echo "Started" || echo "Attempt to start inotifydev failed"
}

function install {
    [ -d /etc/init.d -o -L /etc/init.d ] && __install_sys_v
    [ -d /etc/systemd/system ] && __install_systemd
    [ "$INSTALL_TYPE" ] || echo "Unable to determine system initialization type;" \
        "it's not System V nor systemd"
}


##---------------------------------------------------------------------------##
#       Main processing
##---------------------------------------------------------------------------##
trap shutdown INT
case $1 in
    start)      startup $2;;
    background) startup_bg;;
    stop)       shutdown;;
    --install)  install;;
    *)          echo "usage: inotifydev start|stop";;
esac
exit

# /etc/init.d/inotifydev (gzipped, base64)
# H4sICGzfvVkAA2lub3RpZnlkZXYAlVNda9tAEHz2/YqNbAIpleQmKQEbUwrtQ6FPbdKXtJDzaWUd
# tu/U+7Ad4v737p1kS6EhuMag097s7szsaniWz6XKbcWGbAjfHTfO12CFkbWDUhuQSjtZPha4eQvb
# SooKjFe2RVgKoQK6lAKhlCu0wOsauaFiUgFXBRTSNiEojV5DTuDYS1RLoVUpFxO4un4Plzdwc0Xh
# ApvSUqsJ3Fby0Or/ifykam3n16hAbbRAaxVf46TXJdzIIpSaQL7hJqd2eXfdO2aEY8E97U3o7pUI
# 9GEl54abx4xlkKMTuRFZQWnS0eMAsr1EhW6rzVKqBTTOeMMD5ljAPtrmIm+hjHUsZrm3Jl9pwVdx
# pD0l95CWMOoC8Av2e8CddDBm7Nvn2x8fv87GkQkiVHoLW6S/QaBiKywyJrhFSEbvEjKIDWxYkws2
# GMgS7mF09+UTpAphTHWn4GgQdDVAUWlI7iwaqLilPOvLUgqJypHlckPGLjBLIjQwuaZTKVmbmCpI
# 4jYGNzrmEwgJBcc1+Zum7YBOmM8z+XMulgujvSqoWCt/9KFtTQ/S1EQhxd9R1vk5OO1p52InMnmZ
# Wz+nefRtHgym02COrltvHFoHye6hpanLsGo9NSfwfkjgbAa7o61Av86gyrtoUKG36h+XArSvOhA7
# eHyqaLMOq/OK6JckxO/hYAZ33gY7mhM8s6vPIqANHjdrND7wjSeKvoB/c8G6PeML+lAJ/BTR+5C9
# bwvum+Z/gitx1y4ZWi4Yiy+tbMb+Ag+mM/4MBQAA

# vim: tabstop=4