Как я могу включить ctrl-c / ctrl + break после вызова системы? - PullRequest
2 голосов
/ 22 сентября 2010

Я написал программу, которая вызывает системную команду изнутри:

#include <stdlib.h>

int main(void)
{
    while(1)
    {
        system("ls 2>&1 1>/dev/null"); // comment this line out to enable ctrl+break
    }

    return 0;
}

Однако, когда она работает, CTRL + C и CTRL + BREAK больше не работают и, похоже, игнорируются.

Я пытаюсь написать программу, которая выполняет некоторые операции в фоновом режиме, включая оболочку, но я также хочу иметь возможность выйти из программы, когда пользователь хочет сломаться.

Есть лиспособ заставить его работать так, как я хочу?Должен ли я изменить архитектуру для выполнения какого-либо форка / exec?

Ответы [ 3 ]

5 голосов
/ 22 сентября 2010

Из спецификации POSIX для system():

Функция system () игнорирует сигналы SIGINT и SIGQUIT и блокирует сигнал SIGCHLD, ожидая завершения команды.Если это может привести к тому, что приложение пропустит сигнал, который убил бы его, то приложение должно проверить возвращаемое значение из system () и предпринять любое действие, подходящее для приложения, если команда прервана из-за получениясигнала.

Итак, чтобы правильно реагировать на сигналы, необходимо проверить возвращаемое значение system().

system () возвращает завершениестатус интерпретатора командного языка в формате, заданном waitpid ()

А документы waitpid() относятся к документам для wait(), который инструктирует вас использовать следующие макросы, чтобы выяснить причину выхода из процесса:

  • WIFEXITED (stat_val)
    Оценивает ненулевое значение, еслистатус был возвращен для дочернего процесса, который нормально завершился.
  • WEXITSTATUS (stat_val)
    Если значение WIFEXITED (stat_val) не равно нулю, этот макрос оценивается как младшие 8 битов status аргумент, что дочерний процесс передан _exit () или exit (), или значение, которое дочерний процесс возвратил из main ().
  • WIFSIGNALED (stat_val)
    Оценивает ненулевое значение, если статус былвозвращается для дочернего процесса, который завершился из-за получения сигнала, который не был перехвачен (см.).
  • WTERMSIG (stat_val)
    Если значение WIFSIGNALED (stat_val) не равно нулю, этот макросвычисляется по номеру сигнала, вызвавшего завершение дочернего процесса.
  • WIFSTOPPED (stat_val)
    Оценивает ненулевое значение, если статус был возвращен для дочернего процесса, который в данный момент остановлен.
  • WSTOPSIG (stat_val)
    Если значение WIFSTOPPED (stat_val) не равно нулю, этот макрос оценивается как номер сигнала, вызвавшего остановку дочернего процесса.
  • WIFCONTINUED (stat_val)
    Оценивает ненулевое значение, если статус был возвращен для дочернего процесса, который продолжился с остановки управления заданием.

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

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

int main(void)
{
    while(1)
    {
        int result = system("ls 2>&1 1>/dev/null");
        if (WIFEXITED(result)) {
          printf("Exited normally with status %d\n", WEXITSTATUS(result));
        } else if (WIFSIGNALED(result)) {
          printf("Exited with signal %d\n", WTERMSIG(result));
          exit(1);
        } else {
          printf("Not sure how we exited.\n");
        }
    }

    return 0;
}

И если вы запустите его, вы получите:

$ ./sys
Exited normally with status 0
Exited normally with status 0
Exited normally with status 0
Exited normally with status 0
Exited normally with status 0
Exited normally with status 0
^CExited with signal 2
2 голосов
/ 22 сентября 2010

Согласно Стандарт IEEE 1003.1-2008 (POSIX) :

  • Функция system() должна вести себя так, как если бы дочерний процесс был создан с использованиемfork(), ...

  • Функция system() должна игнорировать сигналы SIGINT и SIGQUIT и блокировать сигнал SIGCHLD, покаожидание команды прекратить.Если это может привести к тому, что приложение пропустит сигнал, который мог бы его убить, то приложение должно проверить возвращаемое значение из system() и предпринять любое действие, соответствующее приложению, если команда прервалась из-за получения сигнала.

  • Функция system() не должна возвращаться, пока дочерний процесс не завершится.

1 голос
/ 23 сентября 2010

Из вышеприведенного комментария Сан-Хасинто:

system () по существу разветвляется, блокирует родительский элемент и игнорирует определенные сигналы в дочернем элементе согласно ссылкам спецификации POSIX.Вы можете обойти это, сначала создав другой процесс для system (), чтобы заблокировать.Это оставляет исходный процесс (прародитель процесса, на котором работает оболочка) свободным для приема сигналов уничтожения.

#include <stdlib.h>
#include <unistd.h>
#include <wait.h>

int main(void)
{
    pid_t pid;

    while(1)
    {
        pid = fork();

        if(pid > 0) // parent
        {
            wait(0);
        }
        else if(pid == 0) // child
        {
            system("ls 2>&1 1>/dev/null");
            return 0;
        }
        else // could not fork
        {
            return 1;
        }
    }

    return 0;
}

На первый взгляд, это делает то, что мне нужно.

...