cron 的 PATH 设置在哪里?

cron 的 PATH 设置在哪里?

Cron 不使用其 crontab 用户的路径,而是有自己的路径。通过PATH=/foo/bar在 crontab 的开头添加可以轻松更改它,经典的解决方法是始终使用 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

那么,cron 用户 crontab 的默认 PATH 是在哪里设置的呢?它cron本身是硬编码的吗?它不会为此读取某种配置文件吗?

答案1

它被硬编码在源代码(该链接指向当前的 Debian cron— 考虑到实现的多样性cron,很难选择其中之一,但其他实现可能类似):

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

cron不从配置文件中读取默认路径;我想原因是它支持指定已经使用的路径PATH=在任何 cronjob 中使用的路径,因此无需在其他地方指定默认值。 (使用硬编码默认值如果没有其他内容指定作业条目中的路径.)

答案2

添加到 Stephen Kitt 的答案中,有一个PATH在 Ubuntu 上设置 cron 的配置文件,以及cron 忽略使用PATH硬编码的默认值(或PATH在 crontab 本身中设置)。该文件是/etc/environment. Notecron的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,例如,作为 cronjobfoo=bar运行并观察输出中显示的内容。env > /tmp/foofoo=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 包含该文件:

$ 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为 hasuser_readenv=1似乎不会造成任何问题,并且变量 in~/.pam_environment开始显示良好(当然PATH,除了 )。


总而言之,为 cron 设置环境变量似乎是一件很麻烦的事情。最好的地方似乎是作业规范本身,如果只是因为您不知道 cron 可能决定忽略哪些继承的环境变量(无需阅读源代码)。

相关内容