nutools/urunserial

172 lines
6.2 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 suite de commande en respectant une planification de type cron
USAGE
$scriptname [options] /path/to/crontab
Ce script doit normalement être lancé toutes les minutes par une tâche cron. A
chaque lancement, il examine quels scripts doivent être exécutés dans le fichier
crontab spécifié. Ce fichier est composé de lignes d'une des formes suivantes,
qui sont analysées et traitées dans l'ordre:
# commentaire ignoré
var=\"initialiser une variable\"
minutes hours days months dows command [args]
Quelles que soient les lignes qui sont sélectionnées pour le lancement, elles
sont garanties de s'exécuter sériellement dans l'ordre du fichier, d'où le nom
de ce script.
Certaines extensions par rapport à la syntaxe de crontab sont autorisées. Il est
en particulier possible de spécifier plusieurs planifications pour une seule
commande. Par exemple, la ligne suivante permet d'exécuter 'command' toutes les
heures ET à 1h05:
0 * * * *
5 1 * * * command
De plus, il est possible de manipuler les variables de type PATH avec une
syntaxe particulière de l'opérateur d'assignation. Les opérateurs += et %=
utilisent uaddpath(), #= utilise uinspath() et -= utilise udelpath(). Par
exemple, les lignes suivantes ajoutent respectivement /usr/local/nutools puis
enlèvent /opt/rogue au PATH:
PATH+=/usr/local/nutools
PATH-=/opt/rogue
OPTIONS
--install
Installer une planification toutes les minutes de ce script dans la
crontab de l'utilisateur.
--uninstall
Désinstaller la planification toutes les minutes de ce script du crontab
de l'utilisateur.
--lock LOCKFILE
Inscrire dans le fichier spécifié des informations permettant d'éviter
les invocations simultanées de ce script. Si selon ce fichier, le script
tourne depuis plus de $LOCKDELAY heures, un message d'erreur est loggé
et un message d'avertissement est affiché au plus une fois.
Utiliser --lock '' pour désactiver cette fonctionnalité
Par défaut, si ce script est lancé en root, le fichier utilisé pour le
verrouillage est de la forme /var/run/$scriptname/abspath/to/crontab
Si le script est lancé avec un compte utilisateur, aucun verrouillage
n'est effectué.
--lockdelay LOCKDELAY[=$LOCKDELAY]
Changer le nombre d'heures pendant lesquelles on autorise le script a
verrouiller l'exécution avant d'afficher un avertissement.
-n, --fake
Afficher au lieu de les exécuter les commandes qui doivent être lancées
-c, --continuous
Par défaut, ce script s'arrête à la première commande qui retourne avec
une code d'erreur. Avec cette option, ce script ne s'arrête jamais, bien
qu'il retourne toujours un code d'erreur si une erreur s'est produite.
-k, --stopec EXITCODE[=101]
Spécifier un code d'erreur spécial qui arrête ce script sans erreur, ou
'' pour désactiver cette fonctionnalité. Ceci permet en début de script
de faire des tests par exemple sur l'environnement avant de lancer les
scripts planifiés. Si l'environnement ne convient pas, il suffit au
script de contrôle de retourner le code d'erreur spécifique pour arrêter
le traitement."
}
source "$(dirname "$0")/ulib/ulib" &&
urequire DEFAULTS crontab ||
exit 1
MY_CTLINE="* * * * * $script"
LOCKDELAY=8
action=run
lockfile=auto
lockdelay=
fake=
continuous=
stopec=101
parse_opts "${PRETTYOPTS[@]}" \
--help '$exit_with display_help' \
--add,--install action=install \
--remove,--uninstall action=uninstall \
--lock: lockfile= \
--lockdelay: lockdelay= \
-n,--fake fake=1 \
-c,--continuous continuous=1 \
-k:,--stop: stopec=1 \
@ args -- "$@" && set -- "${args[@]}" || die "$args"
crontab="$1"; shift
[ -n "$crontab" ] || die_with "Vous devez spécifier le fichier crontab" display_help
[ -f "$crontab" ] || die "$crontab: fichier introuvable"
crontab="$(abspath "$crontab")"
if [ "$action" == "install" ]; then
enable_in_crontab "$MY_CTLINE $(quoted_arg "$crontab")" && estep "add_to_crontab $MY_CTLINE $(quoted_arg "$crontab")"
elif [ "$action" == "uninstall" ]; then
remove_from_crontab "$MY_CTLINE $(quoted_arg "$crontab")" && estep "remove_from_crontab $MY_CTLINE $(quoted_arg "$crontab")"
elif [ "$action" == "run" ]; then
if [ "$lockfile" == auto ]; then
if is_root; then
lockfile="/var/run/$scriptname$crontab.lock"
mkdirof "$lockfile" || die
else
lockfile=
fi
fi
[ -n "$lockdelay" ] || lockdelay="$LOCKDELAY"
if [ -n "$lockfile" ]; then
lockwarn="${lockfile%.lock}.lockwarn"
retry=1
while [ -n "$retry" ]; do
case "$(lf_trylock -h "$lockdelay" "$lockfile")" in
locked)
edebug "Arrêt du script parce que le verrou $lockfile est posé"
exit 0
;;
stale)
msg="Un verrou sur '$scriptname $crontab' est posé depuis plus de $lockdelay heures. Veuillez faire vos vérification et supprimer le cas échéant le fichier $lockfile"
logger -p cron.warn -t "$scriptname" -- "$msg"
if [ -f "$lockwarn" ]; then
edebug "$msg"
else
touch "$lockwarn"
ewarn "$msg"
fi
exit 1
;;
retry) :;;
*) retry=;;
esac
done
[ -f "$lockwarn" ] && rm "$lockwarn"
autoclean "$lockfile"
fi
function __ctexec() {
local ec=0
if [ -n "$fake" ]; then
echo "$*"
else
edebug "$*"
(eval "$*"); ec=$?
fi
[ -n "$stopec" -a "$ec" == "$stopec" ] && exit 0
[ -z "$continuous" -a "$ec" != 0 ] && exit "$ec"
return 0
}
function __cterror() {
die "$*"
}
ctscript="$(ctresolve <"$crontab")"
ec=0
edebug "$ctscript"
(eval "$ctscript"); ec=$?
[ -f "$lockfile" ] && rm "$lockfile"
exit "$ec"
fi