561 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			561 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Bash
		
	
	
		
			Executable File
		
	
	
	
	
| #!/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
 | |
| urequire DEFAULTS crontab install
 | |
| 
 | |
| function display_help() {
 | |
|     uecho "$scriptname: lancer une suite de commande en respectant une planification de type cron
 | |
| 
 | |
| USAGE
 | |
|     $scriptname [options] [/path/to/uscrontab] [var=value...]
 | |
|     $scriptname -e [/path/to/uscrontab]
 | |
|     $scriptname -l
 | |
| 
 | |
| 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.
 | |
| 
 | |
| Avec la première forme du script, le fichier spécifié est traité. Si aucun
 | |
| fichier n'est spécifié, fusionner s'il existe le fichier
 | |
|     $USCRONTAB_USERFILE
 | |
| avec chacun des fichiers du répertoire
 | |
|     $USCRONTAB_USERDIR
 | |
| dans un fichier temporaire, puis exécuter le fichier résultat avec le nom
 | |
| virtuel
 | |
|     $USCRONTAB_USER
 | |
| note: le nom virtuel est utilisé pour le verrouillage avec --lock
 | |
| 
 | |
| A chaque lancement de ce script, le fichier /path/to/uscrontab spécifié est
 | |
| examiné pour déterminer quels commandes doivent être exécutées. Ce fichier est
 | |
| composé de lignes dans un format particulier, qui sont analysées et traitées
 | |
| dans l'ordre.
 | |
| 
 | |
| Quelles que soient les lignes qui sont sélectionnées pour l'exécution, elles
 | |
| sont garanties de s'exécuter dans l'ordre du fichier, l'une après l'autre.
 | |
| 
 | |
| Les définitions var=value mentionnées sur la ligne de commande sont des
 | |
| définitions de variables à effectuer avant de lancer les commandes.
 | |
| 
 | |
| Les lignes commençant par # sont des commentaires et sont ignorées
 | |
| 
 | |
| == Définitions de variables et exécution de commandes ==
 | |
| 
 | |
|     Les lignes de la forme suivante sont des définitions de variable:
 | |
| 
 | |
|         [export] var=\"valeur de la variable\"
 | |
| 
 | |
|     Ces lignes sont des définitions de variable bash qui sont exécutées telles
 | |
|     quelles. Il n'est donc pas autorisé de mettre des espaces autour de =. Par
 | |
|     exemple, les lignes suivantes sont des erreurs de syntaxe:
 | |
| 
 | |
|         var = bad
 | |
|         var=pas de quotes autour de la valeur
 | |
| 
 | |
|     alors que celles-ci sont correctes:
 | |
| 
 | |
|         var=ok
 | |
|         var=\"valeur avec des espaces\"
 | |
|         var='on peut utiliser des quotes aussi'
 | |
| 
 | |
|     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
 | |
| 
 | |
|     Bien sûr, il ne faut pas oublier de quoter les espaces:
 | |
| 
 | |
|         PATH+=\"/path/to/dir with spaces\"
 | |
| 
 | |
|     La syntaxe ?= permet de définir la valeur d'une variable si elle n'est pas
 | |
|     déjà définie:
 | |
| 
 | |
|         var?=default
 | |
| 
 | |
|     Les lignes de la forme suivante permettent d'exécuter une commande qui est
 | |
|     exécutée systématiquement et ignore la planification:
 | |
| 
 | |
|         \$one-line-command
 | |
| 
 | |
|     Une variante permet de spécifier des commandes sur plusieurs lignes.
 | |
|     ATTENTION! \${ et $} doivent être tous seuls sur la ligne.
 | |
| 
 | |
|         \${
 | |
|         several
 | |
|         commands
 | |
|         ...
 | |
|         $}
 | |
| 
 | |
|     Ces commandes sont exécutées systématiquement et ignorent la planification.
 | |
|     On peut s'en servir notamment pour lire un fichier de configuration qui
 | |
|     définit des variables ou des fonctions:
 | |
| 
 | |
|         \$source path/to/file
 | |
| 
 | |
| == Planification de commandes ==
 | |
| 
 | |
|     Les autres lignes doivent être au format d'une ligne de crontab:
 | |
| 
 | |
|         minutes hours days months dows command-line
 | |
| 
 | |
|     command-line peut être n'importe quelle ligne de commande bash, pourvu
 | |
|     qu'elle soit sur une seule ligne.
 | |
| 
 | |
|     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, les lignes suivantes permettent d'exécuter
 | |
|     'command' toutes les heures ET à 1h05:
 | |
| 
 | |
|         0 * * * *
 | |
|         5 1 * * * command
 | |
| 
 | |
|     Il est aussi possible d'utiliser la même planification pour plusieurs
 | |
|     commandes sans devoir répéter la définition de la planification. Les lignes
 | |
|     suivantes planifient command1 et command2 toutes les heures:
 | |
| 
 | |
|         0 * * * * command1
 | |
|                   command2
 | |
| 
 | |
|     Pour être prise en compte, la ligne command2 doit commencer par au moins un
 | |
|     espace ou une tabulation. Pour la lisibilité, la syntaxe suivante est
 | |
|     supportée aussi:
 | |
| 
 | |
|         0 * * * *
 | |
|           command1
 | |
|           command2
 | |
| 
 | |
|     Les deux formats peuvent être utilisés ensemble. Par exemple les lignes
 | |
|     suivantes exécutent command1 et command2 toutes les heures ET à 1h05:
 | |
| 
 | |
|         0 * * * *
 | |
|         5 1 * * * command1
 | |
|                   command2
 | |
| 
 | |
| == Fonctions disponibles ==
 | |
| 
 | |
|     La fonction check_pidfile() est disponible, et permet de vérifier qu'une
 | |
|     opération n'est pas déjà en cours. Si cette fonction est utilisée, il ne
 | |
|     faut pas modifier la valeur de -k. Par exemple:
 | |
| 
 | |
|         0 1 * * *
 | |
|           check_pidfile /path/to/pid [args]
 | |
|           long-running-script
 | |
| 
 | |
|     check_pidfile() doit être utilisée toute seule sur la ligne et s'utilise
 | |
|     avec les argument suivants:
 | |
| 
 | |
|         check_pidfile PIDFILE [DESC] [BARRIER]
 | |
| 
 | |
|     - PIDFILE est le fichier de PID qui est vérifié
 | |
|     - DESC est la description du traitement qui est effectué. La valeur par
 | |
|       défaut est \"Une synchronisation\". Si le fichier de PID est présent, le
 | |
|       message suivant est affiché:
 | |
|         DESC est en cours.
 | |
|         Si vous pensez que c'est une erreur, veuillez vérifier le process de pid PID
 | |
|         puis supprimez le cas échéant le fichier PIDFILE
 | |
|     - BARRIER est un fichier qui est créé avec le contenu 'PID' s'il n'existe
 | |
|       pas encore, et si la vérification du fichier de PID est faite avec succès.
 | |
|       La présence de ce fichier peut-être vérifiée par un processus externe pour
 | |
|       empêcher par exemple de mettre à jour les scripts pendant qu'il sont en
 | |
|       train de tourner.
 | |
|       Son contenu peut être examiné pour connaître le PID du processus qui l'a
 | |
|       créé initialement. Le fichier est automatiquement supprimé à la fin de ce
 | |
|       script.
 | |
|       Attention: ce fichier n'est pas un verrou, il peut être supprimé à tout
 | |
|       moment. Notamment, si deux scripts sont configurés pour créer le même
 | |
|       fichier barrière, le premier script supprimera le fichier barrière avant
 | |
|       la fin de l'exécution du second script.
 | |
| 
 | |
|     La fonction remove_pidfile() permet de supprimer un fichier de pid pour
 | |
|     spécifier qu'une opération est terminée. Considérons l'exemple suivant:
 | |
| 
 | |
|         0 1 * * *
 | |
|           check_pidfile /path/to/pid
 | |
|           script1
 | |
|           script2
 | |
|           remove_pidfile /path/to/pid
 | |
|           script3
 | |
| 
 | |
|     Dans cet exemple, il ne faut pas qu'une autre occurence de script1 tourne
 | |
|     pendant que script2 tourne. Par contre, plusieurs occurences de script3
 | |
|     peuvent tourner en parallèle.
 | |
| 
 | |
|     La fonction elogto() permet de spécifier un fichier vers lequel toutes les
 | |
|     sorties sont redirigées.
 | |
| 
 | |
| OPTIONS
 | |
|     -A, --install
 | |
|         Installer une planification toutes les minutes du script dans la crontab
 | |
|         de l'utilisateur. Si l'argument /path/to/uscrontab n'est pas spécifié,
 | |
|         c'est une planification générique qui exécute les fichiers par défaut
 | |
|         qui est installée.
 | |
|     -R, --uninstall
 | |
|         Désinstaller la planification toutes les minutes du script de la crontab
 | |
|         de l'utilisateur. Si l'argument /path/to/uscrontab est spécifié, cette
 | |
|         instance est désinstallée. Sinon, ne désinstaller que la planification
 | |
|         générique.
 | |
|     -d, --disable-only
 | |
|         Avec l'option -R, désactiver la planification au lieu de la supprimer.
 | |
|     -e, --edit
 | |
|         Lancer un editeur pour modifier l'uscrontab spécifiée. Si aucun fichier
 | |
|         n'est spécifié, éditer $USCRONTAB_USERFILE
 | |
|     -a, --add
 | |
|         Installer un script uscrontab dans le répertoire approprié. L'argument
 | |
|         doit être de la forme [name:]/path/to/uscrontab
 | |
|         Si name n'est pas spécifié, le nom de base du fichier spécifié est
 | |
|         utilisé. Si name est vide ou vaut \$USER (soit $USER en l'occurence),
 | |
|         copier le fichier spécifié vers le chemin $USCRONTAB_USERFILE
 | |
|         Sinon, copier le fichier spécifié vers $USCRONTAB_USERDIR/name
 | |
|     -r, --remove
 | |
|         Supprimer le script uscrontab spécifié. L'argument doit être le nom du
 | |
|         script à supprimer.  Si l'argument n'est pas spécifié ou vaut \$USER
 | |
|         (soit $USER en l'occurence), supprimer le fichier $USCRONTAB_USERFILE
 | |
|         s'il existe
 | |
|     -l, --list
 | |
|         Si l'argument /path/to/crontab est spécifié, afficher le contenu de ce
 | |
|         fichier. Sinon, lister les contenus des fichiers crontab qui sont
 | |
|         exécutés avec la planification actuelle. Si une planification générique
 | |
|         est installée, ou si aucune planification n'est en cours, afficher le
 | |
|         contenu du fichier
 | |
|             $USCRONTAB_USERFILE
 | |
|         et chacun des fichiers du répertoire
 | |
|             $USCRONTAB_USERDIR
 | |
|     -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 $USCRONTAB_LOCKDELAY heures, un message d'erreur
 | |
|         est consigné 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[=$USCRONTAB_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.
 | |
|     --show-ctnow
 | |
|         Afficher l'heure de référence au format crontab 'min hou day mon dow'
 | |
|         Cette valeur peut être utilisée avec l'option --force-ctnow dans des
 | |
|         tests pour reproduire une condition spécifique.
 | |
|     --force-ctnow 'min hou day mon dow'
 | |
|         Pour le développement ou des tests, forcer la valeur de l'heure de
 | |
|         référence. Il faut respecter le format, sinon les résultats ne sont pas
 | |
|         garantis. Le mieux est de reprendre le résultat de l'option --show-ctnow
 | |
|         en le modifiant un peu si nécessaire."
 | |
| }
 | |
| 
 | |
| function set_usercrontabs() {
 | |
|     # initialiser le tableau $1(=usercrontabs) avec la liste suivante: le
 | |
|     # fichier $USCRONTAB_USERFILE s'il existe, puis la liste des fichiers dans
 | |
|     # le répertoire $USCRONTAB_USERDIR
 | |
|     local -a _userfile _userdir
 | |
|     [ -f "$USCRONTAB_USERFILE" ] && _userfile=("$USCRONTAB_USERFILE")
 | |
|     array_lsfiles _userdir "$USCRONTAB_USERDIR"
 | |
|     eval "${1:-usercrontabs}"'=("${_userfile[@]}" "${_userdir[@]}")'
 | |
| }
 | |
| 
 | |
| function get_usercrontab() {
 | |
|     # trouver le chemin correspondant au crontab $1. Si $1 n'est pas spécifié ou
 | |
|     # vaut $USER, afficher $USCRONTAB_USERFILE, sinon afficher $USCRONTAB_USERDIR/$1
 | |
|     local name="$1"
 | |
|     [ "$name" == "$USER" ] && name=
 | |
|     if [ -n "$name" ]; then
 | |
|         echo "$USCRONTAB_USERDIR/$name"
 | |
|     else
 | |
|         echo "$USCRONTAB_USERFILE"
 | |
|     fi
 | |
| }
 | |
| 
 | |
| USCRONTAB_CTLINE="* * * * * $script"
 | |
| USCRONTAB_LOCKDELAY=8
 | |
| USCRONTAB_STOPEC=101
 | |
| USCRONTAB_BASEDIR=/var/local/uscrontab
 | |
| USCRONTAB_USERFILE="$USCRONTAB_BASEDIR/users/$USER"
 | |
| USCRONTAB_USERDIR="$USCRONTAB_BASEDIR/users.d/$USER"
 | |
| USCRONTAB_USER="$USCRONTAB_BASEDIR/$USER"
 | |
| 
 | |
| action=run
 | |
| disable_only=
 | |
| lockfile=auto
 | |
| lockdelay=
 | |
| fake=
 | |
| continuous=
 | |
| parse_opts "${PRETTYOPTS[@]}" \
 | |
|     --help '$exit_with display_help' \
 | |
|     -A,--add,--install action=install \
 | |
|     -R,--remove,--uninstall action=uninstall \
 | |
|     -d,--disable-only '$action=uninstall; disable_only=1' \
 | |
|     -e,--edit action=edit \
 | |
|     -a,--add action=add \
 | |
|     -r,--remove action=remove \
 | |
|     -l,--list action=list \
 | |
|     -n,--fake fake=1 \
 | |
|     --lock: lockfile= \
 | |
|     --lockdelay: lockdelay= \
 | |
|     -c,--continuous continuous=1 \
 | |
|     -k:,--stop: USCRONTAB_STOPEC= \
 | |
|     --show-ctnow action=show-ctnow \
 | |
|     --force-ctnow: __CTRESOLVE_CTNOW= \
 | |
|     @ args -- "$@" && set -- "${args[@]}" || die "$args"
 | |
| 
 | |
| uscrontab="$1"; shift
 | |
| 
 | |
| if [ "$action" == "edit" ]; then
 | |
|     if [ -z "$uscrontab" ]; then
 | |
|         basedir="$(dirname "$USCRONTAB_USERFILE")"
 | |
|         [ -d "$basedir" ] || die "$basedir: ce répertoire n'existe pas. Vérifiez l'installation de nutools"
 | |
|         uscrontab="$USCRONTAB_USERFILE"
 | |
|     fi
 | |
|     enote "Edition de $uscrontab"
 | |
|     if [ ! -f "$uscrontab" ]; then
 | |
|         touch "$uscrontab" || die
 | |
|         chmod 640 "$uscrontab"
 | |
|     fi
 | |
|     "${EDITOR:-vi}" "$uscrontab" || die
 | |
|     exit 0
 | |
| 
 | |
| elif [ "$action" == "add" ]; then
 | |
|     [ -n "$uscrontab" ] || die "Vous devez spécifier le fichier à installer"
 | |
|     if [[ "$uscrontab" == *:* ]]; then
 | |
|         splitfsep2 "$uscrontab" : name uscrontab
 | |
|         [ -f "$uscrontab" ] || die "$uscrontab: fichier introuvable"
 | |
|     else
 | |
|         name="$(basename "$uscrontab")"
 | |
|     fi
 | |
|     dest="$(get_usercrontab "$name")"
 | |
| 
 | |
|     destdir="$(dirname -- "$dest")"
 | |
|     if [ ! -d "$destdir" ]; then
 | |
|         mkdir -p "$destdir" || die
 | |
|         chmod 750 "$destdir"
 | |
|     fi
 | |
| 
 | |
|     copy_update_ask "$uscrontab" "$dest"
 | |
|     exit 0
 | |
| 
 | |
| elif [ "$action" == "remove" ]; then
 | |
|     uscrontab="$(get_usercrontab "$uscrontab")"
 | |
|     if [ -f "$uscrontab" ]; then
 | |
|         ask_yesno "Voulez-vous supprimer le fichier $uscrontab?" C || die
 | |
|         enote "Suppression de $uscrontab"
 | |
|         rm "$uscrontab" || die
 | |
|     fi
 | |
|     exit 0
 | |
| 
 | |
| elif [ "$action" == "list" ]; then
 | |
|     if [ -n "$uscrontab" ]; then
 | |
|         uscrontab="$(abspath "$uscrontab")"
 | |
|         array_from_lines ctfiles "$(crontab -l 2>/dev/null | awkrun script="$script" uscrontab="$uscrontab" '$6 == script && $7 == uscrontab { print $7 }')"
 | |
|         if [ ${#ctfiles[*]} -eq 0 ]; then
 | |
|             ewarn "$(ppath "$uscrontab"): non planifié"
 | |
|             ctfiles=("$uscrontab")
 | |
|         fi
 | |
|     else
 | |
|         array_from_lines ctfiles "$(crontab -l 2>/dev/null | awkrun script="$script" '$6 == script { if ($7) print $7; else print "GENERIC" }')"
 | |
|         if array_contains ctfiles "GENERIC"; then
 | |
|             # il y a une planification générique
 | |
|             array_del ctfiles "GENERIC"
 | |
|             set_usercrontabs usercrontabs
 | |
|             array_extend ctfiles usercrontabs
 | |
|         elif [ ${#ctfiles[*]} -eq 0 ]; then
 | |
|             einfo "aucune planification en cours"
 | |
|             set_usercrontabs ctfiles
 | |
|         fi
 | |
|     fi
 | |
| 
 | |
|     r=1
 | |
|     for ctfile in "${ctfiles[@]}"; do
 | |
|         r=0 # il y a au moins une planification
 | |
|         etitle "$(ppath "$ctfile")" \
 | |
|             cat "$ctfile"
 | |
|     done
 | |
|     exit $r
 | |
| 
 | |
| elif [ "$action" == "show-ctnow" ]; then
 | |
|     ctnow
 | |
|     exit 0
 | |
| fi
 | |
| 
 | |
| [ -z "$uscrontab" -o -f "$uscrontab" ] || die "$uscrontab: fichier introuvable"
 | |
| [ -n "$uscrontab" ] && uscrontab="$(abspath "$uscrontab")"
 | |
| 
 | |
| if [ "$action" == "install" ]; then
 | |
|     ctline="$USCRONTAB_CTLINE"
 | |
|     [ -n "$uscrontab" ] && ctline="$ctline $(quoted_arg "$uscrontab")"
 | |
|     enable_in_crontab "$ctline" && estep "add_to_crontab $ctline"
 | |
| 
 | |
| elif [ "$action" == "uninstall" ]; then
 | |
|     ctline="$USCRONTAB_CTLINE"
 | |
|     [ -n "$uscrontab" ] && ctline="$ctline $(quoted_arg "$uscrontab")"
 | |
|     if [ -n "$disable_only" ]; then
 | |
|         disable_in_crontab "$ctline" && estep "disable_in_crontab $ctline"
 | |
|     else
 | |
|         remove_from_crontab "$ctline" && estep "remove_from_crontab $ctline"
 | |
|     fi
 | |
| 
 | |
| elif [ "$action" == "run" ]; then
 | |
|     if [ -n "$uscrontab" ]; then
 | |
|         default_lockfile="/var/run/$scriptname$uscrontab.lock"
 | |
|     else
 | |
|         set_usercrontabs usercrontabs
 | |
|         ac_set_tmpfile uscrontab
 | |
|         for usercrontab in "${usercrontabs[@]}"; do
 | |
|             echo "# $usercrontab" >>"$uscrontab"
 | |
|             cat "$usercrontab" >>"$uscrontab"
 | |
|         done
 | |
|         default_lockfile="/var/run/$scriptname$USCRONTAB_USER.lock"
 | |
|     fi
 | |
| 
 | |
|     if [ "$lockfile" == auto ]; then
 | |
|         if is_root; then
 | |
|             lockfile="$default_lockfile"
 | |
|             mkdirof "$lockfile" || die
 | |
|         else
 | |
|             lockfile=
 | |
|         fi
 | |
|     fi
 | |
|     [ -n "$lockdelay" ] || lockdelay="$USCRONTAB_LOCKDELAY"
 | |
| 
 | |
|     if [ -n "$lockfile" ]; then
 | |
|         lockwarn="${lockfile%.lock}.lockwarn"
 | |
|         autoclean "$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 $uscrontab' 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
 | |
| 
 | |
|         ac_clean "$lockwarn"
 | |
|         autoclean "$lockfile"
 | |
|     fi
 | |
| 
 | |
|     function __should_fork() {
 | |
|         # tester si la commande doit être lancée dans un sous-shell
 | |
|         local cmd
 | |
|         cmd="${1%% *}"
 | |
|         case "$cmd" in
 | |
|         check_pidfile|remove_pidfile|elogto) return 1;;
 | |
|         esac
 | |
|         return 0
 | |
|     }
 | |
|     function __ctexec() {
 | |
|         local ec=0
 | |
|         if [ -n "$fake" ]; then
 | |
|             echo "$*"
 | |
|         else
 | |
|             edebug "$*"
 | |
|             if __should_fork "$1"; then
 | |
|                 (eval "$*"); ec=$?
 | |
|             else
 | |
|                  # cas particulier: certaines fonctions doivent être exécutée
 | |
|                  # dans le contexte courant, et non pas dans un sous-shell
 | |
|                 eval "$*"; ec=$?
 | |
|             fi
 | |
|         fi
 | |
|         [ -n "$USCRONTAB_STOPEC" -a "$ec" == "$USCRONTAB_STOPEC" ] && exit 0
 | |
|         [ -z "$continuous" -a "$ec" != 0 ] && exit "$ec"
 | |
|         return 0
 | |
|     }
 | |
|     function __cterror() {
 | |
|         die "$*"
 | |
|     }
 | |
| 
 | |
|     __ctscript="$(ctresolve <"$uscrontab")"
 | |
|     ec=0
 | |
|     edebug "$__ctscript"
 | |
|     (
 | |
|         # tableau des fichiers de pid en cours. la conséquence est que ce n'est
 | |
|         # pas une erreur d'appeler à plusieurs reprises check_pidfile avec le
 | |
|         # même fichier
 | |
|         __USCRONTAB_PIDFILES=()
 | |
|         function check_pidfile() {
 | |
|             if [ -n "$1" ]; then
 | |
|                 local pidfile="$(abspath "$1")"
 | |
|                 if ! array_contains __USCRONTAB_PIDFILES "$pidfile"; then
 | |
|                     local status
 | |
|                     pidfile_set -r "$pidfile"; status=$?
 | |
|                     case "$status" in
 | |
|                     1)
 | |
|                         eerror "${2:-Une synchronisation} est en cours.
 | |
| Si vous pensez que c'est une erreur, veuillez vérifier le process de pid $(<"$pidfile")
 | |
| puis supprimez le cas échéant le fichier $pidfile"
 | |
|                         return "$USCRONTAB_STOPEC"
 | |
|                         ;;
 | |
|                     10)
 | |
|                         die "Une erreur s'est produite pendant l'écriture du fichier de pid. Impossible de continuer"
 | |
|                         ;;
 | |
|                     esac
 | |
|                     array_add __USCRONTAB_PIDFILES "$pidfile"
 | |
|                 fi
 | |
|             fi
 | |
|             if [ -n "$3" -a -w "$(dirname "$3")" ]; then
 | |
|                 (set -o noclobber
 | |
|                     echo_ $$ >"$3" &&
 | |
|                     chmod 644 "$3"
 | |
|                 ) 2>/dev/null &&
 | |
|                 autoclean "$3"
 | |
|             fi
 | |
|             return 0
 | |
|         }
 | |
|         function remove_pidfile() {
 | |
|             if [ -n "$1" ]; then
 | |
|                 local pidfile="$(abspath "$1")"
 | |
|                 ac_clean "$pidfile"
 | |
|                 array_del __USCRONTAB_PIDFILES "$pidfile"
 | |
|             fi
 | |
|         }
 | |
| 
 | |
|         __ac_forgetall
 | |
|         # Si des variables sont spécifiées, les initialiser avant de lancer le
 | |
|         # script
 | |
|         for __var in "$@"; do
 | |
|             splitvar "$__var" __name __value
 | |
|             edebug "$__name=$__value"
 | |
|             set_var "$__name" "$__value"
 | |
|         done
 | |
|         eval "$__ctscript"
 | |
|         ac_cleanall
 | |
|     ); ec=$?
 | |
| 
 | |
|     ac_clean "$uscrontab"
 | |
|     ac_clean "$lockfile"
 | |
| 
 | |
|     exit "$ec"
 | |
| fi
 | 
