2015-11-26 5 views
5

Das Programm, das ich habe, ist wie folgt:Ist es für ein Programm möglich, SIGTERM zu erfassen, das vom Systemaufruf exit generiert wurde?

#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); 
     } 
    } 
} 

ich behandeln möchten/ignorieren SIGTERM durch Exit Systemaufruf erzeugt. Ist es möglich? Es gibt keine Möglichkeit für mich, den Aufruf von exit zu vermeiden, da es sich tatsächlich um einen Bibliotheksaufruf handelt, der versucht, das Programm zu beenden, das ich vermeiden möchte.

+2

Sind Sie sicher, dass 'exit' ein SIGTERM-Signal sendet? Davon habe ich noch nie gehört und in gdb läuft kein 'SIGTERM' auf 'exit'. – kaylum

+0

Ja .. sieht aus wie du hast Recht. Es sendet kein SIGTERM. – Nikhil

Antwort

2

Mit Blick auf die glibc source für den Ausgang sieht es aus wie es nicht möglich ist. Aber es könnte sein, wenn Sie eine andere C std-Bibliothek verwenden.

Sie können Sachen at_exit tun, aber Sie können es nicht verhindern.

[Bearbeiten]

Alles hier unten ist offenbar nicht anwendbar für den Austritt aus den genannten Gründen in this question.

Wenn Sie gnu ld verwenden, könnte es möglich sein, __run_exit_handlers oder für die Angelegenheit zu überschreiben, mit der gnu ld --wrap Option, aber ich habe es nicht ausprobiert.

Wenn Sie gnu ld verwenden können, können Sie --wrap exit ausführen und dann __wrap_exit() in Ihrem Code implementieren. Wenn Sie danach 10 anrufen möchten, können Sie darauf unter __real_exit() zugreifen. Dies ist ein Gnu ld Feature und ich bin mir nicht sicher, wie universell es ist.

+0

Ist es möglich, den Aufruf von exit() in der Bibliothek durch eine andere Funktion zu ersetzen, die dasselbe tut und die ich "fangen" kann? – Nikhil

+0

Ich verwende glibc – Nikhil

+0

GNU ld hat die --wrap Option, das zu tun. Es könnte funktionieren. Se aktualisierte Antwort. – evading

0

Eine Möglichkeit besteht darin, den Bibliotheksaufruf in einem untergeordneten Prozess mit fork auszuführen. Dies verhindert nicht den Aufruf an , aber möglicherweise eine Problemumgehung, wenn Sie den Fehler selbst behandeln möchten.

Nach einem Tutorial Fork, Exec and Process control. Ich verwende Pipes, um das Ergebnis des Bibliotheksrückrufs zu senden, wenn der Aufruf erfolgreich ist.

#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

Sie können sicherlich SIGTERM fangen. Aber das ist nicht das Problem hier. Sie möchten den Anruf exit() überschreiben.

Dies ist in keiner tragbaren oder standardkonformen Weise möglich. Die exit() ist eine der Funktionen, die zu nicht zurück zu seinem Aufrufer definiert ist. In der Regel erfolgt dies mit dem __attribute__((noreturn)) in gcc und C11 hat das Makro _Noreturn für den gleichen Zweck eingeführt.

Der Versuch, von einer solchen Funktion wie exit() zurückzukehren, ist undefined behaviour.

Es gibt nur wenige Möglichkeiten, kann ich mir vorstellen:

  • Compile und ersetzen Sie durch Ihre Funktion: gcc -Dexit=not_exit file.c
  • eine Hook-Funktion für exit() schreiben. Ein Beispiel finden Sie unter here. Das Implementieren einer Hook-Funktion funktioniert möglicherweise überhaupt nicht, da dieses noreturn in den meisten libc-Implementierungen vor C11s _Noreturn existiert hat.
  • Verwenden Sie GNUs ld wie von @evading vorgeschlagen.Ich glaube, das entspricht dem oben genannten, aber der Linker macht die Hälfte der Arbeit für Sie.

<stdlib.h> Ändern der _Noreturn (oder dessen Äquivalent) Attribut für die exit() Funktion zu entfernen, könnte es funktioniert. Keines davon funktioniert garantiert. Wir sind schon gut in UB Land.

Andere Option ist eine Installation atexit() Handler, die nützlich sein könnte, wenn Sie etwas vor exit() tun möchten.

Ein vernünftigerer Ansatz wäre, die Bibliothek zu ändern, wenn Sie nicht exit() aufrufen, sondern stattdessen einen Fehlercode zurückgeben. Meiner Meinung nach ist entweder die Bibliothek schlecht entworfen, dass sie zufällig von alleine austritt oder wahrscheinlich gibt es einen guten Grund, dass die Bibliothek (aufgrund eines nichtbehebbaren Fehlers) austritt und Ihre Anwendung nicht weiter fortgesetzt werden soll, was Sie versuchen machen.