Perché "su -c <comando> &" sembra consentire l'esecuzione di un comando in background senza riagganciare


11

Stavo aiutando un collega che stava avendo problemi con un processo in background che moriva a intermittenza.

Ho scoperto che stavano iniziando il processo in background accedendo al server ed eseguendo:

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

"Aha", ho esclamato. "Se avvii un comando con" & "si bloccherà quando esci dal terminale di controllo. Per ottenere ciò devi usare qualcosa come nohup. In realtà questo processo deve supportare l'esecuzione come demone, tut tut."

Abbiamo testato il comando sopra per dimostrare il mio punto e ... sembrava funzionare: il processo avviato dal comando non è terminato quando siamo usciti dal terminale che ha eseguito il comando sopra.

Il comando è uno script Python personalizzato il cui output passa a un file. Per quanto ne so, nella sceneggiatura non esiste una funzionalità "daemonize" intelligente. Non fa nulla del necessario per funzionare come demone elencato nella pagina Wikipedia: Daemon (informatica): Creazione .

L'esecuzione del comando in questo modo si comporta come previsto:

<command> &
exit

Nel caso precedente il processo in background avviato dal comando termina quando usciamo dal terminale.

La mia domanda è questa:

  1. Cosa succede quando aggiungiamo "su - -c &" che impedisce al processo di uscire quando il nostro terminale esce. Vorrei capire in dettaglio per quanto riguarda il terminale di controllo, input e output standard ecc.

  2. È un modo ragionevole per raggiungere l'obiettivo di eseguire questo comando come processo in background? Se no, perché no?

Voglio diffondere le migliori pratiche all'interno della mia azienda, ma devo essere in grado di dimostrare e supportare tutte le raccomandazioni che faccio.

Voglio anche capire cosa sta succedendo esattamente.

Risposte:


12

Esistono diversi modi in cui un processo potrebbe essere ucciso a causa di un terminale morente.

  1. Il primo modo è che il driver del terminale nel kernel invii un segnale SIGHUP al processo di controllo per il quale il terminale è il terminale di controllo . Nella maggior parte dei casi, il processo di controllo è la shell che viene inizialmente avviata nel terminale e il suo terminale di controllo è quello a cui sono collegati stdin, stdout e stderr. Un processo viene disconnesso dal terminale di controllo se chiama setsid.

  2. Il secondo modo è che la shell, quando riceve SIGHUP, rispedisce quel segnale ai suoi sottoprocessi - più precisamente, ai suoi lavori in background. Alcune shell (ksh, bash, zsh) hanno un disownbuiltin per dire alla shell di non inviare un SIGHUP a un particolare lavoro.

  3. Se il terminale scompare e un programma tenta di leggerlo, viene notificato una condizione di fine file (o eventualmente EIO per un processo in background). Se il terminale scompare e un programma tenta di scrivere su di esso, la scrittura ritorna con un errore EIO. Ciò potrebbe causare la chiusura del programma.

Quindi ciò che sucambia qui è che (2) normalmente farebbe sì che la shell iniziale uccida il processo in background, ma poiché quel processo in background è in esecuzione come un altro utente, il segnale non può essere consegnato e il processo in background continua.


Ho visto fare l'utente root chroot --userspec root:root / sh -c "exec some_forever_process" &. Il lavoro è in esecuzione come lo stesso utente, senza esplicito nohupprima o disowndopo. Quindi, in questo caso, come è possibile che il segnale non possa essere inviato all'uscita termine?
Toddius Zho,

@ToddiusZho Presumable some_forever_processdoveva funzionare per sempre (un demone) e quindi si protegge dalla ricezione di SIGHUP da un'uscita terminale (eseguendo nel proprio gruppo di processi).
Gilles 'SO- smetti di essere malvagio' il

bash / tail non protegge da SIGHUP, ma funziona ancora: `` local $ ssh root @ REMOTE_HOST remote # chroot --userspec root: root / sh -c "exec bash -c 'tail -f / dev / null '"& [1] 6376 remoto # ps -p $! --no-header -o pid, uid, comando -ww 6376 0 tail -f / dev / null remote # esci locale $ ssh root @ REMOTE_HOST remote # ps -p 6376 --no-header -o pid, uid, comando -ww 6376 0 tail -f / dev / null `` `
Toddius Zho
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.