Di mana set PATH cron diatur?

34

Cron tidak menggunakan jalur dari pengguna yang memiliki crontab itu dan, sebaliknya, memiliki sendiri. Ini dapat dengan mudah diubah dengan menambahkan PATH=/foo/bardi awal crontab, dan solusi klasiknya adalah selalu menggunakan path absolut untuk perintah yang dijalankan oleh cron, tetapi di mana PATH default cron didefinisikan?

Saya membuat crontab dengan konten berikut pada sistem Arch saya (cronie 1.5.1-1) dan juga diuji pada kotak Ubuntu 16.04.3 LTS dengan hasil yang sama:

$ crontab -l
* * * * * echo "$PATH" > /home/terdon/fff

Itu dicetak:

$ cat fff
/usr/bin:/bin

Tapi kenapa? Jalur lebar sistem default ditetapkan /etc/profile, tetapi itu termasuk direktori lain:

$ grep PATH= /etc/profile
PATH="/usr/local/sbin:/usr/local/bin:/usr/bin"

Tidak ada hal lain yang relevan dalam /etc/environmentatau /etc/profile.d, file lain yang saya pikir mungkin dapat dibaca oleh 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

Ada juga tidak ada yang relevan di salah satu file /etc/skel, tidak mengejutkan, juga tidak diatur dalam /etc/cron*file apa pun :

$ 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

Jadi, di mana PATH default cron untuk crontab pengguna disetel? Apakah hardcode cronitu sendiri? Bukankah itu membaca semacam file konfigurasi untuk ini?

terdon
sumber
3
Tidak ada alasan untuk cronmelihat /etc/profile, atau peduli dengan cangkang tertentu. Pertanyaan yang lebih baik adalah mengapa tidak cronmembaca PATHdari login.defs(di Linux) atau login.conf(di * BSD). Saya kira itu akhirnya merupakan detail implementasi.
Satō Katsura
@ SatōKatsura yakin, saya hanya menyebutkan /etc/profilekarena menggunakan sintaks yang sama ( var=value) seperti cronitu sendiri, jadi itu akan cukup mudah untuk dilakukan dan /etc/profile, setahu saya, sangat luas. Yang mengejutkan saya adalah bahwa saya tidak dapat menemukannya diatur di mana saja sehingga tampak seperti itu sulit dikodekan. Memang benar, seperti yang dijelaskan Stephen di bawah ini.
terdon
Orang-orang menggunakan zshsebagai shell interaktif mereka tidak peduli /etc/profile(yang khusus untuk bash)
Basile Starynkevitch
2
@ BasileStarynkevitch tidak, itu tidak spesifik untuk bash sama sekali ! Justru sebaliknya! Meskipun ada beberapa cangkang yang tidak membacanya (c-shell keluarga AFAIK), zsh bukan salah satunya. Lihat halaman manual zsh, jika kamu tidak percaya padaku. Bagaimanapun, shell interaktif tidak relevan karena berbagai profilefile hanya dibaca oleh shell login. Ini mungkin, atau mungkin tidak interaktif.
terdon
1
Kadang-kadang berjalan stringsmelawan suatu program dapat membantu menemukan nilai-nilai ini juga.
jrw32982 mendukung Monica

Jawaban:

47

Hard-coded dalam kode sumber (yang menunjukkan poin ke Debian saat ini cron- mengingat beragam cronimplementasi, sulit untuk memilih satu, tetapi implementasi lain mungkin serupa):

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

#ifndef _PATH_DEFPATH_ROOT
# define _PATH_DEFPATH_ROOT "/usr/sbin:/usr/bin:/sbin:/bin"
#endif

crontidak membaca jalur default dari file konfigurasi; Saya membayangkan alasan ada yang mendukung menentukan jalur yang sudah digunakan PATH=dalam cronjob, jadi tidak perlu untuk dapat menentukan default di tempat lain. (Default hard-coded digunakan jika tidak ada yang lain yang menentukan jalur dalam entri pekerjaan .)

Stephen Kitt
sumber
Perhatikan bahwa, terlepas dari adanya _PATH_DEFPATH_ROOTdefine, saya mengkonfirmasi (menggunakan cron job echo $PATH > /testfile) setelah mengedit crontab root menggunakan crontab -epada Debian Stretch yang juga menggunakan crontab root _PATH_DEFPATH, yaitu "/ usr / bin: / bin", tidak _PATH_DEFPATH_ROOT . Ini juga dikonfirmasi oleh tautan kode sumber kedua dalam jawaban ini (yang _PATH_DEFPATH_ROOTtidak digunakan). Tidak jelas bagi saya apakah definisi yatim ini adalah bug.
njahnke
8

Menambah jawaban Stephen Kitt, ada file konfigurasi yang set PATHuntuk cron pada Ubuntu, dan cron pengabaian yang PATHmenggunakan default keras-kode (atau PATHs diatur dalam crontab sendiri). File tersebut adalah /etc/environment. cronKonfigurasi PAM Note :

$ 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
...

Ini mudah diverifikasi. Tambahkan variabel ke /etc/environment, katakanlah foo=bar, jalankan env > /tmp/foosebagai cronjob dan tonton seperti yang foo=barditampilkan di output.


Tapi kenapa? Jalur lebar sistem default ditetapkan di / etc / profile, tetapi itu termasuk direktori lain:

$ grep PATH= /etc/profile
PATH="/usr/local/sbin:/usr/local/bin:/usr/bin"

Itu benar di Arch Linux, tetapi di Ubuntu, basis PATHsudah diatur /etc/environment. File di /etc/profile.dpakukan ke yang sudah ada PATH, dan Anda dapat menambahkannya di ~/.pam_environment. Saya memiliki bug yang diajukan tentang perilaku Arch .

Sayangnya, /etc/pam.d/crontidak termasuk membaca dari ~/.pam_environment. Anehnya, /etc/pam.d/atd memang termasuk file itu:

$ 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

... tetapi perintah yang dijalankan attampaknya mewarisi lingkungan yang tersedia saat membuat atpekerjaan (misalnya, env -i /usr/bin/at ...tampaknya menjalankan pekerjaan dengan lingkungan yang sangat bersih).

Mengubah /etc/pam.d/cronmemiliki user_readenv=1tampaknya tidak menimbulkan masalah, dan variabel di ~/.pam_environmentmulai muncul baik (kecuali untuk PATH, tentu saja).


Semua mengatakan, menetapkan variabel lingkungan untuk cron tampaknya menjadi bisnis yang berantakan. Tempat terbaik tampaknya berada dalam spesifikasi pekerjaan itu sendiri, jika hanya karena Anda tidak tahu variabel lingkungan bawaan mana yang mungkin diabaikan oleh cron (tanpa membaca sumbernya).

muru
sumber
Mengenai atpekerjaan, jika Anda membuang suatu atpekerjaan Anda akan melihatnya secara eksplisit mengatur lingkungan agar sesuai dengan lingkungan ketika pekerjaan itu dibuat.
Stephen Kitt