Почему обработчик сигнала не обрабатывает сигнал - PullRequest
0 голосов
/ 16 июня 2019

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

         ./mynohup sleep 120 &

И затем я пытаюсь отправить SIGHUP с другого терминала, сон прерывается, когда он должен быть защищен от него.

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

#include <signal.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>

#include "utils.h"

#define NOHUP_OUT_FILE      "nohup.out"

static void handle_signal(int signum)
{
    if(signum == SIGHUP)
    {
        printf("This is ignored\n");
    }
    else
    {
        printf("Not ignored\n");
    }
    fflush(stdout);
}

/* configure handlers */
static void set_signals(void)
{
    struct sigaction sa;
    int rc;

    /* TODO - ignore SIGHUP */
    memset(&sa, 0, sizeof(struct sigaction));
    sa.sa_handler = handle_signal;
    rc = sigaction(SIGHUP, &sa, NULL);

    DIE(rc == -1, "sigaction");

}

/* execute a new program */
static void exec_func(int argc, char **argv)
{
    int rc;
    int i;
    char **exec_args;
    int fd;

    set_signals();  /* ignore SIGHUP */

    if(isatty(STDOUT_FILENO))
    {
        fd = open(NOHUP_OUT_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0644);
        DIE(fd < 0, "open");

        dup2(fd, STDOUT_FILENO);
        close(fd);
    }

    /* exec a new process */
    exec_args = malloc(argc * sizeof(*exec_args));
    DIE(exec_args == NULL, "malloc");

    for (i = 0; i < argc-1; i++)
        exec_args[i] = argv[i+1];
    exec_args[argc-1] = NULL;

    execvp(exec_args[0], exec_args);
    DIE(1, "execvp");
}

int main(int argc, char **argv)
{
    if (argc <= 1) {
        fprintf(stderr, "Usage: %s command_and_arguments\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    exec_func(argc, argv);

    return 0;
}

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

static void set_signals(void)
{
    struct sigaction sa;
    int rc;

    /* ignore SIGHUP */
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = SIG_IGN;

    rc = sigaction(SIGHUP, &sa, NULL);
    DIE(rc == -1, "sigaction");
}

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

Заранее спасибо!

Ответы [ 3 ]

2 голосов
/ 16 июня 2019

execvp() - это интерфейс для системного вызова execve().

С справочная страница linux :

Все атрибуты процесса сохраняются во время execve (), кроме следующих:

  *  The dispositions of any signals that are being caught are reset to
      the default (signal(7)).

Таким образом, установленный вами обработчик сигнала сбрасывается.

2 голосов
/ 16 июня 2019

Все функции exec сбрасывают расположение перехваченных сигналов в их расположение по умолчанию.

Когда вы выполняете, ваш образ процесса уничтожается и заменяется образом процесса новой программы.В нем указатель на handle_function, который вы передали sigaction, больше не имеет значения или, по крайней мере, старого значения.Единственная разумная вещь, которую ОС может сделать с обработанными сигналами при execve, - это сброс их.

Значение SIG_IGN универсально и не зависит от текущей программы, и поэтому SIG_IGN может быть, иесть, унаследовано.

0 голосов
/ 16 июня 2019

ИСПРАВЛЕНИЕ: (см. Историю изменений для исходного текста)

Программа nohup(1) просто смещает имя программы (nohup) и параметры к нему из argc / argvпараметры на main, перенаправляет stdout / stderr в файл (nohup.out), если один или оба направлены на устройство tty, а затем просто игнорирует SIGHUP и execvp(*argv, argv); для исходной программы навыполнить.Он даже вообще не fork(2).

Исходный код nohup FreeBSD доступен здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...