200 lines
5.5 KiB
Bash
Executable File
200 lines
5.5 KiB
Bash
Executable File
#!/bin/bash
|
|
# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
|
|
|
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.
|
|
Attention! La commande lancée en tâche de fond, et son entrée standard est
|
|
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]
|
|
Nombre de secondes au bout duquel la commande est lancée. Si ce script
|
|
est relancé avant la fin de ce décompte, le compte est remis à zéro.
|
|
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
|
|
|
|
source "$(dirname "$0")/ulib/ulib" &&
|
|
urequire base pretty ||
|
|
exit 1
|
|
|
|
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
|
|
if [ -n "$datafile" ]; then
|
|
cat "$datafile" >>"$podata"
|
|
fi
|
|
if [ -n "$data" ]; then
|
|
echo "$data" >>"$podata"
|
|
fi
|
|
}
|
|
|
|
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
|