333 lines
9.1 KiB
Bash
333 lines
9.1 KiB
Bash
##@cooked comments # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
|
|
## Gestion du fichier crontab
|
|
##@cooked nocomments
|
|
##@require base
|
|
uprovide crontab
|
|
urequire base
|
|
|
|
# Ajouter la ligne $1 au crontab de l'utilisateur $2
|
|
# Le code de retour est 123 si la ligne est déjà présente
|
|
function add_to_crontab() {
|
|
local -a crontab=(crontab ${2:+-u "$2"})
|
|
local current="$("${crontab[@]}" -l 2>/dev/null)"
|
|
local tmpfile
|
|
ac_set_tmpfile tmpfile
|
|
if [ -n "$current" ]; then
|
|
echo "$current" >"$tmpfile"
|
|
fi
|
|
local NL=$'\n'
|
|
if quietgrep -xF "$1$NL#$1" "$tmpfile"; then
|
|
ac_clean "$tmpfile"
|
|
return 123
|
|
else
|
|
echo "$1" >>"$tmpfile"
|
|
"${crontab[@]}" "$tmpfile"
|
|
ac_clean "$tmpfile"
|
|
fi
|
|
}
|
|
# Supprimer la ligne $1 du crontab de l'utilisateur $2
|
|
# Le code de retour est 123 si la ligne a déjà été supprimée
|
|
function remove_from_crontab() {
|
|
local -a crontab=(crontab ${2:+-u "$2"})
|
|
local current="$("${crontab[@]}" -l 2>/dev/null)"
|
|
local tmpfile
|
|
ac_set_tmpfile tmpfile
|
|
if [ -n "$current" ]; then
|
|
echo "$current" >"$tmpfile"
|
|
fi
|
|
local NL=$'\n'
|
|
if ! quietgrep -xF "$1$NL#$1" "$tmpfile"; then
|
|
ac_clean "$tmpfile"
|
|
return 123
|
|
else
|
|
grep -vxF "$1$NL#$1" "$tmpfile" | "${crontab[@]}" -
|
|
ac_clean "$tmpfile"
|
|
fi
|
|
}
|
|
# Désactiver la ligne $1 du crontab de l'utilisateur $2 en mettant '#' devant. Si
|
|
# la ligne n'existe pas, elle est ajoutée mais commentée.
|
|
# Le code de retour est 123 si la ligne est déjà désactivée
|
|
function disable_in_crontab() {
|
|
local -a crontab=(crontab ${2:+-u "$2"})
|
|
local current="$("${crontab[@]}" -l 2>/dev/null)"
|
|
local tmpfile
|
|
ac_set_tmpfile tmpfile
|
|
if [ -n "$current" ]; then
|
|
echo "$current" >"$tmpfile"
|
|
fi
|
|
local NL=$'\n'
|
|
if ! quietgrep -xF "$1$NL#$1" "$tmpfile"; then
|
|
echo "#$1" >>"$tmpfile"
|
|
"${crontab[@]}" "$tmpfile"
|
|
elif quietgrep -xF "#$1" "$tmpfile"; then
|
|
ac_clean "$tmpfile"
|
|
return 123
|
|
else
|
|
<"$tmpfile" awkrun line="$1" '$0 == line { $0 = "#" $0 } { print }' | "${crontab[@]}" -
|
|
ac_clean "$tmpfile"
|
|
fi
|
|
}
|
|
# Activer la ligne $1 du crontab de l'utilisateur $2 en enlevant '#' devant. Si
|
|
# la ligne n'existe pas, elle est ajoutée.
|
|
# Le code de retour est 123 si la ligne est déjà activée
|
|
function enable_in_crontab() {
|
|
local -a crontab=(crontab ${2:+-u "$2"})
|
|
local current="$("${crontab[@]}" -l 2>/dev/null)"
|
|
local tmpfile
|
|
ac_set_tmpfile tmpfile
|
|
if [ -n "$current" ]; then
|
|
echo "$current" >"$tmpfile"
|
|
fi
|
|
local NL=$'\n'
|
|
if ! quietgrep -xF "$1$NL#$1" "$tmpfile"; then
|
|
echo "$1" >>"$tmpfile"
|
|
"${crontab[@]}" "$tmpfile"
|
|
elif quietgrep -xF "$1" "$tmpfile"; then
|
|
ac_clean "$tmpfile"
|
|
return 123
|
|
else
|
|
<"$tmpfile" awkrun line="$1" '$0 == "#" line { sub(/^#/, "") } { print }' | "${crontab[@]}" -
|
|
ac_clean "$tmpfile"
|
|
fi
|
|
}
|
|
# Afficher la spécification crontab correspondant à l'heure courante
|
|
function ctnow() {
|
|
#date +"%-M %-H %-d %-m %u"
|
|
if [ -n "$1" ]; then
|
|
echo "$1" | awk '{ print strftime("%-M %-H %-d %-m %u", $0) }'
|
|
else
|
|
awk 'BEGIN { print strftime("%-M %-H %-d %-m %u", systime()) }'
|
|
fi
|
|
}
|
|
__CTRESOLVE_CTNOW=""
|
|
# Analyser STDIN qui contient des lignes au format crontab, et afficher des
|
|
# commandes pour les lignes correspondant à la date courante.
|
|
# Les commandes sont de la forme "export var=value" pour la définition d'une
|
|
# variable, "__ctexec 'cmd'" pour exécuter la commande correspondante ou
|
|
# "__cterror 'msg'" en cas d'erreur de syntaxe sur une ligne. Il faut bien
|
|
# entendu définir les function __ctexec et __cterror.
|
|
# Cette fonction s'utilise de cette manière:
|
|
# function __ctexec() { eval "$*"; }
|
|
# function __cterror() { die "$*"; }
|
|
# eval "$(ctresolve <crontab)"
|
|
function ctresolve() {
|
|
local -a ctnow
|
|
if [ -n "$__CTRESOLVE_CTNOW" ]; then
|
|
eval "ctnow=($__CTRESOLVE_CTNOW)"
|
|
else
|
|
eval "ctnow=($(ctnow))"
|
|
fi
|
|
filter_conf | awkrun -f ctnow[@] '
|
|
function ctmatch_one(ctval, ref, parts, part, i, j, start, end, step, ok) {
|
|
ok = 0
|
|
split(ctval, parts, /,/)
|
|
for(i = 1; i <= length(parts); i++) {
|
|
part = parts[i]
|
|
start = -1; end = -1; step = 1
|
|
# extraire /step
|
|
pos = index(part, "/")
|
|
if (pos != 0) {
|
|
step = substr(part, pos + 1) + 0
|
|
part = substr(part, 1, pos - 1)
|
|
}
|
|
# traiter start-end
|
|
pos = index(part, "-")
|
|
if (pos != 0) {
|
|
start = substr(part, 1, pos - 1) + 0
|
|
end = substr(part, pos + 1) + 0
|
|
} else {
|
|
start = part + 0
|
|
end = start
|
|
}
|
|
# tester si ça matche
|
|
for (j = start; j <= end; j += step) {
|
|
if (j == ref) {
|
|
ok = 1
|
|
break
|
|
}
|
|
}
|
|
#print " step: is " ref " in [" start "-" end "/" step "] ? " (ok? "yes": "no") #DEBUG
|
|
if (ok) break
|
|
}
|
|
#print "final: is " ref " ~ " ctval " ? " (ok? "yes": "no") #DEBUG
|
|
return ok
|
|
}
|
|
function ctmatch_all(M, H, dom, mon, dow, refM, refH, refdom, refmon, refdow, Mok, Hok, domok, monok, dowok) {
|
|
gsub(/\*/, "0-59", M)
|
|
Mok = ctmatch_one(M, refM)
|
|
|
|
gsub(/\*/, "0-23", H)
|
|
Hok = ctmatch_one(H, refH)
|
|
|
|
gsub(/\*/, "1-31", dom)
|
|
domok = ctmatch_one(dom, refdom)
|
|
|
|
gsub(/\*/, "1-12", mon)
|
|
monok = ctmatch_one(mon, refmon)
|
|
|
|
gsub(/\*/, "1-7", dow)
|
|
dowok = ctmatch_one(dow, refdow)
|
|
|
|
return Mok && Hok && monok && (domok || dowok)
|
|
}
|
|
function print_cmd(cmd) {
|
|
print "__ctexec " quote_value(cmd)
|
|
}
|
|
|
|
BEGIN {
|
|
refM = ctnow[1]; refH = ctnow[2]; refdom = ctnow[3]; refmon = ctnow[4]; refdow = ctnow[5]
|
|
ctref = refM " " refH " " refdom " " refmon " " refdow
|
|
print "## now: " ctref
|
|
|
|
# est-on dans une série de ctline?
|
|
ctline_run = 0
|
|
# dans une série de ctline, il y a-t-il au moins un match?
|
|
ctline_run_one_match = 0
|
|
# faut-il afficher les commandes indentées?
|
|
match_indented = 0
|
|
}
|
|
|
|
/^(export[ \t]+)?[a-zA-Z_][a-zA-Z0-9_]*[-+%#?]=/ {
|
|
ctline_run = 0; ctline_run_one_match = 0; match_indented = 0
|
|
|
|
# manipulation de variables de type PATH
|
|
match($0, /^(export[ \t]+)?([a-zA-Z_][a-zA-Z0-9_]*)([-+%#?])=(.*)$/, parts)
|
|
name = parts[2]
|
|
type = parts[3]
|
|
value = parts[4]
|
|
if (type == "+" || type == "%") {
|
|
print "uaddpath " value " " name
|
|
} else if (type == "#") {
|
|
print "uinspath " value " " name
|
|
} else if (type == "-") {
|
|
print "udelpath " value " " name
|
|
} else if (type == "?") {
|
|
print "[ -n \"$" name "\" ] || " name "=" value
|
|
}
|
|
print "export " name
|
|
next
|
|
}
|
|
/^(export[ \t]+)?[a-zA-Z_][a-zA-Z0-9_]*=/ {
|
|
ctline_run = 0; ctline_run_one_match = 0; match_indented = 0
|
|
|
|
# spécification de variable
|
|
sub(/^export[ \t]+/, "", $0)
|
|
print "export " $0
|
|
next
|
|
}
|
|
/^\$.+/ {
|
|
ctline_run = 0; ctline_run_one_match = 0; match_indented = 0
|
|
|
|
# exécution de commande arbitraire
|
|
if ($0 ~ /^\$\{([ \t]*(#.*)?)?$/) {
|
|
# commande sur plusieurs lignes
|
|
getline
|
|
while ($0 !~ /^\$\}([ \t]*(#.*)?)?$/) {
|
|
print
|
|
if (getline <= 0) break
|
|
}
|
|
} else {
|
|
# commande sur une seule ligne
|
|
sub(/^\$/, "", $0)
|
|
print
|
|
}
|
|
next
|
|
}
|
|
|
|
/^[ \t]*[-0-9/*,]+[ ]*[-0-9/*,]+[ ]*[-0-9/*,]+[ ]*[-0-9/*,]+[ ]*[-0-9/*,]+/ {
|
|
match_indented = 0
|
|
|
|
M = $1; H = $2; dom = $3; mon = $4; dow = $5
|
|
ctline = M " " H " " dom " " mon " " dow
|
|
|
|
sub(/^[ \t]*[^ ]+[ ]+[^ ]+[ ]+[^ ]+[ ]+[^ ]+[ ]+[^ ]+[ ]*/, "", $0)
|
|
cmd = $0
|
|
|
|
match_cur = ctmatch_all(M, H, dom, mon, dow, refM, refH, refdom, refmon, refdow)
|
|
if (match_cur) print "## match: " ctline
|
|
|
|
if (cmd == "") {
|
|
ctline_run = 1
|
|
if (match_cur) ctline_run_one_match = 1
|
|
if (ctline_run_one_match) match_indented = 1
|
|
|
|
} else {
|
|
if (ctline_run && match_cur) ctline_run_one_match = 1
|
|
if (ctline_run && ctline_run_one_match) {
|
|
print_cmd(cmd)
|
|
match_indented = 1
|
|
}
|
|
|
|
if (!ctline_run && match_cur) {
|
|
print_cmd(cmd)
|
|
match_indented = 1
|
|
}
|
|
|
|
ctline_run = 0
|
|
ctline_run_one_match = 0
|
|
}
|
|
|
|
next
|
|
}
|
|
/^[ \t]+/ {
|
|
ctline_run = 0; ctline_run_one_match = 0
|
|
|
|
if (match_indented) {
|
|
sub(/^[ \t]+/, "", $0)
|
|
print_cmd($0)
|
|
}
|
|
|
|
next
|
|
}
|
|
{
|
|
print "__cterror " quote_value("ligne de format incorrect: " $0)
|
|
}
|
|
'
|
|
}
|
|
|
|
## Préfixes
|
|
|
|
function get_default_crontabdir_prefix() {
|
|
if check_sysinfos -s darwin; then
|
|
if check_sysinfos -d 10.6+; then
|
|
echo /var/at/tabs
|
|
else
|
|
echo /var/cron/tabs
|
|
fi
|
|
elif check_sysinfos -s linux; then
|
|
if check_sysinfos -d debianlike; then
|
|
echo /var/spool/cron/crontabs
|
|
elif check_sysinfos -d redhatlike; then
|
|
echo /var/spool/cron
|
|
fi
|
|
fi
|
|
}
|
|
|
|
__crontab_prefixes=
|
|
function __compute_crontab_prefixes() {
|
|
[ -n "$__crontab_prefixes" ] && return
|
|
CRONTABDIR="${CRONTABDIR:-$(get_default_crontabdir_prefix)}"
|
|
__crontab_prefixes=1
|
|
}
|
|
|
|
CRONTAB_PREFIXES=(CRONTABDIR)
|
|
UTOOLS_PREFIXES=("${UTOOLS_PREFIXES[@]}" "${CRONTAB_PREFIXES[@]}")
|
|
|
|
function compute_crontab_prefixes() {
|
|
__compute_crontab_prefixes
|
|
}
|
|
|
|
function recompute_crontab_prefixes() {
|
|
local v
|
|
for v in "${CRONTAB_PREFIXES[@]}"; do
|
|
eval "$v="
|
|
done
|
|
__crontab_prefixes=
|
|
__compute_crontab_prefixes
|
|
}
|
|
|
|
function get_CRONTABDIR_prefix() {
|
|
__compute_crontab_prefixes
|
|
echo "$CRONTABDIR"
|
|
}
|