Where is cron's PATH set?
It’s hard-coded in the source code (that link points to the current Debian cron
— given the variety of cron
implementations, it’s hard to choose one, but other implementations are likely similar):
#ifndef _PATH_DEFPATH
# define _PATH_DEFPATH "/usr/bin:/bin"
#endif
cron
doesn’t read default paths from a configuration file; I imagine the reasoning there is that it supports specifying paths already using PATH=
in any cronjob, so there’s no need to be able to specify a default elsewhere. (The hard-coded default is used if nothing else specified a path in a job entry.)
Adding to Stephen Kitt's answer, there is a configuration file that sets PATH
for cron on Ubuntu, and cron
ignores that PATH
to use the hard-coded default (or PATH
s set in the crontabs themselves). The file is /etc/environment
. Note cron
's PAM configuration:
$ 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
...
This is easily verifiable. Add a variable to /etc/environment
, say foo=bar
, run env > /tmp/foo
as a cronjob and watch as foo=bar
shows up in the output.
But why? The default system-wide path is set in /etc/profile, but that includes other directories:
$ grep PATH= /etc/profile PATH="/usr/local/sbin:/usr/local/bin:/usr/bin"
That's true in Arch Linux, but in Ubuntu, the base PATH
is set in /etc/environment
. Files in /etc/profile.d
tack on to an existing PATH
, and you can append to it in ~/.pam_environment
. I have a bug filed about Arch's behaviour.
Unfortunately, /etc/pam.d/cron
does not include reading from ~/.pam_environment
. Weirdly, /etc/pam.d/atd
does include that file:
$ 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
... but commands run via at
apparently inherit the environment available when creating the at
job (for example, env -i /usr/bin/at ...
seems to run jobs with a very clean environment).
Amending /etc/pam.d/cron
to have user_readenv=1
seems to cause no problems, and variables in ~/.pam_environment
started showing up fine (except for PATH
, of course).
All told, setting environment variables for cron seems to be a messy business. The best place seems to be in the job specification itself, if only because you don't know which inherited environment variables cron might decide ignore (without reading the source).