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" ] &&
etitle "Installation de /etc/init.d/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
echo -n -
local first="${1:1}"; shift
echo "$first" "$@"
echo "$first$@"
else
echo "$*"
echo "$@"
fi
}
function recho_() {
@ -49,9 +49,9 @@ function recho_() {
if [[ "${1:0:2}" == -[eEn] ]]; then
echo -n -
local first="${1:1}"; shift
echo -n "$first" "$@"
echo -n "$first$@"
else
echo -n "$*"
echo -n "$@"
fi
}
function qval() {
@ -88,7 +88,7 @@ function qvals() {
[ -z "$first" ] && echo -n " "
if should_quote "$arg"; then
echo -n \"
qv "$arg"
qval "$arg"
echo -n \"
else
recho_ "$arg"
@ -733,7 +733,7 @@ function array_extend_lasts() {
function array_xsplit() {
# 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).
eval "$1=($(<<<"$2" stripnl | awkrun RS="${3:-:}" '
eval "$1=($(recho_ "$2" | awkrun RS="${3:-:}" '
{
gsub(/'\''/, "'\'\\\\\'\''")
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
# par $3, qui vaut ':' par défaut). Les éléments vides sont ignorés. par exemple
# "a::b" est équivalent à "a:b"
eval "$1=($(<<<"$2" stripnl | awkrun RS="${3:-:}" '
eval "$1=($(recho_ "$2" | awkrun RS="${3:-:}" '
/^$/ { next }
{
gsub(/'\''/, "'\'\\\\\'\''")
@ -755,7 +755,7 @@ function array_from_path() {
}
function array_from_xlines() {
# créer le tableau $1 avec chaque ligne de $2.
eval "$1=($(<<<"$2" _nl2lf | awk '
eval "$1=($(recho_ "$2" | _nl2lf | awk '
{
gsub(/'\''/, "'\'\\\\\'\''")
print "'\''" $0 "'\''"
@ -763,7 +763,7 @@ function array_from_xlines() {
}
function array_from_lines() {
# 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 }
{
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
USAGE
$scriptname [options] /path/to/crontab
$scriptname -l [/path/to/crontab]
$scriptname [options] [/path/to/crontab]
$scriptname -e [/path/to/crontab]
$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.
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
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.
@ -157,17 +166,29 @@ Les lignes commençant par # sont des commentaires et sont ignorées
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.
Installer une planification toutes les minutes du script dans la crontab
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
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.
Désinstaller la planification toutes les minutes du script du crontab de
l'utilisateur. Si l'argument /path/to/crontab est spécifié, cette
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
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 son exécution a été planifiée.
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
@ -198,9 +219,23 @@ OPTIONS AVANCEES
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_LOCKDELAY=8
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
lockfile=auto
@ -217,43 +252,97 @@ parse_opts "${PRETTYOPTS[@]}" \
-c,--continuous continuous=1 \
-k:,--stop: USCRONTAB_STOPEC= \
-l,--list action=list \
-e,--edit action=edit \
-r,--remove action=remove \
@ args -- "$@" && set -- "${args[@]}" || die "$args"
if [ "$action" == "list" ]; then
crontab="$1"; shift
[ -n "$crontab" ] && crontab="$(abspath "$crontab")"
crontab="$1"; shift
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é"
if [ "$action" == "edit" ]; then
if [ -z "$crontab" ]; then
basedir="$(dirname "$USCRONTAB_USERFILE")"
[ -d "$basedir" ] || die "$basedir: ce répertoire n'existe pas. Vérifiez l'installation de nutools"
crontab="$USCRONTAB_USERFILE"
fi
enote "Edition de $crontab"
if [ ! -f "$crontab" ]; then
touch "$crontab"
chmod 640 "$crontab"
fi
"${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
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
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")"
[ -z "$crontab" -o -f "$crontab" ] || die "$crontab: fichier introuvable"
[ -n "$crontab" ] && crontab="$(abspath "$crontab")"
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
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
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 is_root; then
lockfile="/var/run/$scriptname$crontab.lock"
lockfile="$default_lockfile"
mkdirof "$lockfile" || die
else
lockfile=
@ -263,6 +352,8 @@ elif [ "$action" == "run" ]; then
if [ -n "$lockfile" ]; then
lockwarn="${lockfile%.lock}.lockwarn"
autoclean "$lockwarn"
retry=1
while [ -n "$retry" ]; do
case "$(lf_trylock -h "$lockdelay" "$lockfile")" in
@ -285,7 +376,8 @@ elif [ "$action" == "run" ]; then
*) retry=;;
esac
done
[ -f "$lockwarn" ] && rm "$lockwarn"
ac_clean "$lockwarn"
autoclean "$lockfile"
fi
@ -314,21 +406,29 @@ elif [ "$action" == "run" ]; then
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 status
pidfile_set -r "$1"; 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 $(<"$1")
puis supprimez le cas échéant le fichier $1"
return "$USCRONTAB_STOPEC"
;;
10)
die "Une erreur s'est produite pendant l'écriture du fichier de pid. Impossible de continuer"
;;
esac
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
@ -340,12 +440,16 @@ puis supprimez le cas échéant le fichier $1"
return 0
}
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
eval "$ctscript"
ac_cleanall
); ec=$?
[ -f "$lockfile" ] && rm "$lockfile"
ac_clean "$lockfile"
exit "$ec"
fi