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 PATHs 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).

Tags:

Path

Cron