204 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			204 lines
		
	
	
		
			7.4 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
 | |
|     $scriptname -l [/path/to/crontab]
 | |
| 
 | |
| La première forme du script doit normalement être lancé toutes les minutes par
 | |
| une tâche cron. Utiliser l'option --install pour ajouter automatique la ligne
 | |
| dans la crontab de l'utilisateur.
 | |
| 
 | |
| A chaque lancement du script, 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 dans l'ordre du fichier, l'une après l'autre.
 | |
| 
 | |
| 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
 | |
|     -A, --install
 | |
|         Installer une planification toutes les minutes de ce script dans la
 | |
|         crontab de l'utilisateur. L'argument /path/to/crontab est requis.
 | |
|     -R, --uninstall
 | |
|         Désinstaller la planification toutes les minutes de ce script du crontab
 | |
|         de l'utilisateur. L'argument /path/to/crontab est requis, et seule cette
 | |
|         instance est désinstallée le cas échéant.
 | |
|     -l, --list
 | |
|         Lister les contenus des fichiers crontab dont l'exécution a été
 | |
|         planifiée avec --install
 | |
|         Si /path/to/crontab est spécifié, ne lister le contenu de ce fichier que
 | |
|         si et seulement si son exécution a été planifiée.
 | |
|     -n, --fake
 | |
|         Afficher au lieu de les exécuter les commandes qui doivent être lancées
 | |
| 
 | |
| OPTIONS AVANCEES
 | |
|     --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.
 | |
|     -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' \
 | |
|     -A,--add,--install action=install \
 | |
|     -R,--remove,--uninstall action=uninstall \
 | |
|     --lock: lockfile= \
 | |
|     --lockdelay: lockdelay= \
 | |
|     -n,--fake fake=1 \
 | |
|     -c,--continuous continuous=1 \
 | |
|     -k:,--stop: stopec=1 \
 | |
|     -l,--list action=list \
 | |
|     @ args -- "$@" && set -- "${args[@]}" || die "$args"
 | |
| 
 | |
| if [ "$action" == "list" ]; then
 | |
|     crontab="$1"; shift
 | |
|     [ -n "$crontab" ] && crontab="$(abspath "$crontab")"
 | |
| 
 | |
|     array_from_lines ctfiles "$(crontab -l 2>/dev/null | awkrun script="$script" '$6 == script { print $7 }')"
 | |
|     found=
 | |
|     for ctfile in "${ctfiles[@]}"; do
 | |
|         if [ -z "$crontab" -o "$ctfile" == "$crontab" ]; then
 | |
|             found=1
 | |
|             etitle "$(ppath "$ctfile")"
 | |
|             cat "$ctfile"
 | |
|             eend
 | |
|         fi
 | |
|     done
 | |
|     if [ -n "$crontab" -a -z "$found" ]; then
 | |
|         ewarn "$(ppath "$crontab"): non planifié"
 | |
|     fi
 | |
|     exit 0
 | |
| fi
 | |
| 
 | |
| 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
 | 
