#!/bin/sh
#
# samba-torture
#
# Script to stress-test Samba restarts with file system notify loks
#
# Author: Peter Eriksson <pen@lysator.liu.se>

# User to login as
TESTUSER="$USER"

# Server to test
TESTHOST="localhost"

# Path to already existing test directory on server
TESTPATH="changeme"

# Number of concurrent test clients to start for each iteration
NCLIENTS=1

# How to restart Samba. Valid options:
#
# restart               = service samba_server restart
# stop-start            = service samba_server stop ; service samba_server start
# stop-wait-start       = service samba_server stop ; wait-for-all-to-die ; service samba_server start
# pkill-smbd-winbindd   = pkill smbd+wait ; pkill winbindd+wait ; service samba_server start
# pkill-winbindd-smbd   = pkill winbindd+wait ; pkill smbd+wait ; service samba_server start
# pidfiles-smbd-winbind = kill pidof(smbd)+wait ; kill pidof(winbindd)+wait ; service samba_server start
# pidfiles-winbind-smbd = kill pidof(winbind)+wait ; kill pidof(smbd)+wait ; service samba_server start
#
KILLMODE=restart

# Where the Samba PID files are located
PIDDIR=/var/samba/run


MORE=yes
while [ $MORE = yes ]; do
    case "$1" in
	-h|--help)
	    echo "Usage:"
	    echo "  $0 [<options>] [<killmode>]"
	    echo ""
	    echo "Options:"
	    echo "  -h|--help"
	    echo "  -U|--user <name>"
	    echo "  -H|--host <name>"
	    echo "  -D|--dir <path>"
	    echo "  -C|--clients <count>"
	    echo "  -P|--pid <path>"
	    echo ""
	    echo "Killmodes:"
	    echo "  restart"
	    echo "  stop-start"
	    echo "  stop-wait-start"
	    echo "  pkill-smbd-winbindd"
	    echo "  pkill-winbindd-smbd"
	    echo "  pidfiles-smbd-winbind"
	    echo "  pidfiles-winbind-smbd"
	    exit 0
	    ;;
	-U|--user)
	    TESTUSER="$2"
	    shift
	    ;;
	-H|--host)
	    TESTHOST="$2"
	    shift
	    ;;
	-D|--dir*)
	    TESTPATH="$2"
	    shift
	    ;;
	-C|--clients)
	    NCLIENTS="$2"
	    shift
	    ;;
	-P|--pid*)
	    PIDDIR="$2"
	    shift
	    ;;
	-|--)
	    shift
	    MORE=no
	    ;;
	-*)
	    echo "$0: Error: $1: Invalid option" >&2
	    exit 1;
	    ;;
	*)
	    MORE=no
	    ;;
    esac
    if [ $MORE = yes ]; then
	shift
    fi
done

if [ "$1" != "" ]; then
    KILLMODE="$1"
fi

waitfor() {
    NAME="$1"
    PID="$2"

    echo "Waiting for $NAME (parent $PID) to die:"
    WPID=""
    if [ "$PID" != "" ]; then
	WPID="-s $PID"
	NAME=""
    fi
    while pgrep -q $WPID $NAME; do
	echo -n "."
    done
    echo ""
}


kinit "$TESTUSER" || exit 1

while true; do
    SMBDPID=""
    WINBPID=""
    if [ -f $PIDDIR/smbd.pid ]; then
	SMBDPID="`cat $PIDDIR/smbd.pid`"
    fi
    if [ -f $PIDDIR/winbindd.pid ]; then
	WINBPID="`cat $PIDDIR/winbindd.pid`"
    fi
    
    case $KILLMODE in
	restart)
	    service samba_server restart
	    ;;

	stop-start)
	    service samba_server stop
	    service samba_server start
	    ;;
	
	stop-wait-start)
	    service samba_server stop
	    waitfor "smbd" $SMBDPID
	    waitfor "winbindd" $WINBPID
	    service samba_server start
	    ;;
	
	pkill-smbd-winbindd)
	    echo "Terminating smbd:"
	    pkill smbd
	    waitfor "smbd"
	    echo "Terminating winbind:"
	    pkill winbindd
	    waitfor "winbindd"
	    echo "Restarting"
	    service samba_server start
	    ;;

	pkill-winbindd-smbd)
	    echo "Terminating winbind:"
	    pkill winbindd
	    waitfor "winbindd"
	    echo "Terminating smbd:"
	    pkill smbd
	    waitfor "smbd"
	    echo "Restarting"
	    service samba_server start
	    ;;

	pidfiles-smbd-winbindd)
	    if [ "$SMBDPID" != "" ]; then
		echo "Terminating smbd:"
		kill -TERM $SMBDPID
		waitfor "smbd" $SMBDPID
	    fi
	    if [ "$WINBPID" != "" ]; then
		echo "Terminating winbind:"
		kill -TERM $WINBPID
		waitfor "winbindd" $WINBPID
	    fi
	    echo "Restarting"
	    service samba_server start
	    ;;

	pidfiles-winbindd-smbd)
	    if [ "$WINBPID" != "" ]; then
		echo "Terminating winbind:"
		kill -TERM $WINBPID
		waitfor "winbindd" $WINBPID
	    fi
	    echo "Terminating smbd:"
	    if [ "$SMBDPID" != "" ]; then
		kill -TERM $SMBDPID
		waitfor "smbd" $SMBDPID
	    fi
	    echo "Restarting"
	    service samba_server start
	    ;;

	*)
	    echo "$0: Error: $1: Invalid killmode" >&2
	    exit 1
	    ;;
    esac

    echo "Waiting for clients to terminate"
    wait

    echo "Sleeping 5 seconds"
    sleep 5
    
    echo "Starting $NCLIENTS clients..."
    for N in `seq 1 $NCLIENTS`; do
	smbclient -k "//$TESTHOST/$TESTUSER" -c "notify $TESTPATH" >/dev/null &
    done

    echo "Sleeping 10 seconds"
    sleep 10
done
