Как поймать SIGINT и проигнорировать его в дочернем процессе?

У меня есть основная программа, которая запускает программу из аргументов командной строки. Программа командной строки разветвляется и запускается в дочернем процессе. Когда SIGINT отправляется, я хочу поймать его и попросить пользователя подтвердить, что он / она хочет выйти. Если да, и родитель, и дочерний процесс заканчиваются, иначе дочерний процесс продолжает работать. Моя проблема в том, что я не могу заставить ребенка начать резервное копирование, когда пользователь говорит «нет». Я пробовал SIGSTOP и SIGCONT, но на самом деле они просто останавливают процессы.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>

extern char **environ;
void sigint_handler(int sig);
void sigint_chldhandler(int sig);

int main( int argc, char** argv)
{
    int pid;
    signal(SIGINT,sigint_handler);


    if((pid=fork())==0)
    {
            printf("%d\n",pid);

            execve(argv[1],argv,environ);
    }


    int status;
    waitpid(pid,&status,0);
}
void sigint_handler(int sig)
{
    printf("Do you want to quit?Yes/No:\n");
    char buf[4];
    fgets(buf, sizeof(char)*4, stdin);

    printf("child pid:%d\n",getpid());
    printf("parent pid:%d\n",getppid());

    if(strcmp(buf,"Yes")==0)
    {
            kill(-getpid(),SIGKILL);
            printf("Exiting!\n");
            exit(0);
    }

}

person user3213348    schedule 26.02.2014    source источник
comment
stackoverflow.com/questions/6803395/ - это?   -  person someuser    schedule 26.02.2014
comment
Также вы можете использовать signal(SIGINT, SIG_IGN); в дочернем процессе, я думаю, или написать для него другой обработчик SIGINT.   -  person someuser    schedule 26.02.2014
comment
нет, если я блокирую sigint, то бесконечный дочерний процесс никогда не останавливается, когда пользователь нажимает ctrl C. Я хочу отправить cntl C sig и попросить пользователя подтвердить, действительно ли он хочет выйти, если пользователь говорит «нет», тогда дочерний процесс продолжается   -  person user3213348    schedule 26.02.2014
comment
Вы можете остановить дочерний процесс от родительского. У вас есть дочерний pid. SIGINT приходит в родительский процесс и в дочерний процесс. Родительский процесс вызывает ваш обработчик. Ребенок обрабатывает этот сигнал по умолчанию. Это твоя проблема.   -  person someuser    schedule 26.02.2014


Ответы (2)


Если вы не настроите обработку сигнала дочернего элемента, он будет завершен прерыванием при отправке сигнала, независимо от того, что происходит в родительском. Поэтому вам нужно быть более изощренным. Я думаю, вам понадобится что-то вроде:

  1. Родительский процесс устанавливает свой обработчик сигнала SIGINT.
  2. Родительские вилки.
  3. Дочерний процесс устанавливает для обработки SIGINT значение SIG_IGN.
  4. Ребенок выполняет указанную команду.
  5. Родитель ждет поступления SIGINT, вероятно, во время выполнения waitpid().
  6. Когда он приходит, он отправляет SIGSTOP дочернему элементу.
  7. Он задает вопрос и получает ответ.
  8. Если ответ должен быть продолжен, то он отправляет SIGCONT дочернему процессу и возвращается в режим ожидания.
  9. Если ответ должен остановить, то он отправляет сначала SIGCONT, а затем SIGTERM (или другой сигнал, отличный от SIGINT) дочернему элементу, чтобы убить его. (Использование SIGKILL нецелесообразно; ребенку следует дать возможность выйти в ответ на SIGTERM или SIGHUP. Если ребенок не воспринимает всерьез угрозу смерти, вы можете послать ему SIGKILL.)
  10. Когда родитель установил, что потомок вышел, он может выйти в свою очередь.

Обратите внимание, что если дочерний процесс выполняет что-то вроде vim, что резко меняет настройки терминала, то отправка этого SIGKILL оставит терминал в косом состоянии. Он с трудом возвращает его в нормальное состояние; лучше дать программе возможность сбросить настройки терминала самостоятельно.

person Jonathan Leffler    schedule 26.02.2014

SIGINT приходит в родительский процесс и в дочерний процесс (в группу процессов).
Родительский процесс вызывает ваш обработчик.
Ребенок обрабатывает этот сигнал по умолчанию.
Вы можете использовать это, например:

#include <unistd.h>
#include <signal.h>
#include <stdio.h>
int main()
{
    pid_t pid;
    char c;
    switch(pid = fork())
    {
        case -1:
            printf("!!!");
            return -1;
        break;
        case 0:
            printf("child started\n");
            while(1) { };
        break;
        default:
            while(1)
            {
                c = getchar();
                if(c == 'q')
                {       
                        //your conditions
                        kill(pid, SIGKILL);
                        return 0;
                }
            }
        break;
    }
    return 0;
}
person someuser    schedule 26.02.2014