Debian系の cron で気をつけること
はじめに
平素は大変お世話になっております。
クイックガードのパー子です。
先日、とある Ubuntuサーバの /etc/cron.d/
配下に debパッケージのゴミ (= *.dpkg-old
とか) がいくつも放置されていることに気がつきました。
このようなゴミは cron がよしなに無視してくれることを経験的には知っていたのですが、正確な仕様が気になってあらためて man をじっくり読んでみたところ、いろいろ興味深い発見 (というか罠) があったのでご紹介したいと思います。
この記事で書くこと、書かないこと
crontab の書き方などの基本的な使い方は今さらなのでググっていただくとして、この記事では Debian系における /etc/
周りの制約と罠をご紹介します。
スプール領域 (/var/spool/cron/
) には触れません。
man に DEBIAN SPECIFIC というセクションがあり、Debian固有の制約が詳しく書かれているので、特にこれを重点的に見ていきます。
検証環境
検証には以下の環境を使いました。
- OS: Ubuntu (20.04.1 LTS Focal Fossa)
- cron実装:
apt install cron
でインストールした Vixie Cron (3.0pl1-136ubuntu1)
/etc/配下の crontabファイル
本題に入る前に、まずはおさらいとして /etc/
配下にある crontab (cron table) ファイルの中身を見ていきましょう。
ご存知のとおり、Debian系の cron は以下の 2か所に置かれた crontabファイルを認識します。
/etc/crontab
/etc/cron.d/*
また、/etc/cron.hourly/
、/etc/cron.daily/
などの事前定義済みのディレクトリ (以降、総称して「/etc/cron.<PERIOD>/
」と呼びます。) 配下に実行ファイルを置いておけば、配置したディレクトリに応じて毎時〜毎月の頻度で定期実行してくれます。
/etc/crontab
Debian系ではこのファイルで /etc/cron.<PERIOD>/
配下のジョブをスケジューリングしています。
/etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
# Example of job definition:
# .---------------- minute (0 - 59)
# | .------------- hour (0 - 23)
# | | .---------- day of month (1 - 31)
# | | | .------- month (1 - 12) OR jan,feb,mar,apr ...
# | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# | | | | |
# * * * * * user-name command to be executed
17 * * * * root cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )
#
run-parts
というのは、指定したディレクトリ内の実行ファイルをまとめて実行してくれるコマンド です。
このように「毎時〜毎月1回実行されるよう定義したスケジュールにしたがって、時がきたらそれぞれのディレクトリ配下のスクリプトを run-parts
で素朴に実行するだけ」というのが /etc/cron.<PERIOD>/
の仕組みなのです。
ちなみに anacron がインストールされている (= test -x ...
にマッチする) 場合、日レベル以上のジョブは anacron に委譲されますが、anacron でも同じように run-parts
を実行しています。
/etc/anacrontab
# /etc/anacrontab: configuration file for anacron
# See anacron(8) and anacrontab(5) for details.
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
HOME=/root
LOGNAME=root
# These replace cron's entries
1 5 cron.daily run-parts --report /etc/cron.daily
7 10 cron.weekly run-parts --report /etc/cron.weekly
@monthly 15 cron.monthly run-parts --report /etc/cron.monthly
なお、もちろん /etc/crontab
には任意のジョブ定義を追加することもできますが、ペライチの単一ファイルなので多数のジョブを書き連ねるとゴチャゴチャして管理が難しくなってきます。
その場合は、次のセクションで詳しく述べますが、/etc/cron.d/
のほうに適度にファイルを分割しながら配置することをオススメします。
/etc/cron.d/
/etc/cron.d/
配下には任意のファイル名で複数の crontabファイルを配置できます。
(任意と言いつつ細かい制約があるので、詳細は後述します。)
ジョブごとにファイルを分けて配置できるので、/etc/crontab
よりもこちらのディレクトリに程よい粒度で配置したほうが管理しやすいでしょう。
なお、man には「/etc/cron.d/
じゃなくて /etc/crontab
を使え。」とか、
… In
general, the system administrator should not use/etc/cron.d/
, but use the standard system
crontab/etc/crontab.
別の箇所 には「/etc/cron.d/
は debパッケージ用だ。」などと書かれていますが、
The intended purpose of this feature is to allow packages that require finer control of
their scheduling than the/etc/cron.{hourly,daily,weekly,monthly}
directories to add a
crontab file to/etc/cron.d
. Such files should be named after the package that supplies
them.
とはいえ、/etc/crontab
の取り回しの悪さは受け入れがたいので、個人的にはやはり /etc/cron.d/
を優先して使っていきたい気分です。
ファイルの制約
/etc/cron.<PERIOD>/
と /etc/cron.d/
に配置するファイルには、ファイル名やパーミッションなど、それぞれ細かい制約がいくつもあります。
man に (嘘がちょいちょい混ぜ込まれているものの) 詳しくまとまっているので、どのような制約があるのか見ていきます。
いきなり結論
詳細はあとで見ていくので、とりあえずいきなり結論を書きます。
/etc/cron.<PERIOD>/
普通に run-parts
経由で実行しているだけなので、run-parts
の探索ルール (以下2点) を満たせば OK です。
- 実行ファイルであること
- ファイル名が次の文字種のみで構成されること
- 英字
- 数字
- アンダースコア
- ハイフン
具体例を示します。
実行ファイル:
✘ 実行権限が付与されていないと NG です。
$ ls -lh /etc/cron.hourly/
-rw-r--r-- 1 root staff 47 Oct 8 02:28 ng-job # [NG] 実行ファイルではない
✘ シンボリック・リンクの場合は、参照先ファイルに実行権限が付与されていないといけません。
$ ls -lh /etc/cron.hourly/
lrwxrwxrwx 1 root staff 13 Oct 8 01:56 ng-job -> /scripts/orig # [NG] 参照先が実行ファイルではない
$ ls -lh /scripts/
-rw-r--r-- 1 root staff 47 Oct 8 02:28 orig
ファイル名:
✘ .
(ドット) など、[A-Za-z0-9_-]
以外の文字が含まれていると NG です。
$ ls -lh /etc/cron.hourly/
-rwxr-xr-x 1 root staff 47 Oct 8 02:28 ng-job.dot # [NG] `[A-Za-z0-9_-]`以外の文字が含まれている
✔ シンボリック・リンクの場合は、参照先ファイルの名称に制約はありません。
(.
などが含まれていてもよい。)
$ ls -lh /etc/cron.hourly/
lrwxrwxrwx 1 root staff 13 Oct 8 01:56 ok-job -> /scripts/orig.dot # [OK] :)
✘ もちろんシンボリック・リンク自体のファイル名は run-parts
に準拠している必要があります。
$ ls -lh /etc/cron.hourly/
lrwxrwxrwx 1 root staff 13 Oct 8 01:56 ng-job.dot -> /scripts/orig # [NG] シンボリック・リンク名に `[A-Za-z0-9_-]`以外の文字が含まれている
所有者:
✔ 所有者は root でなくても OK です。
$ ls -lh /etc/cron.hourly/
-rwxr-xr-x 1 yumeko staff 47 Oct 8 02:28 ok-job # [OK] :)
書き込み権限:
✔ 所有者以外の書き込み権限があっても OK です。
$ ls -lh /etc/cron.hourly/
-rwxrwxrwx 1 root staff 47 Oct 8 02:28 ok-job # [OK] :)
/etc/cron.d/
以下の条件をすべて満たす必要があります。
- ファイル名が次の文字種のみで構成されること
- 英字
- 数字
- アンダースコア
- ハイフン
- 所有者が root であること
- 所有者以外に書き込み権限がないこと
/etc/cron.<PERIOD>/
とは異なり、実行ファイルである必要はありません。
(スクリプトではなく /etc/crontab
相当の設定ファイルなので)
具体例を示します。
ファイル名:
run-parts
は関係しないものの、/etc/cron.<PERIOD>/
と同じルールが適用されます。
.
が含まれていると crontabファイルとして認識されないので、*.dpkg-old
などの debパッケージの残骸が放置されていても安心です。
所有者:
✘ 所有者は root でないといけません。
$ ls -lh /etc/cron.d/
-rw-r--r-- 1 yumeko staff 47 Oct 8 02:28 ng-tab # [NG] 所有者が root ではない
✘ シンボリック・リンクの場合は、シンボリック・リンク自体と参照先ファイルの両方の所有者が root でないといけません。
$ ls -lh /etc/cron.d/
lrwxrwxrwx 1 root staff 22 Oct 8 03:02 ng-tab-1 -> /crontabs/orig-1 # [NG] 参照先ファイルの所有者が root ではない
lrwxrwxrwx 1 yumeko staff 22 Oct 8 03:06 ng-tab-2 -> /crontabs/orig-2 # [NG] シンボリック・リンク自体の所有者が root ではない
$ ls -lh /crontabs/
-rw-r--r-- 1 yumeko staff 125 Oct 8 03:00 orig-1
-rw-r--r-- 1 root staff 125 Oct 8 03:00 orig-2
書き込み権限:
✘ 所有者以外の書き込み権限があると NG です。
$ ls -lh /etc/cron.d/
-rw-rw-rw- 1 root staff 117 Oct 8 02:55 ng-tab # [NG] 所有者以外の書き込み権限がある
✘ シンボリック・リンクの場合は、参照先ファイルに所有者以外の書き込み権限があると NG です。
$ ls -lh /etc/cron.d/
lrwxrwxrwx 1 root staff 22 Oct 8 03:02 ng-tab -> /crontabs/orig # [NG] 参照先ファイルに所有者以外の書き込み権限がある
$ ls -lh /crontabs/
-rw-rw-rw- 1 root staff 125 Oct 8 03:00 orig
調査結果
結論と順番が前後しますが、制約に関する man の記述と調査結果です。
/etc/cron.<PERIOD>/
man には以下のように書かれています。
As described above, the files under these directories have to pass some sanity checks
including the following: be executable, be owned by root, not be writable by group or
other and, if symlinks, point to files owned by root. Additionally, the file names must
conform to the filename requirements of run-parts: they must be entirely made up of
letters, digits and can only contain the special signs underscores (’_’) and hyphens
(’-’). Any file that does not conform to these requirements will not be executed by run-
parts. For example, any file containing dots will be ignored.
個別の条件を列挙すると次のとおりなのですが、
- 実行ファイルであること
- 所有者が root であること
(シンボリック・リンクの場合は参照先ファイルが root であること) - 所有者以外に書き込み権限がないこと
- ファイル名が次の文字種のみで構成されること
- 英字
- 数字
- アンダースコア
- ハイフン
しかし、/etc/crontab
の中身で見たとおり、/etc/cron.<PERIOD>/
配下のスクリプトは単純に run-parts
で実行しているだけなので、どうもこの記述は怪しそうです。
(run-parts
の man では所有者や書き込み権限には言及されていません。)
結果:
以下のスクリプト群を作成して実際に cron の毎時実行を待ってみたところ、やはりこの記述は正確ではありませんでした。
$ ls -lh /etc/cron.hourly/
total 24K
-rwxr-xr-x 1 root staff 47 Oct 8 02:28 job-1
-rw-r--r-- 1 root staff 47 Oct 8 02:28 job-2
-rwxr-xr-x 1 yumeko staff 47 Oct 8 02:28 job-3
-rwxrwxrwx 1 root staff 47 Oct 8 02:28 job-4
-rwxr-xr-x 1 root staff 47 Oct 8 02:28 job-5.dot
lrwxrwxrwx 1 root staff 13 Oct 8 01:56 job-sym-a-1 -> /scripts/orig.dot-1
lrwxrwxrwx 1 root staff 13 Oct 8 01:56 job-sym-a-2 -> /scripts/orig.dot-2
lrwxrwxrwx 1 root staff 13 Oct 8 01:59 job-sym-a-3 -> /scripts/orig.dot-3
lrwxrwxrwx 1 root staff 13 Oct 8 01:59 job-sym-a-4 -> /scripts/orig.dot-4
lrwxrwxrwx 1 root staff 13 Oct 8 01:59 job-sym-a-5.dot -> /scripts/orig.dot-5
lrwxrwxrwx 1 yumeko staff 13 Oct 8 01:56 job-sym-b-1 -> /scripts/orig.dot-1
lrwxrwxrwx 1 yumeko staff 13 Oct 8 01:56 job-sym-b-2 -> /scripts/orig.dot-2
lrwxrwxrwx 1 yumeko staff 13 Oct 8 02:00 job-sym-b-3 -> /scripts/orig.dot-3
lrwxrwxrwx 1 yumeko staff 13 Oct 8 02:00 job-sym-b-4 -> /scripts/orig.dot-4
lrwxrwxrwx 1 yumeko staff 13 Oct 8 02:00 job-sym-b-5.dot -> /scripts/orig.dot-5
$ ls -lh /scripts/
total 12K
-rwxr-xr-x 1 root staff 47 Oct 8 02:28 orig.dot-1
-rw-r--r-- 1 root staff 47 Oct 8 02:28 orig.dot-2
-rwxr-xr-x 1 yumeko staff 47 Oct 8 02:28 orig.dot-3
-rwxrwxrwx 1 root staff 47 Oct 8 02:28 orig.dot-4
-rwxr-xr-x 1 root staff 47 Oct 8 02:28 orig.dot-5
それぞれのスクリプトに込めた意図と、そのうち実際に実行されたものをわかりやすくまとめた表が以下です。
ファイル名 | 所有者 | 実行権限 | 書き込み権限 [※1] | 名称規則 [※2] | 実行された |
---|---|---|---|---|---|
job-1 | root | ✔ | u - - | ✔ | ✔ |
job-2 | root | ✘ | u - - | ✔ | ✘ |
job-3 | yumeko | ✔ | u - - | ✔ | ✔ |
job-4 | root | ✔ | u g o | ✔ | ✔ |
job-5.dot | root | ✔ | u - - | ✘ | ✘ |
ファイル名 (シンボリック・リンク) | 所有者 (シンボリック・リンク) | 名称規則 [※2] (シンボリック・リンク) | 所有者 (参照先) | 実行権限 (参照先) | 書き込み権限 [※1] (参照先) | 名称規則 [※2] (参照先) | 実行された |
---|---|---|---|---|---|---|---|
job-sym-a-1 | root | ✔ | root | ✔ | u - - | ✘ | ✔ |
job-sym-a-2 | root | ✔ | root | ✘ | u - - | ✘ | ✘ |
job-sym-a-3 | root | ✔ | yumeko | ✔ | u - - | ✘ | ✔ |
job-sym-a-4 | root | ✔ | root | ✔ | u g o | ✘ | ✔ |
job-sym-a-5.dot | root | ✘ | root | ✔ | u - - | ✘ | ✘ |
job-sym-b-1 | yumeko | ✔ | root | ✔ | u - - | ✘ | ✔ |
job-sym-b-2 | yumeko | ✔ | root | ✘ | u - - | ✘ | ✘ |
job-sym-b-3 | yumeko | ✔ | yumeko | ✔ | u - - | ✘ | ✔ |
job-sym-b-4 | yumeko | ✔ | root | ✔ | u g o | ✘ | ✔ |
job-sym-b-5.dot | yumeko | ✘ | root | ✔ | u - - | ✘ | ✘ |
※1 u: 所有者 / g: グループ / o: それ以外
※2 run-parts
のファイル名の規則に適合するか?
考察:
見てのとおり、実行ファイルでないものやファイル名がまずいものは実行されない一方、所有者や書き込み権限は実行可否に影響しないこと、また、シンボリック・リンクの参照先ファイルの名称も関係しないことがわかりました。
やはり run-parts
の探索ルール (実行ファイル + ファイル名) を満たしていれば OK なのです。
/etc/cron.d/
/etc/cron.d/
の制約も man の続く段落に書かれています。
Files in this directory have to be owned by root, do not need to be executable (they are
configuration files, just like/etc/crontab
) and must conform to the same naming
convention as used by run-parts(8) : they must consist solely of upper- and lower-case
letters, digits, underscores, and hyphens. This means that they cannot contain any dots.
/etc/cron.<PERIOD>/
と同じく、所有者やファイル名の規則 (run-parts
と同等) が挙げられています。
一方、/etc/cron.<PERIOD>/
とは違って、スクリプトそのものではなく crontabファイルを配置するため、実行権限は不要となっています。
また、書き込み権限の制約は NOTESセクションで言及されています。
/etc/crontab
and the files in/etc/cron.d
must be owned by root, and must not be group- or
other-writable.
結果:
以下のファイル群について検証しました。
$ ls -lh /etc/cron.d/
total 24K
-rw-r--r-- 1 root staff 117 Oct 8 02:54 tab-1
-rw-r--r-- 1 yumeko staff 117 Oct 8 02:55 tab-2
-rw-rw-rw- 1 root staff 117 Oct 8 02:55 tab-3
-rw-r--r-- 1 root staff 117 Oct 8 02:57 tab-4.dot
lrwxrwxrwx 1 root staff 22 Oct 8 03:02 tab-sym-a-1 -> /crontabs/orig.dot-1
lrwxrwxrwx 1 root staff 22 Oct 8 03:02 tab-sym-a-2 -> /crontabs/orig.dot-2
lrwxrwxrwx 1 root staff 22 Oct 8 03:02 tab-sym-a-3 -> /crontabs/orig.dot-3
lrwxrwxrwx 1 root staff 22 Oct 8 03:03 tab-sym-a-4.dot -> /crontabs/orig.dot-4
lrwxrwxrwx 1 yumeko staff 22 Oct 8 03:06 tab-sym-b-1 -> /crontabs/orig.dot-1
lrwxrwxrwx 1 yumeko staff 22 Oct 8 03:06 tab-sym-b-2 -> /crontabs/orig.dot-2
lrwxrwxrwx 1 yumeko staff 22 Oct 8 03:06 tab-sym-b-3 -> /crontabs/orig.dot-3
lrwxrwxrwx 1 yumeko staff 22 Oct 8 03:06 tab-sym-b-4.dot -> /crontabs/orig.dot-4
$ ls -lh /crontabs/
total 12K
-rw-r--r-- 1 root staff 125 Oct 8 03:03 orig.dot-1
-rw-r--r-- 1 yumeko staff 125 Oct 8 03:00 orig.dot-2
-rw-rw-rw- 1 root staff 125 Oct 8 03:00 orig.dot-3
-rw-r--r-- 1 root staff 125 Oct 8 03:03 orig.dot-4
ファイル名 | 所有者 | 書き込み権限 [※1] | 名称規則 [※2] | 実行された |
---|---|---|---|---|
tab-1 | root | u - - | ✔ | ✔ |
tab-2 | yumeko | u - - | ✔ | ✘ |
tab-3 | root | u g o | ✔ | ✘ |
tab-4.dot | root | u - - | ✘ | ✘ |
ファイル名 (シンボリック・リンク) | 所有者 (シンボリック・リンク) | 名称規則 [※2] (シンボリック・リンク) | 所有者 (参照先) | 書き込み権限 [※1] (参照先) | 名称規則 [※2] (参照先) | 実行された |
---|---|---|---|---|---|---|
tab-sym-a-1 | root | ✔ | root | u - - | ✘ | ✔ |
tab-sym-a-2 | root | ✔ | yumeko | u - - | ✘ | ✘ |
tab-sym-a-3 | root | ✔ | root | u g o | ✘ | ✘ |
tab-sym-a-4.dot | root | ✘ | root | u - - | ✘ | ✘ |
tab-sym-b-1 | yumeko | ✔ | root | u - - | ✘ | ✘ |
tab-sym-b-2 | yumeko | ✔ | yumeko | u - - | ✘ | ✘ |
tab-sym-b-3 | yumeko | ✔ | root | u g o | ✘ | ✘ |
tab-sym-b-4.dot | yumeko | ✘ | root | u - - | ✘ | ✘ |
※1 u: 所有者 / g: グループ / o: それ以外
※2 run-parts
のファイル名の規則に適合するか?
考察:
実行されたのは tab-1
と tab-sym-a-1
のみでした。/etc/cron.<PERIOD>/
とは違って、こちらの man の記述は正しいようです。
(ファイル名 + 所有者 + 書き込み権限)
Appendix: LSB namespace
cron には -l
というオプションがあり、これを指定すると /etc/cron.d/
配下のファイルの探索ルールが変わるようです。
…が、ここでも man の記述に誤りがあるので注意が必要です。
-l Enable LSB compliant names for
/etc/cron.d
files. This setting, however, does not
affect the parsing of files under/etc/cron.hourly
,/etc/cron.daily
,
/etc/cron.weekly
or/etc/cron.monthly
.
If the -l option is specified to cron (this option can be setup through
/etc/default/cron
,
see below), then they must conform to the LSB namespace specification, exactly as in the
–lsbsysinit option in run-parts.
–lsbsysinit
use LSB namespaces instead of classical behavior.
If the –lsbsysinit option is given, then the names must not end in .dpkg-old or
.dpkg-dist or .dpkg-new or .dpkg-tmp, and must belong to one or more of the following
namespaces: the LANANA-assigned namespace (^[a-z0-9]+$); the LSB hierarchical and reserved
namespaces (^_?([a-z0-9_.]+-)+[a-z0-9]+$); and the Debian cron script namespace (^[a-zA-
Z0-9_-]+$).
突然出てきた「namespace」という概念がよくわからないものの、どうやらファイル名が以下2つの条件の両方を満たすものだけが crontabファイルとして認識されるようです。
- 拡張子が以下ではないこと
.dpkg-old
.dpkg-dist
.dpkg-new
.dpkg-tmp
- 以下の namespace (単にファイル名と思ってよい?) のいずれかに属すること
- the LANANA-assigned namespace:
^[a-z0-9]+$
- the LSB hierarchical and reserved namespace:
^_?([a-z0-9_.]+-)+[a-z0-9]+$
- the Debian cron script namespace:
^[a-zA-Z0-9_-]+$
- the LANANA-assigned namespace:
ところがコードを読んでみたところ、実際の挙動と解離していることがわかりました。
コードの確認
Launchpad からソースをダウンロードして、run-parts.c
の実装を見てみました。
ファイル名のチェックをしているのは valid_name
関数で、regex_mode == RUNPARTS_LSBSYSINIT
のブロックを見ればよさそうです。
run-parts.c#L146-L169
|
|
regexec
関数で何度か正規表現のマッチングを試みていますね。
ここで拡張子と namespace を判定していそうです。
各正規表現の実体は regex_compile_pattern
関数で定義されていました。
run-parts.c#L651-L693
|
|
この正規表現の実体を使って valid_name
関数の 157-164行目をわかりやすく表記すると次のようになります。
`--lsbsysinit`オプション付きで実行した場合
│
└── /^_?([a-z0-9_.]+-)+[a-z0-9]+$/ (= hierre) にマッチ?
│
├── する
│ │
│ └── /^[a-z0-9-].*\.dpkg-(old|dist|new|tmp)$/ (= excsre) にマッチ?
│ │
│ ├── する
│ │ │
│ │ └── false (Path 1)
│ │
│ └── しない
│ │
│ └── true (Path 2)
│
└── しない
│
└── /^[a-z0-9][a-z0-9-]*$/ (= tradre) にマッチ?
│
├── する
│ │
│ └── true (Path 3)
│
└── しない
│
└── false (Path 4)
戻り値が true (= Path 2, 3) になるファイルが実行対象として認識されるのですが、どう見ても man の記述とは違いますね。
なお、man に書かれているとおり cron も run-parts
の実装を模倣しているため、ほぼ同等の挙動になるはずです。
(拡張子の判定が若干異なります。)
ソース: cron_3.0pl1-136ubuntu1.debian.tar.xz
patches/features/Drop-in-drop.d-directory-support.patch#L322-L358
|
|
動作確認
念のため Path 1〜4 をそれぞれ通過するファイル名のスクリプトを用意して、実際に run-parts
を実行してみました。
ファイル名 | hierre | excsre | tradre | Path |
---|---|---|---|---|
a.dpkg-old | ✔ | ✔ | ✘ | 1 |
_b.dpkg-old | ✔ | ✘ | ✘ | 2 |
c | ✘ | ✘ | ✔ | 3 |
D | ✘ | ✘ | ✘ | 4 |
ファイル名の選定の正しさは RSpec で担保しています。
(C は不慣れなので…。)
regexec_spec.rb
RSpec.describe 'regexec' do
let!(:hierre) { /^_?([a-z0-9_.]+-)+[a-z0-9]+$/ }
let!(:excsre) { /^[a-z0-9-].*\.dpkg-(old|dist|new|tmp)$/ }
let!(:tradre) { /^[a-z0-9][a-z0-9-]*$/ }
describe 'a.dpkg-old' do
subject { 'a.dpkg-old' }
it { is_expected.to match(hierre) }
it { is_expected.to match(excsre) }
it { is_expected.to_not match(tradre) }
end
describe '_b.dpkg-old' do
subject { '_b.dpkg-old' }
it { is_expected.to match(hierre) }
it { is_expected.to_not match(excsre) }
it { is_expected.to_not match(tradre) }
end
describe 'c' do
subject { 'c' }
it { is_expected.to_not match(hierre) }
it { is_expected.to_not match(excsre) }
it { is_expected.to match(tradre) }
end
describe 'D' do
subject { 'D' }
it { is_expected.to_not match(hierre) }
it { is_expected.to_not match(excsre) }
it { is_expected.to_not match(tradre) }
end
end
$ bundle exec rspec -f d ./regexec_spec.rb
regexec
a.dpkg-old
is expected to match /^_?([a-z0-9_.]+-)+[a-z0-9]+$/
is expected to match /^[a-z0-9-].*\.dpkg-(old|dist|new|tmp)$/
is expected not to match /^[a-z0-9][a-z0-9-]*$/
_b.dpkg-old
is expected to match /^_?([a-z0-9_.]+-)+[a-z0-9]+$/
is expected not to match /^[a-z0-9-].*\.dpkg-(old|dist|new|tmp)$/
is expected not to match /^[a-z0-9][a-z0-9-]*$/
c
is expected not to match /^_?([a-z0-9_.]+-)+[a-z0-9]+$/
is expected not to match /^[a-z0-9-].*\.dpkg-(old|dist|new|tmp)$/
is expected to match /^[a-z0-9][a-z0-9-]*$/
D
is expected not to match /^_?([a-z0-9_.]+-)+[a-z0-9]+$/
is expected not to match /^[a-z0-9-].*\.dpkg-(old|dist|new|tmp)$/
is expected not to match /^[a-z0-9][a-z0-9-]*$/
Finished in 0.00337 seconds (files took 0.09024 seconds to load)
12 examples, 0 failures
なお、スクリプトの中身はすべて共通で、自身のファイル名を出力するだけです。
スクリプトの中身は共通
#!/bin/bash
echo ${0}
以上で準備が整いました。
$ ls -lh
total 16K
-rwxr-xr-x 1 yumeko staff 33 Sep 29 08:27 D
-rwxr-xr-x 1 yumeko staff 33 Sep 29 08:28 _b.dpkg-old
-rwxr-xr-x 1 yumeko staff 33 Sep 29 08:28 a.dpkg-old
-rwxr-xr-x 1 yumeko staff 33 Sep 29 08:27 c
--lsbsysinit
オプション付きで run-parts
を実行してみると、
$ run-parts --lsbsysinit .
./_b.dpkg-old
./c
思ったとおり Path 2 と 3 を通過するファイルだけ実行されました。
やはり man と実際の挙動が解離しているようです。
まとめ
以上、/etc/
配下の cron関連ファイルの概要をおさらいしつつ、Debian系cron の制約と罠を見ていきました。
cron の認識対象となるための条件 (ファイルの所有者やパーミッション) が man に誤って記載されているため、man を読むだけで安心せず手を動かして実際の挙動を確かめてみることが大事だと思います。
また、普段は使うことはないと思いますが、cron -l
/ run-parts --lsbsysinit
というオプションを詳しく見てみました。
コードを読んでみたところ、こちらも man と実装が解離していることがわかりました。
RedHat系の cron実装はまた違った挙動になると思いますが、この記事が Debian系cron に不意を衝かれないための一助になれば幸いです。
今後ともよろしくお願い申し上げます。