cron設定

最近の変更

  • RHEL6ではcronのパッケージが変更された
    • RHEL6: cronie, cronie-anacron, crontabs
    • RHEL5: vixie-cron, anacron, crontabs
    • cronieはvixie-cronから派生で、セキュリティ面(SELinux, PAM)のエンハンスを行ったもの。以下、rpm -qi cronieより抜粋。

Cronie contains the standard UNIX daemon crond that runs specified programs at scheduled times and related tools. It is a fork of the original vixie-cron and has security and configuration enhancements like the ability to use pam and SELinux.

    • anacronがcron (hourly) からの定期的起動に変更され、常駐サービスではなくなった(chkconfigからも消えた)。
    • cron.daily,weekly,monthly の実行が cron からの直接起動ではなく、anacron からとなった。起動時間範囲内でランダムに実行するようになっており、従来のように定時実行ではない。

個別調査

run-partsの動作

/etc/cron.daily などの実行に使われる run-parts の動作を確認しておく。

  • /usr/bin/run-parts はパッケージ crontabs によって導入される。
  • オプションで指定されたディレクトリ内のスクリプトを順番に実行する。
  • 中身は通常の bash スクリプト
  • CentOS6.0 (crontabs-1.10-32.1.el6.noarch) から動作の核心部分を抜粋する 。
for i in $(LC_ALL=C; echo $1/*[^~,]) ; do
        [ -d $i ] && continue
        # Don't run *.{rpmsave,rpmorig,rpmnew,swp,cfsaved} scripts
        [ "${i%.cfsaved}" != "${i}" ] && continue
        [ "${i%.rpmsave}" != "${i}" ] && continue
        [ "${i%.rpmorig}" != "${i}" ] && continue
        [ "${i%.rpmnew}" != "${i}" ] && continue
        [ "${i%.swp}" != "${i}" ] && continue
        [ "${i%,v}" != "${i}" ] && continue

        # jobs.deny prevents specific files from being executed
        # jobs.allow prohibits all non-named jobs from being run.
        # can be used in conjunction but there's no reason to do so. 
        if [ -r $1/jobs.deny ]; then
                grep -q "^$(basename $i)$" $1/jobs.deny && continue
        fi
        if [ -r $1/jobs.allow ]; then
                grep -q "^$(basename $i)$" $1/jobs.allow || continue
        fi

        if [ -x $i ]; then
                if [ -r $1/whitelist ]; then
                        grep -q "^$(basename $i)$" $1/whitelist && continue
                fi
                logger -p cron.notice -t "run-parts($1)[$$]" "starting $(basename $i)"
                $i 2>&1 | awk -v "progname=$i" \
                              'progname {
                                   print progname ":\n"
                                   progname="";
                               }
                               { print; }'
                logger -i -p cron.notice -t "run-parts($1)" "finished $(basename $i)"
        fi
done

exit 0
  • だいたい以下の事がわかる。
    • 無視するもの
      • ディレクトリは無視される
      • 拡張子が cfsaved, rpmsave, rpmorig, rpmnew, swap のファイル、~(ニョロ) や ,(カンマ) で終わるファイル、,v (カンマとv)で終わるファイル(CVSがつけるらしい) は無視される
      • 実行可能ファイル以外は無視される
    • ディレクトリ内で実行したいファイル・したくないファイルの制御ができる (RHEL5にはない)
      • ディレクトリ内の jobs.deny ファイルが存在する場合、そこに記載されたファイルは実行がスキップされる(man crontabs に記載あり)
      • ディレクトリ内の jobs.allow ファイルが存在する場合、そこに記載されていないファイルは実行がスキップされる(man crontabs に記載あり)
      • man crontabs に記載がないので whitelist なるファイルは無視する(jobs.deny と同じにしか見えないが)
    • ファイルはロケール C のソート基準でのソート順で実行される (RHEL5ではロケール指定無し)
    • 実行前と後で下記の様なログをsyslogに出力する(cronのログなので/var/log/cronに記録) (RHEL5にはない)
Aug  6 03:32:02 cron.notice localhost run-parts(/etc/cron.daily)[7346]: starting tmpwatch
Aug  6 03:32:02 cron.notice localhost run-parts(/etc/cron.daily)[7546]: finished tmpwatch
    • run-parts の標準出力へ下記のフォーマットで出力される。
      • 実行したプログラムの標準エラー出力も一緒に拾われる
      • 実行したプログラム名がわかるように簡易ヘッダをつけている(cronがメール送信・ログ記録した際の可読性のためと思われる)
      • 1行も標準出力・標準エラー出力が行われなかった場合は、ヘッダも出力されない。無駄な cron 実行ログメールを送らないため重要。 ※BEGINではなく progname { } を使っている理由はそこにあった(行が無ければ評価されない)・・・
プログラム名:

プログラムの標準出力および標準エラー出力
・・・
    • run-parts はそれぞれのプログラムの実行結果によらず、0 で終了する。※オプションで渡すディレクトリが不正など実行以前の問題は 0 以外を返す。
cron実行結果のメール送信
  • cron により実行した場合
    • 実行したプログラムの標準出力・標準エラー出力で何らかの出力があった場合にはメールが送られる。何も出力が無い場合にはメールは送られない。
    • メールの送信有無にプログラムのexitコードは影響しない。
    • メールのサブジェクト: Cron <ユーザ名@ホスト名> 実行したプログラムのパス
    • メールの内容: 標準出力と標準エラー出力(区別無し)。プログラムのexitコードはメールには含まれない。
cronで呼び出されるプログラムのexitコード
  • 何を返してもcron側の動作には影響を与えない。
    • メールの送信有無への影響は無い。
    • syslog出力がcronにより行われるわけでもない。※特に0以外を返した場合でも
  • お作法として『exit 0』を最後につけておく。※そうしているものが多い