Mengapa "su -c <command> &" tampaknya memungkinkan perintah untuk berjalan di latar belakang tanpa menutup telepon

11

Saya sedang membantu seorang kolega yang mengalami masalah dengan proses latar belakang yang sebentar-sebentar sekarat.

Saya menemukan bahwa mereka memulai proses latar belakang dengan masuk ke server dan menjalankan:

su - <user> -c '<command>' &

"Aha", seruku. "Jika Anda memulai perintah dengan" & "itu akan hang-up ketika Anda keluar dari terminal pengendali. Anda perlu menggunakan sesuatu seperti nohup untuk mencapai ini. Sungguh proses ini perlu mendukung berjalan sebagai daemon, tut tut."

Kami menguji perintah di atas untuk menunjukkan maksud saya dan ... sepertinya berhasil: proses yang dimulai dengan perintah tidak keluar ketika kami keluar dari terminal yang menjalankan perintah di atas.

perintah adalah skrip Python khusus yang hasilnya dikirim ke file. Sejauh yang saya tahu, tidak ada kemampuan "daemonize" cerdas dalam skrip. Itu tidak melakukan hal-hal yang diperlukan untuk dijalankan sebagai daemon yang terdaftar di Wikipedia: Daemon (komputasi): halaman Pembuatan .

Menjalankan perintah seperti itu berlaku seperti yang diharapkan:

<command> &
exit

Dalam kasus di atas proses latar belakang dimulai dengan perintah keluar ketika kita keluar dari terminal.

Pertanyaan saya adalah ini:

  1. Apa yang terjadi ketika kita menambahkan "su - -c &" yang mencegah proses keluar saat terminal kita keluar. Saya ingin memahami secara detail sehubungan dengan terminal pengendali, input dan output standar dll.

  2. Apakah ini cara yang masuk akal untuk mencapai tujuan menjalankan perintah ini sebagai proses latar belakang. Jika tidak mengapa, bukan?

Saya ingin menyebarkan praktik terbaik dalam perusahaan saya, tetapi saya harus dapat menunjukkan dan mendukung semua rekomendasi yang saya buat.

Saya juga ingin mengerti apa yang sebenarnya terjadi.

Sam Elstob
sumber

Jawaban:

12

Ada beberapa cara suatu proses dapat dibunuh karena terminal sekarat.

  1. Cara pertama adalah bahwa driver terminal di kernel mengirimkan sinyal SIGHUP ke proses kontrol yang mana terminal adalah terminal pengendali . Dalam kebanyakan kasus, proses pengendalian adalah shell yang awalnya dimulai di terminal, dan terminal pengendali adalah yang terhubung dengan stdin, stdout dan stderr. Suatu proses menjadi terputus dari terminal pengendali jika ia memanggil setsid.

  2. Cara kedua adalah shell, ketika menerima SIGHUP, mengirim kembali sinyal itu ke subprosesnya - lebih tepatnya, ke pekerjaan latar belakangnya. Beberapa shell (ksh, bash, zsh) memiliki disownbuiltin untuk memberi tahu shell agar tidak mengirim SIGHUP ke pekerjaan tertentu.

  3. Jika terminal hilang dan sebuah program mencoba untuk membacanya, itu diberitahukan tentang kondisi akhir file (atau mungkin EIO untuk pekerjaan latar belakang). Jika terminal hilang dan suatu program mencoba menulis ke sana, penulisan kembali dengan kesalahan EIO. Ini mungkin menyebabkan program keluar.

Jadi superubahan di sini adalah bahwa (2) biasanya akan menyebabkan shell awal untuk mematikan pekerjaan latar belakang, tetapi karena proses latar belakang berjalan sebagai pengguna yang berbeda, sinyal tidak dapat dikirim, dan proses latar belakang hidup.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
Saya telah melihat pengguna root lakukan chroot --userspec root:root / sh -c "exec some_forever_process" &. Pekerjaan berjalan sebagai pengguna yang sama, tanpa eksplisit nohupsebelum atau disownsesudahnya. Jadi untuk kasus ini, bagaimana caranya sinyal tidak dapat dikirim pada saat term term?
Toddius Zho
@ToddiusZho Presumable some_forever_processdimaksudkan untuk berjalan selamanya (daemon) dan karenanya melindungi dirinya sendiri dari menerima SIGHUP dari terminal keluar (dengan menjalankan grup prosesnya sendiri).
Gilles 'SANGAT berhenti menjadi jahat'
bash / tail tidak melindungi terhadap SIGHUP, namun itu masih berfungsi: `` `$ ssh root lokal @ REMOTE_HOST remote # chroot - root root: shs / ​​sh -c" exec bash -c 'tail -f / dev / null '"& [1] 6376 remote # ps -p $! --no-heading -o pid, uid, perintah -ww 6376 0 tail -f / dev / null remote # keluar lokal $ ssh root @ REMOTE_HOST remote # ps -p 6376 --no-heading -o pid, uid, command -ww 6376 0 tail -f / dev / null `` `
Toddius Zho