2015-11-26 18 views
5

Il programma che ho è la seguente:È possibile che un programma acquisisca SIGTERM generato dalla chiamata di sistema di uscita?

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include <signal.h> 

int main() 
{ 
    struct sigaction new_sa; 
    struct sigaction old_sa; 
    sigfillset(&new_sa.sa_mask); 
    new_sa.sa_handler = SIG_IGN; 
    new_sa.sa_flags = 0; 
    int input; 

    if (sigaction(SIGTERM, &new_sa, &old_sa) == 0 && old_sa.sa_handler != SIG_IGN) { 
     new_sa.sa_handler = NULL; 
     sigaction(SIGTERM, &new_sa, 0); 
    } 

    printf("Pgm is running\n"); 
    while (1) { 
     printf("Enter input\n"); 
     scanf("%d", &input); 
     if (!input) { 
      /* I actually call a libraries API which calls exit() 
      * Just calling exit here for simpilicity */ 
      exit(1); 
     } 
    } 
} 

voglio gestire/ignorare SIGTERM generato dalla chiamata di sistema di uscita. È possibile? Non c'è modo per me di evitare di chiamare exit poiché in realtà è una chiamata alla libreria che sta cercando di uscire dal programma che voglio evitare.

+2

Sei sicuro che 'exit' invia un segnale SIGTERM? Non ne ho mai sentito parlare prima e nell'esecuzione in gdb non mostra un SIGTERM su 'exit'. – kaylum

+0

Sì, sembra che tu abbia ragione. Non sta inviando SIGTERM. – Nikhil

risposta

2

Guardando allo glibc source per l'uscita sembra che non sia possibile. Ma potrebbe essere se stai usando un'altra libreria C std.

Si possono fare cose a_exit ma non è possibile impedirlo.

[modifica]

Tutto qua giù non è evidentemente applicabile per l'uscita per i motivi in ​​this question.

Se si utilizza ld gnu potrebbe essere possibile eseguire l'override __run_exit_handlers, o exit per quella materia, utilizzando il ld GNU --wrap opzione, ma io hav provato.

Se è possibile utilizzare gnu ld, è possibile eseguire --wrap exit e quindi implementare __wrap_exit() nel codice. Se si desidera chiamare exit dopo questo è possibile accedervi tramite __real_exit(). Questa è una caratteristica di gnu ld e non sono sicuro di quanto sia universalmente disponibile.

+0

È possibile sostituire la chiamata exit() nella libreria con qualche altra funzione che fa la stessa cosa e che posso "catturare"? – Nikhil

+0

Sto usando glibc – Nikhil

+0

GNU ld ha l'opzione --wrap per farlo. Potrebbe funzionare. Se risposta aggiornata. – evading

0

Una possibilità è eseguire la chiamata di libreria in un processo figlio con fork. Ciò non impedisce la chiamata a exit ma potrebbe essere una soluzione alternativa se si desidera gestire l'errore da soli.

A seguito di un tutorial Fork, Exec and Process control. Io uso pipe per inviare il risultato della chiamata alla biblioteca se la chiamata ha successo.

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/wait.h> 

int main(){ 
    int pipefd[2]; 
    pipe(pipefd); //Create pipe for communication 
    pid_t pid = fork(); 
    if (pid == 0){ //Child process 
    close(pipefd[0]); // close the read-end of the pipe, 
    printf("Run library here\n"); 
    // exit(3); if failed 
    int val=4; //Result of library call send to parent 
    write(pipefd[1], &val, sizeof(val)); 
    close(pipefd[1]); // close the write-end of the pipe 
    exit(EXIT_SUCCESS); 
    } 
    else if (pid < 0){   
    printf("Failed to fork\n"); 
    } 
    else{//Parent process 
    close(pipefd[1]); 
    printf("Parent process\n"); 
    int status=0; 
    int pid=wait(&status); 
    printf("The pid %d finished with status %d\n",pid,status);   
    if (status==EXIT_SUCCESS){//The library call was successful 
     int val=2; 
     read(pipefd[0],&val,sizeof(int)); //Read data from pipe and do something with it 
     printf("Value %d received\n",val); 
    } 
    close(pipefd[0]); 
    } 
    return 0; 
} 
2

Si può certamente prendere SIGTERM. Ma non è questo il problema qui. Si desidera ignorare la chiamata exit().

Questo non è possibile in alcun modo portatile o conforme allo standard. Il exit() è una delle funzioni che è definita per non ritorno al relativo chiamante. In genere, questo viene fatto utilizzando lo __attribute__((noreturn)) in gcc e C11 ha introdotto la macro _Noreturn per lo stesso scopo.

Il tentativo di ritorno da tale funzione, ad esempio exit(), è undefined behaviour.

Ci sono alcune opzioni, mi viene in mente:

  • Compilare e sostituirli con la funzione: gcc -Dexit=not_exit file.c
  • Scrivete una funzione gancio per exit(). Vedere here per un esempio. L'implementazione di una funzione di hook potrebbe non funzionare affatto poiché questo noreturn è esistito sulla maggior parte delle implementazioni di libc prima di C2 _Noreturn.
  • Usa GNU ld come suggerito da @evading.Credo che questo sia equivalente a quanto sopra ma il linker fa la metà del lavoro per te.

Modifica <stdlib.h> per rimuovere l'attributo _Noreturn (o equivalente) per la funzione exit() potrebbe farlo funzionare. Nessuno di questi è garantito per funzionare. Siamo già nella terra dell'UB.

Un'altra opzione è per un gestore di installazione atexit(), che potrebbe essere utile se si desidera fare qualcosa prima di exit().

Un approccio più sicuro sarebbe quello di modificare la libreria se non si chiama exit() ma si restituisce invece un codice di errore. Secondo me, la libreria è mal progettata perché esce in modo casuale da sola o probabilmente c'è una buona ragione per cui la libreria esce (a causa di un errore irreversibile) e la tua applicazione non dovrebbe continuare oltre, cosa che stai tentando di fare.