简体   繁体   中英

Why the signal handler doesn't process the signal

I'm trying to make a program that simulates the command nohup. The program gets as a first parameter, the name of a command that is gonna be executed. The program executed by my program must not be notified when the terminal is closed, it will have to ignore the SIGHUP. If I test my program with with the following command:

         ./mynohup sleep 120 &

And then I try to send a SIGHUP from another terminal, sleep terminates when it should be immune to it.

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

I tried to skip creating a new process and the signal handler works great. If the signal handler is in the following form the program works

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

I don't understand why when I create the first version of the signal handler the program doesn't works and with the second one it works.

Thanks in advance!

All exec functions reset the dispositions of caught signals to their default dispositions.

When you exec, your process image is destroyed and replaced by the process image of the new program. In it, the pointer to the handle_function you passed to sigaction no longer has meaning, or the old meaning at least. The only sensible thing the OS can do with handled signals upon execve is to reset them.

The meaning of SIG_IGN is universal and independent of the current program and that's why SIG_IGN can be, and is, inherited.

execvp() is a front end for the execve() syscall.

From its linux manpage :

All process attributes are preserved during an execve(), except the following:

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

So the signal handler you installed is reset.

CORRECTION: (see history of changes for original text)

The nohup(1) program just shifts the progran name ( nohup ) and the options to it, from the argc / argv parameters to main , redirects stdout / stderr to a file ( nohup.out ) in case one or both are directed to a tty device, and then just ignores SIGHUP and execvp(*argv, argv); for the original program to execute. It even does no fork(2) at all.

The source code of FreeBSD nohup is available here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM