web-dev-qa-db-ja.com

cronのPATHはどこに設定されていますか?

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自体にハードコードされていますか?これのためになんらかの設定ファイルを読み取っていませんか?

36
terdon

ソースコード にハードコーディングされています(このリンクは現在のDebian cronを指します— cronの実装が多様であるため、1つを選択するのは困難ですが、他の実装も同様です)。

#ifndef _PATH_DEFPATH
# define _PATH_DEFPATH "/usr/bin:/bin"
#endif

cronは、構成ファイルからデフォルトパスを読み取りません。任意のcronジョブでPATH=をすでに使用しているパスの指定をサポートしているため、他の場所でデフォルトを指定する必要はないという理由があると思います。 (ハードコードされたデフォルトが使用されます ジョブエントリで他にパスが指定されていない場合 。)

48
Stephen Kitt

Stephen Kittの回答に加えて、UbuntuのcronにPATHを設定する構成ファイルがあり、cronignoresハードコーディングされたデフォルト(またはcrontabs自体に設定されたPATHs)を使用するための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/atddoesはそのファイルをインクルードします:

$ 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が無視を決定する可能性がある継承された環境変数がわからない場合にのみ、最適な場所はジョブ仕様自体にあるようです。

9
muru