Cronは、crontabが存在するユーザーのパスを使用せず、代わりに独自のパスを持っています。これは、crontabの先頭にPATH=/foo/bar
を追加することで簡単に変更できます。従来の回避策は、cronによって実行されるコマンドへの絶対パスを常に使用することですが、cronのデフォルトのPATHはどこに定義されていますか?
私のArchシステム(cronie 1.5.1-1)で次の内容のcrontabを作成し、Ubuntu 16.04.3 LTSボックスでテストしたところ、同じ結果が得られました。
$ crontab -l
* * * * * echo "$PATH" > /home/terdon/fff
それは印刷されました:
$ cat fff
/usr/bin:/bin
しかし、なぜ?デフォルトのシステム全体のパスは/etc/profile
で設定されていますが、他のディレクトリが含まれています。
$ grep PATH= /etc/profile
PATH="/usr/local/sbin:/usr/local/bin:/usr/bin"
/etc/environment
または/etc/profile.d
に関連するものは他にありません。他のファイルはcronによって読み取られる可能性があると考えました。
$ grep PATH= /etc/profile.d/* /etc/environment
/etc/profile.d/jre.sh:export PATH=${PATH}:/usr/lib/jvm/default/bin
/etc/profile.d/mozilla-common.sh:export MOZ_PLUGIN_PATH="/usr/lib/mozilla/plugins"
/etc/profile.d/perlbin.sh:[ -d /usr/bin/site_Perl ] && PATH=$PATH:/usr/bin/site_Perl
/etc/profile.d/perlbin.sh:[ -d /usr/lib/Perl5/site_Perl/bin ] && PATH=$PATH:/usr/lib/Perl5/site_Perl/bin
/etc/profile.d/perlbin.sh:[ -d /usr/bin/vendor_Perl ] && PATH=$PATH:/usr/bin/vendor_Perl
/etc/profile.d/perlbin.sh:[ -d /usr/lib/Perl5/vendor_Perl/bin ] && PATH=$PATH:/usr/lib/Perl5/vendor_Perl/bin
/etc/profile.d/perlbin.sh:[ -d /usr/bin/core_Perl ] && PATH=$PATH:/usr/bin/core_Perl
当然のことながら、/etc/skel
のどのファイルにも関連性はなく、/etc/cron*
ファイルにも設定されていません。
$ grep PATH /etc/cron* /etc/cron*/*
grep: /etc/cron.d: Is a directory
grep: /etc/cron.daily: Is a directory
grep: /etc/cron.hourly: Is a directory
grep: /etc/cron.monthly: Is a directory
grep: /etc/cron.weekly: Is a directory
/etc/cron.d/0hourly:PATH=/sbin:/bin:/usr/sbin:/usr/bin
では、ユーザーのcrontabが設定されているcronのデフォルトのPATHはどこにあるのでしょうか。 cron
自体にハードコードされていますか?これのためになんらかの設定ファイルを読み取っていませんか?
ソースコード にハードコーディングされています(このリンクは現在のDebian cron
を指します— cron
の実装が多様であるため、1つを選択するのは困難ですが、他の実装も同様です)。
#ifndef _PATH_DEFPATH
# define _PATH_DEFPATH "/usr/bin:/bin"
#endif
cron
は、構成ファイルからデフォルトパスを読み取りません。任意のcronジョブでPATH=
をすでに使用しているパスの指定をサポートしているため、他の場所でデフォルトを指定する必要はないという理由があると思います。 (ハードコードされたデフォルトが使用されます ジョブエントリで他にパスが指定されていない場合 。)
Stephen Kittの回答に加えて、UbuntuのcronにPATH
を設定する構成ファイルがあり、cron
ignoresハードコーディングされたデフォルト(またはcrontabs自体に設定されたPATH
s)を使用するためのPATH
。ファイルは/etc/environment
です。 cron
のPAM設定に注意してください:
$ cat /etc/pam.d/cron
...
# Read environment variables from pam_env's default files, /etc/environment
# and /etc/security/pam_env.conf.
session required pam_env.so
# In addition, read system locale information
session required pam_env.so envfile=/etc/default/locale
...
これは簡単に検証できます。変数を/etc/environment
に追加し、_foo=bar
と言い、cronjobとしてenv > /tmp/foo
を実行し、foo=bar
が出力に表示されるのを確認します。
しかし、なぜ?デフォルトのシステム全体のパスは/ etc/profileに設定されていますが、これには他のディレクトリが含まれています。
$ grep PATH= /etc/profile PATH="/usr/local/sbin:/usr/local/bin:/usr/bin"
これはArch Linuxでも同じですが、UbuntuではPATH
が/etc/environment
に設定されています。 /etc/profile.d
のファイルは既存のPATH
に追加され、~/.pam_environment
で追加できます。私は Archの振る舞いについて報告されたバグ を持っています。
残念ながら、/etc/pam.d/cron
には~/.pam_environment
からの読み取りは含まれていません。奇妙なことに、/etc/pam.d/atd
doesはそのファイルをインクルードします:
$ cat /etc/pam.d/atd
#
# The PAM configuration file for the at daemon
#
@include common-auth
@include common-account
session required pam_loginuid.so
@include common-session-noninteractive
session required pam_limits.so
session required pam_env.so user_readenv=1
...しかしat
を介して実行されるコマンドは、at
ジョブの作成時に使用可能な環境を継承しているようです(たとえば、env -i /usr/bin/at ...
は非常にクリーンな環境でジョブを実行しているようです)。
/etc/pam.d/cron
を変更してuser_readenv=1
を追加しても問題は発生せず、~/.pam_environment
の変数が正常に表示されるようになりました(もちろんPATH
を除く)。
つまり、cronの環境変数の設定は厄介なビジネスのようです。 (ソースを読み取らずに)cronが無視を決定する可能性がある継承された環境変数がわからない場合にのみ、最適な場所はジョブ仕様自体にあるようです。