4

http://www.masterraghu.com/subjects/np/introduction/unix_network_programming_v1.3/ch13lev1sec4.html (excerpt from Richard Steven's UNIX Network Programming Vol. 1) includes

Signal(SIGHUP, SIG_IGN);

as part of the daemon_init function because:

..."We must ignore SIGHUP because when the session leader terminates (the first child), all processes in the session (our second child) receive the SIGHUP signal."

The core of the function is:

int     i;
pid_t     pid;

if ( (pid = Fork()) < 0)
    return (-1);
else if (pid)
    _exit(0);               /* parent terminates */

/* child 1 continues... */

if (setsid() < 0)           /* become session leader */
    return (-1);

Signal(SIGHUP, SIG_IGN);
if ( (pid = Fork()) < 0)
    return (-1);
else if (pid)
    _exit(0);               /* child 1 terminates */

/* child 2 continues... */

daemon_proc = 1;            /* for err_XXX() functions */

What I don't understand is why should the target child get a SIGHUP?

I tried replicating that code with some info-printing to test that SIGHUP is really received but I can't seem to catch it, not even if I stop (SIGSTOP) the grandchild process, in which case I thought it really should get a SIGHUP because that would cause the grandchild to become a stopped orphaned process group, but no SIGHUP gets received even then (this is obviously related to the SIGSTOP part: why SIGHUP signal not received when becoming an Orphaned Process Group ).

#define _GNU_SOURCE
#include <unistd.h>
#include <signal.h>
#include <stdio.h>

int daemon_proc = 0;

static void
pr_ids(char* name){
    printf("%s: pid = %ld, ppid = %ld, sid=%ld, pgrp = %ld, tpgrp = %ld\n",
            name, (long)getpid(), (long)getppid(), (long)getsid(getpid()), (long)getpgrp(),
            (long)tcgetpgrp(STDOUT_FILENO));
    fflush(stdout);
}
void hndlr(int s){
    static const char msg[] = "Caught SIGHUP\n";
    write(2,msg,sizeof(msg));
}
int daemon_init(){
    pid_t pid;
    pr_ids("gparent");

    if ( 0>(pid=fork()))
        return -1;
    if (pid) 
        _exit(0);

    pr_ids("parent");
    if (0>setsid())
        return -1;

    close(0);
    dup(1);

    if(0>sysv_signal(SIGHUP, hndlr))
        return -1;
    if(0>(pid=fork()))
        return -1;
    if(pid){
        sleep(1);
        _exit(0);
    }
    pr_ids("child");
    sleep(2);
    pr_ids("child");
    kill(getpid(), SIGSTOP);
    daemon_proc = 1;
    chdir("/");
    return 0;
}
int main(int argc, char** argv){
    daemon_init();
    printf("daemon_proc=%d\n", daemon_proc);
    return 0;
}

This gives me outputs such as:

 gparent: pid = 20904, ppid = 20015, sid=20015, pgrp = 20904, tpgrp = 20904
 parent: pid = 20905, ppid = 1, sid=20015, pgrp = 20904, tpgrp = 20015
 child: pid = 20906, ppid = 20905, sid=20905, pgrp = 20905, tpgrp = -1
 #waiting
 child: pid = 20906, ppid = 1,   sid=20905, pgrp = 20905, tpgrp = -1

Can you explain why self-termination of the first child (session leader) should cause a SIGHUP in the second child and why it doesn't?

Community
  • 1
  • 1
Petr Skocik
  • 58,047
  • 6
  • 95
  • 142
  • 1
    You've probably already read it, but the POSIX specification for [`_exit()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/_exit.html) details what happens when a process exits, and in particular when SIGHUP signals are sent to the children of a dying process. You also need to be aware of the POSIX [`definitions`](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html) of things such as controlling processes, controlling terminals, sessions, session leaders, etc. It is intricate. – Jonathan Leffler Aug 23 '16 at 17:49
  • @JonathanLeffler Thanks a lot for the links. Solved the problem! I simply needed to make the session leader into a "controlling process" by attaching a new terminal (pty) to it. Then when the session leader dies, I get that SIGHUP. (By my interpretation, that makes ignoring SIGHUP in the daemon_init function unecessary. Only a session leader may become a controlling process, and if the session leader exits immediately after it forks, its child is without a controlling process and so should not get a SIGHUP.) – Petr Skocik Aug 23 '16 at 19:24
  • I hesitated to suggest that the signal handling was superfluous until I'd had a chance to step through everything, but I had some suspicions. I have a program and a library function (both in source files `daemonize.c` — oh well) that both include the ignoring of SIGHUP, but I based the code on the same source as you, hence the same problem as you. Ignoring SIGHUP may not be necessary; it is unlikely to do any harm, though. – Jonathan Leffler Aug 23 '16 at 20:11

0 Answers0