Merge branch 'uscrontab'

This commit is contained in:
Jephté Clain 2014-04-23 18:59:08 +04:00
commit 39d3c37912
4 changed files with 173 additions and 59 deletions

View File

@ -71,3 +71,13 @@ etitle "Installation de /etc/init.d/kvm-stop-all" \
[ -n "$openvz_service" ] && [ -n "$openvz_service" ] &&
etitle "Installation de /etc/init.d/openvz-fix-etchosts" \ etitle "Installation de /etc/init.d/openvz-fix-etchosts" \
"$scriptdir/../init.d/install-openvz-fix-etchosts" "$scriptdir/../init.d/install-openvz-fix-etchosts"
etitle "Installation des répertoires pour uscrontab"
if mkdir -p /var/uscrontab/crontabs; then
chmod 1733 /var/uscrontab/crontabs
else
eerror "Impossible de créer le répertoire /var/uscrontab/crontabs"
fi
eend
exit 0

View File

@ -1 +1 @@
34 35

View File

@ -38,9 +38,9 @@ function recho() {
if [[ "${1:0:2}" == -[eEn] ]]; then if [[ "${1:0:2}" == -[eEn] ]]; then
echo -n - echo -n -
local first="${1:1}"; shift local first="${1:1}"; shift
echo "$first" "$@" echo "$first$@"
else else
echo "$*" echo "$@"
fi fi
} }
function recho_() { function recho_() {
@ -49,9 +49,9 @@ function recho_() {
if [[ "${1:0:2}" == -[eEn] ]]; then if [[ "${1:0:2}" == -[eEn] ]]; then
echo -n - echo -n -
local first="${1:1}"; shift local first="${1:1}"; shift
echo -n "$first" "$@" echo -n "$first$@"
else else
echo -n "$*" echo -n "$@"
fi fi
} }
function qval() { function qval() {
@ -88,7 +88,7 @@ function qvals() {
[ -z "$first" ] && echo -n " " [ -z "$first" ] && echo -n " "
if should_quote "$arg"; then if should_quote "$arg"; then
echo -n \" echo -n \"
qv "$arg" qval "$arg"
echo -n \" echo -n \"
else else
recho_ "$arg" recho_ "$arg"
@ -733,7 +733,7 @@ function array_extend_lasts() {
function array_xsplit() { function array_xsplit() {
# créer le tableau $1 avec chaque élément de $2 (un ensemble d'éléments séparés # créer le tableau $1 avec chaque élément de $2 (un ensemble d'éléments séparés
# par $3, qui vaut ':' par défaut). # par $3, qui vaut ':' par défaut).
eval "$1=($(<<<"$2" stripnl | awkrun RS="${3:-:}" ' eval "$1=($(recho_ "$2" | awkrun RS="${3:-:}" '
{ {
gsub(/'\''/, "'\'\\\\\'\''") gsub(/'\''/, "'\'\\\\\'\''")
print "'\''" $0 "'\''" print "'\''" $0 "'\''"
@ -743,7 +743,7 @@ function array_split() {
# créer le tableau $1 avec chaque élément de $2 (un ensemble d'éléments séparés # créer le tableau $1 avec chaque élément de $2 (un ensemble d'éléments séparés
# par $3, qui vaut ':' par défaut). Les éléments vides sont ignorés. par exemple # par $3, qui vaut ':' par défaut). Les éléments vides sont ignorés. par exemple
# "a::b" est équivalent à "a:b" # "a::b" est équivalent à "a:b"
eval "$1=($(<<<"$2" stripnl | awkrun RS="${3:-:}" ' eval "$1=($(recho_ "$2" | awkrun RS="${3:-:}" '
/^$/ { next } /^$/ { next }
{ {
gsub(/'\''/, "'\'\\\\\'\''") gsub(/'\''/, "'\'\\\\\'\''")
@ -755,7 +755,7 @@ function array_from_path() {
} }
function array_from_xlines() { function array_from_xlines() {
# créer le tableau $1 avec chaque ligne de $2. # créer le tableau $1 avec chaque ligne de $2.
eval "$1=($(<<<"$2" _nl2lf | awk ' eval "$1=($(recho_ "$2" | _nl2lf | awk '
{ {
gsub(/'\''/, "'\'\\\\\'\''") gsub(/'\''/, "'\'\\\\\'\''")
print "'\''" $0 "'\''" print "'\''" $0 "'\''"
@ -763,7 +763,7 @@ function array_from_xlines() {
} }
function array_from_lines() { function array_from_lines() {
# créer le tableau $1 avec chaque ligne de $2. Les lignes vides sont ignorés. # créer le tableau $1 avec chaque ligne de $2. Les lignes vides sont ignorés.
eval "$1=($(<<<"$2" _nl2lf | awk ' eval "$1=($(recho_ "$2" | _nl2lf | awk '
/^$/ { next } /^$/ { next }
{ {
gsub(/'\''/, "'\'\\\\\'\''") gsub(/'\''/, "'\'\\\\\'\''")

202
uscrontab
View File

@ -6,13 +6,22 @@ function display_help() {
uecho "$scriptname: lancer une suite de commande en respectant une planification de type cron uecho "$scriptname: lancer une suite de commande en respectant une planification de type cron
USAGE USAGE
$scriptname [options] /path/to/crontab $scriptname [options] [/path/to/crontab]
$scriptname -l [/path/to/crontab] $scriptname -e [/path/to/crontab]
$scriptname -l
La première forme du script doit normalement être lancé toutes les minutes par 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 une tâche cron. Utiliser l'option --install pour ajouter automatique la ligne
dans la crontab de l'utilisateur. dans la crontab de l'utilisateur.
Si aucun fichier n'est spécifié, fusionner s'il existe le fichier
$USCRONTAB_USERFILE
avec chacun des fichiers du répertoire
$USCRONTAB_USERDIR
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 du script, il examine quels scripts doivent être exécutés 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 dans un dans le fichier crontab spécifié. Ce fichier est composé de lignes dans un
format particulier, qui sont analysées et traitées dans l'ordre. format particulier, qui sont analysées et traitées dans l'ordre.
@ -157,17 +166,29 @@ Les lignes commençant par # sont des commentaires et sont ignorées
OPTIONS OPTIONS
-A, --install -A, --install
Installer une planification toutes les minutes de ce script dans la Installer une planification toutes les minutes du script dans la crontab
crontab de l'utilisateur. L'argument /path/to/crontab est requis. de l'utilisateur. Si l'argument /path/to/crontab n'est pas spécifié,
c'est une planification générique qui exécute les fichiers par défaut.
-R, --uninstall -R, --uninstall
Désinstaller la planification toutes les minutes de ce script du crontab Désinstaller la planification toutes les minutes du script du crontab de
de l'utilisateur. L'argument /path/to/crontab est requis, et seule cette l'utilisateur. Si l'argument /path/to/crontab est spécifié, cette
instance est désinstallée le cas échéant. instance est désinstallée. Sinon, ne désinstaller que la planification
générique.
-e, --edit
Lancer un editeur pour modifier la crontab spécifiée. Si aucun fichier
n'est spécifié, éditer $USCRONTAB_USERFILE
-r, --remove
Supprimer le fichier $USCRONTAB_USERFILE s'il existe
Si l'argument /path/to/crontab est spécifié, il est ignoré.
-l, --list -l, --list
Lister les contenus des fichiers crontab dont l'exécution a été Si l'argument /path/to/crontab est spécifié, afficher le contenu de ce
planifiée avec --install fichier. Sinon, lister les contenus des fichiers crontab qui sont
Si /path/to/crontab est spécifié, ne lister le contenu de ce fichier que exécutés avec la planification actuelle. Si une planification générique
si son exécution a été planifiée. 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 -n, --fake
Afficher au lieu de les exécuter les commandes qui doivent être lancées Afficher au lieu de les exécuter les commandes qui doivent être lancées
@ -198,9 +219,23 @@ OPTIONS AVANCEES
le traitement." le traitement."
} }
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[@]}")'
}
USCRONTAB_CTLINE="* * * * * $script" USCRONTAB_CTLINE="* * * * * $script"
USCRONTAB_LOCKDELAY=8 USCRONTAB_LOCKDELAY=8
USCRONTAB_STOPEC=101 USCRONTAB_STOPEC=101
USCRONTAB_BASEDIR=/var/uscrontab
USCRONTAB_USERFILE="$USCRONTAB_BASEDIR/crontabs/$USER"
USCRONTAB_USERDIR="$USCRONTAB_BASEDIR/$USER.d"
USCRONTAB_USER="$USCRONTAB_BASEDIR/$USER"
action=run action=run
lockfile=auto lockfile=auto
@ -217,43 +252,97 @@ parse_opts "${PRETTYOPTS[@]}" \
-c,--continuous continuous=1 \ -c,--continuous continuous=1 \
-k:,--stop: USCRONTAB_STOPEC= \ -k:,--stop: USCRONTAB_STOPEC= \
-l,--list action=list \ -l,--list action=list \
-e,--edit action=edit \
-r,--remove action=remove \
@ args -- "$@" && set -- "${args[@]}" || die "$args" @ args -- "$@" && set -- "${args[@]}" || die "$args"
if [ "$action" == "list" ]; then crontab="$1"; shift
crontab="$1"; shift
[ -n "$crontab" ] && crontab="$(abspath "$crontab")"
array_from_lines ctfiles "$(crontab -l 2>/dev/null | awkrun script="$script" '$6 == script { print $7 }')" if [ "$action" == "edit" ]; then
found= if [ -z "$crontab" ]; then
for ctfile in "${ctfiles[@]}"; do basedir="$(dirname "$USCRONTAB_USERFILE")"
if [ -z "$crontab" -o "$ctfile" == "$crontab" ]; then [ -d "$basedir" ] || die "$basedir: ce répertoire n'existe pas. Vérifiez l'installation de nutools"
found=1 crontab="$USCRONTAB_USERFILE"
etitle "$(ppath "$ctfile")" fi
cat "$ctfile" enote "Edition de $crontab"
eend if [ ! -f "$crontab" ]; then
fi touch "$crontab"
done chmod 640 "$crontab"
if [ -n "$crontab" -a -z "$found" ]; then fi
ewarn "$(ppath "$crontab"): non planifié" "${EDITOR:-vi}" "$crontab"
exit 0
elif [ "$action" == "remove" ]; then
[ -n "$crontab" ] && ewarn "$crontab: cet argument a été ignoré"
crontab="$USCRONTAB_USERFILE"
if [ -f "$crontab" ]; then
ask_yesno "Voulez-vous supprimer le fichier $crontab?" C || die
enote "Suppression de $crontab"
rm "$crontab" || die
fi fi
exit 0 exit 0
elif [ "$action" == "list" ]; then
if [ -n "$crontab" ]; then
crontab="$(abspath "$crontab")"
array_from_lines ctfiles "$(crontab -l 2>/dev/null | awkrun script="$script" crontab="$crontab" '$6 == script && $7 == crontab { print $7 }')"
if [ ${#ctfiles[*]} -eq 0 ]; then
ewarn "$(ppath "$crontab"): non planifié"
ctfiles=("$crontab")
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
fi fi
crontab="$1"; shift [ -z "$crontab" -o -f "$crontab" ] || die "$crontab: fichier introuvable"
[ -n "$crontab" ] || die_with "Vous devez spécifier le fichier crontab" display_help [ -n "$crontab" ] && crontab="$(abspath "$crontab")"
[ -f "$crontab" ] || die "$crontab: fichier introuvable"
crontab="$(abspath "$crontab")"
if [ "$action" == "install" ]; then if [ "$action" == "install" ]; then
enable_in_crontab "$USCRONTAB_CTLINE $(quoted_arg "$crontab")" && estep "add_to_crontab $USCRONTAB_CTLINE $(quoted_arg "$crontab")" ctline="$USCRONTAB_CTLINE"
[ -n "$crontab" ] && ctline="$ctline $(quoted_arg "$crontab")"
enable_in_crontab "$ctline" && estep "add_to_crontab $ctline"
elif [ "$action" == "uninstall" ]; then elif [ "$action" == "uninstall" ]; then
remove_from_crontab "$USCRONTAB_CTLINE $(quoted_arg "$crontab")" && estep "remove_from_crontab $USCRONTAB_CTLINE $(quoted_arg "$crontab")" ctline="$USCRONTAB_CTLINE"
[ -n "$crontab" ] && ctline="$ctline $(quoted_arg "$crontab")"
remove_from_crontab "$ctline" && estep "remove_from_crontab $ctline"
elif [ "$action" == "run" ]; then elif [ "$action" == "run" ]; then
clean_crontab=
if [ -n "$crontab" ]; then
default_lockfile="/var/run/$scriptname$crontab.lock"
else
set_usercrontabs usercrontabs
ac_set_tmpfile crontab
clean_crontab=1
for usercrontab in "${usercrontabs[@]}"; do
echo "# $usercrontab" >>"$crontab"
cat "$usercrontab" >>"$crontab"
done
default_lockfile="/var/run/$scriptname$USCRONTAB_USER.lock"
fi
if [ "$lockfile" == auto ]; then if [ "$lockfile" == auto ]; then
if is_root; then if is_root; then
lockfile="/var/run/$scriptname$crontab.lock" lockfile="$default_lockfile"
mkdirof "$lockfile" || die mkdirof "$lockfile" || die
else else
lockfile= lockfile=
@ -263,6 +352,8 @@ elif [ "$action" == "run" ]; then
if [ -n "$lockfile" ]; then if [ -n "$lockfile" ]; then
lockwarn="${lockfile%.lock}.lockwarn" lockwarn="${lockfile%.lock}.lockwarn"
autoclean "$lockwarn"
retry=1 retry=1
while [ -n "$retry" ]; do while [ -n "$retry" ]; do
case "$(lf_trylock -h "$lockdelay" "$lockfile")" in case "$(lf_trylock -h "$lockdelay" "$lockfile")" in
@ -285,7 +376,8 @@ elif [ "$action" == "run" ]; then
*) retry=;; *) retry=;;
esac esac
done done
[ -f "$lockwarn" ] && rm "$lockwarn"
ac_clean "$lockwarn"
autoclean "$lockfile" autoclean "$lockfile"
fi fi
@ -314,21 +406,29 @@ elif [ "$action" == "run" ]; then
ec=0 ec=0
edebug "$ctscript" 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() { function check_pidfile() {
if [ -n "$1" ]; then if [ -n "$1" ]; then
local status local pidfile="$(abspath "$1")"
pidfile_set -r "$1"; status=$? if ! array_contains __USCRONTAB_PIDFILES "$pidfile"; then
case "$status" in local status
1) pidfile_set -r "$pidfile"; status=$?
eerror "${2:-Une synchronisation} est en cours. case "$status" in
Si vous pensez que c'est une erreur, veuillez vérifier le process de pid $(<"$1") 1)
puis supprimez le cas échéant le fichier $1" eerror "${2:-Une synchronisation} est en cours.
return "$USCRONTAB_STOPEC" 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"
10) return "$USCRONTAB_STOPEC"
die "Une erreur s'est produite pendant l'écriture du fichier de pid. Impossible de continuer" ;;
;; 10)
esac die "Une erreur s'est produite pendant l'écriture du fichier de pid. Impossible de continuer"
;;
esac
array_add __USCRONTAB_PIDFILES "$pidfile"
fi
fi fi
if [ -n "$3" -a -w "$(dirname "$3")" ]; then if [ -n "$3" -a -w "$(dirname "$3")" ]; then
(set -o noclobber (set -o noclobber
@ -340,12 +440,16 @@ puis supprimez le cas échéant le fichier $1"
return 0 return 0
} }
function remove_pidfile() { function remove_pidfile() {
[ -n "$1" ] && ac_clean "$1" if [ -n "$1" ]; then
local pidfile="$(abspath "$1")"
ac_clean "$pidfile"
array_del __USCRONTAB_PIDFILES "$pidfile"
fi
} }
__ac_forgetall __ac_forgetall
eval "$ctscript" eval "$ctscript"
ac_cleanall ac_cleanall
); ec=$? ); ec=$?
[ -f "$lockfile" ] && rm "$lockfile" ac_clean "$lockfile"
exit "$ec" exit "$ec"
fi fi