nutools/utrigger

195 lines
5.5 KiB
Plaintext
Raw Permalink Normal View History

2013-08-27 15:14:44 +04:00
#!/bin/bash
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
source "$(dirname -- "$0")/lib/ulib/ulib" || exit 1
2014-07-07 22:06:38 +04:00
urequire base pretty
2013-08-27 15:14:44 +04:00
function display_help() {
uecho "$scriptname: lancer une commande en différé
USAGE
$scriptname [options] -- command [args]
La commande est lancée après un certain temps, sauf si ce script est rappelé
(auquel cas le compte est réinitialisé), ou si l'opération est annulée.
2013-10-16 10:07:20 +04:00
Attention! La commande est lancée en tâche de fond, et son entrée standard est
2013-08-27 15:14:44 +04:00
connectée à un fichier qui peut être provisionné avec l'option -a
note: ce script ne fonctionne que sous Linux puisqu'il utilise la commande flock
OPTIONS
-n, --name NAME
Spécifier un nom identifiant la tâche. Par défaut, le nom est généré à
partir des détails de la tâche à lancer. Ce nom est utilisé pour
identifier les invocations successives.
-f, --cmdfile CMDFILE
Spécifier un fichier contenant les commandes à lancer. Le fichier est
sourcé dans un sous-shell. Utiliser - pour lire les commandes depuis
l'entrée standard.
--rundelay RUNDELAY[=$RUNDELAY]
2013-10-16 10:07:20 +04:00
Nombre de secondes au bout desquelles la commande est lancée. Si ce
script est relancé avant la fin de ce décompte, le compte est remis à
zéro.
2013-08-27 15:14:44 +04:00
Utiliser --rundelay '' pour désactiver cette fonctionnalité, auquel cas
la commande est lancée immédiatement.
-s, --sudo
Forcer l'exécution de la commande avec l'utilisateur root si ce n'est
pas déjà le cas
-a, --datafile DATAFILE
Accumuler des données à fournir à la commande. Les informations du
fichier DATAFILE (utiliser - pour l'entrée standard) sont ajoutées à un
fichier temporaires, et sont fournies en une seule fois à la commande
sur son entrée standard.
-A, --data DATA
Variante de --datafile où les données sont fournies sur la ligne de
commande au lieu d'un fichier externe. Si les deux options -a et -A sont
spécifiées, les données sont accumulées dans l'ordre --datafile puis
--data
-k, --cancel
Annuler le lancement planifié d'une commande. Si la commande est déjà en
train de tourner, cette option n'a aucun effet."
}
RUNDELAY=5
2013-08-27 15:14:44 +04:00
function acquire_lock() {
eval "exec $1>'$2'"
flock $3 "$1"
}
function release_lock() {
rm "$2"
eval "exec $1>&-"
}
name=
cmdfile=
rundelay="$RUNDELAY"
run_as_root=
datafile=
data=
cancel=
parse_opts "${PRETTYOPTS[@]}" \
--help '$exit_with display_help' \
-n:,--name: name= \
-f:,--cmdfile: cmdfile= \
--rundelay: rundelay= \
-s,--sudo run_as_root=1 \
-a:,--datafile: datafile= \
-A:,--data: data= \
-k,--cancel cancel=1 \
@ args -- "$@" && set -- "${args[@]}" || die "$args"
if [ -n "$run_as_root" ]; then
args=(
-n "$name"
-f "$cmdfile"
--rundelay "$rundelay"
-a "$datafile"
-A "$data"
${cancel:+-k}
-- "$@"
)
run_as_root "${args[@]}"
fi
[ -n "$cmdfile" -o $# -gt 0 ] || die "Vous devez spécifier la commande à lancer"
[ -n "$cmdfile" -a $# -gt 0 ] && ewarn "Vous avez spécifié une commande et un fichier de commandes. La commande '$*' sera ignorée"
if [ -n "$name" ]; then
if is_root; then
base="/var/run/$scriptname/name/$name"
else
base="/tmp/$scriptname/name/$name"
fi
else
if is_root; then
base="/var/run/$scriptname/cmd"
else
base="/tmp/$scriptname/cmd"
fi
[ "$cmdfile" == "-" ] && cmdfile=/dev/stdin
if [ -n "$cmdfile" ]; then
# fichier de commande
cmdfile="$(abspath "$cmdfile")"
base="$base$cmdfile"
elif [ "${1#/}" != "$1" ]; then
# commande avec un chemin absolu
base="$base$1"
else
# commande avec un chemin relatif: il faut calculer le chemin absolu
if progexists "$1"; then
base="$base$(which "$1")"
else
base="$base/$1"
fi
fi
fi
mkdirof "$base"
if [ "$cmdfile" == "/dev/stdin" ]; then
# commandes lues depuis stdin
cmdfile="$base"
cat >"$cmdfile"
fi
# données en cours de collecte
podata="$base.podata"
polock="$base.polock"
function acquire_po() { acquire_lock 7 "$polock" "$*"; }
function release_po() { release_lock 7 "$polock" "$*"; }
# données à traiter
codata="$base.codata"
# commande à lancer
uslock="$base.uslock"
function acquire_us() { acquire_lock 8 "$uslock" "$*"; }
function release_us() { release_lock 8 "$uslock" "$*"; }
uspid="$base.uspid"
function __update_pending() {
touch "$podata"
[ "$datafile" == "-" ] && datafile=/dev/stdin
[ -n "$datafile" ] && stdredir "$datafile" ">>$podata" "" cat
[ -n "$data" ] && echo "$data" >>"$podata"
2013-08-27 15:14:44 +04:00
}
function __run_command() { (
exec <"$codata"
if [ -n "$cmdfile" ]; then
source "$cmdfile"
else
"$@"
fi
); }
acquire_po
__update_pending
release_po
if acquire_us -n; then
(
[ -f "$uspid" ] && {
pid=$(<"$uspid")
kill -0 "$pid" >&/dev/null && kill "$pid"
rm "$uspid"
}
if [ -n "$cancel" ]; then
release_us
exit 0
fi
echo $BASHPID >"$uspid"
release_us
[ -n "$rundelay" ] && sleep "$rundelay"
acquire_us
while [ -f "$podata" ]; do
acquire_po
mv "$podata" "$codata"
release_po
__run_command "$@"
rm "$codata"
done
rm "$uspid"
release_us
) &
fi