##@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" } __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 } UTOOLS_PREFIXES=("${UTOOLS_PREFIXES[@]}" CRONTABDIR) function compute_crontab_prefixes() { __compute_crontab_prefixes } function recompute_crontab_prefixes() { __crontab_prefixes= __compute_crontab_prefixes } function get_CRONTABDIR_prefix() { __compute_crontab_prefixes echo "$CRONTABDIR" }