/**
* SIGHUP test01: how if a session leader associated with a ctty is killed,
* what happen to it's clild processes.
*
* ONLY IF the session leader have assoicated with a ctty, (and if the
* session exited), its child processes will receive SIGHUP.
*
* compile with -D_XOPEN_SOURCE=500 (>=500)
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <signal.h>
#include <termios.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#ifndef _XOPEN_SOURCE
#error "please compile with -D_XOPEN_SOURCE=500 (>=500)"
#endif
#ifdef _XOPEN_SOURCE
#if _XOPEN_SOURCE < 500
#error "please compile with -D_XOPEN_SOURCE=500 (>=500)"
#endif
#endif
enum {
SA_IGNORE,
SA_DEFAULT,
SA_HANDLER,
};
enum {
SF_ONCE,
SF_KILL,
};
struct my_sig_act {
int signo;
char* signame;
int sigact;
int flags;
};
static struct my_sig_act def_sig_act[] = {
{SIGHUP, "SIGHUP", SA_HANDLER, SF_KILL,},
{SIGINT, "SIGINT", SA_HANDLER, SF_KILL,},
{SIGQUIT, "SIGQUIT", SA_HANDLER, SF_KILL,},
{SIGILL, "SIGILL", SA_HANDLER, SF_KILL,},
{SIGTRAP, "SIGTRAP", SA_HANDLER, SF_KILL,},
{SIGABRT, "SIGABRT", SA_HANDLER, SF_KILL,},
{SIGIOT, "SIGIOT", SA_HANDLER, 0,},
{SIGBUS, "SIGBUS", SA_HANDLER, SF_KILL,},
{SIGFPE, "SIGFPE", SA_HANDLER, SF_KILL,},
{SIGKILL, "SIGKILL", SA_HANDLER, SF_KILL,},
{SIGUSR1, "SIGUSR1", SA_HANDLER, 0,},
{SIGSEGV, "SIGSEGV", SA_HANDLER, SF_KILL,},
{SIGUSR2, "SIGUSR2", SA_HANDLER, 0,},
{SIGPIPE, "SIGPIPE", SA_HANDLER, SF_KILL,},
{SIGALRM, "SIGALRM", SA_HANDLER, 0,},
{SIGTERM, "SIGTERM", SA_HANDLER, SF_KILL,},
{SIGSTKFLT, "SIGSTKFLT", SA_HANDLER, 0,},
{SIGCLD, "SIGCLD", SA_DEFAULT, SF_KILL,},
{SIGCHLD, "SIGCHLD", SA_DEFAULT, SF_KILL,},
{SIGCONT, "SIGCONT", SA_HANDLER, SF_KILL,},
{SIGSTOP, "SIGSTOP", SA_HANDLER, SF_KILL,},
{SIGTSTP, "SIGTSTP", SA_HANDLER, SF_KILL,},
{SIGTTIN, "SIGTTIN", SA_HANDLER, SF_KILL,},
{SIGTTOU, "SIGTTOU", SA_HANDLER, SF_KILL,},
{SIGURG, "SIGURG", SA_HANDLER, SF_KILL,},
{SIGXCPU, "SIGXCPU", SA_HANDLER, SF_KILL,},
{SIGXFSZ, "SIGXFSZ", SA_HANDLER, SF_KILL,},
{SIGVTALRM, "SIGVTALRM", SA_HANDLER, SF_KILL,},
{SIGPROF, "SIGPROF", SA_HANDLER, SF_KILL,},
{SIGWINCH, "SIGWINCH", SA_HANDLER, SF_KILL,},
{SIGPOLL, "SIGPOLL", SA_HANDLER, SF_KILL,},
{SIGIO, "SIGIO", SA_HANDLER, SF_KILL,},
{SIGPWR, "SIGPWR", SA_HANDLER, SF_KILL,},
{SIGSYS, "SIGSYS", SA_HANDLER, SF_KILL,},
{SIGUNUSED, "SIGUNUSED", SA_HANDLER, 0,},
{0, 0, 0, 0,},
};
static void my_sigchld_action(int signo, siginfo_t* info, void* p)
{
int status;
if(signo == SIGCHLD) {
int pid;
while(1) {
pid = waitpid(0, &status, WNOHANG);
if(pid < 0) {
perror("waitpid");
break;
}
if(WIFEXITED(status)) {
printf("child (%d) exited.\n", pid);
break;
} else {
printf("status = %d\n", status);
}
}
}
}
static void my_action(int signo, siginfo_t* info, void* p)
{
pid_t self = getpid();
fprintf(stderr, "%s: signo: %d, pid: %d, ppid: %d, pgid: %d, sid: %d\n", __func__,
signo, self, getppid(), getpgid(self), getsid(0));
}
static void def_sighandler(void)
{
struct my_sig_act* a = def_sig_act;
struct sigaction sa;
sa.sa_handler = NULL;
sa.sa_sigaction = my_action;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO | SA_RESTART;
while(a->signo) {
if(a->sigact == SA_HANDLER) {
if(a->flags & SF_ONCE) {
sa.sa_flags |= SA_RESETHAND;
}
sigaction(a->signo, &sa, NULL);
}
++a;
}
}
static void def_sigchld(void)
{
struct sigaction sa;
sa.sa_handler = NULL;
sa.sa_sigaction = my_sigchld_action;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO | SA_RESTART;
sigaction(SIGCHLD, &sa, NULL);
}
static void do_child(void)
{
pid_t pids[2];
pid_t sid, self;
int i, fd;
int nb = 2;
sid = setsid();
self = getpid();
def_sighandler();
def_sigchld();
for(i = 0; i <= 2; i++) {
close(i);
}
/* open a real terminal device */
fd = open("/dev/ttyS0", O_RDONLY);
assert(fd == 0);
fd = open("/tmp/stdout.log", O_WRONLY | O_CREAT, 0644);
assert(fd == 1);
fd = open("/tmp/stderr.log", O_WRONLY | O_CREAT, 0644);
assert(fd == 2);
printf("child:pid = %d, session id: %d, pgid: %d\n",
self, sid, getpgid(self));
for (i = 0; i < nb; i++) {
pids[i] = fork();
if(pids[i] < 0) {
perror("fork2: ");
exit(1);
} else if (pids[i] == 0) {
while(1) {
printf("%s: child, pid = %d, ppid = %d\n",
__func__, getpid(), getppid());
sleep(5);
}
} else {
printf("%s: parent, pid = %d, ppid = %d\n",
__func__, pids[i], getppid());
}
}
while(1) {
printf("%s: \n", __func__);
sleep(1);
}
}
int main(int argc, char* argv[])
{
pid_t pid;
def_sighandler();
def_sigchld();
pid = fork();
if (pid < 0) {
perror("fork:");
exit(1);
} else if (pid == 0) {
do_child();
} else {
exit(0);
}
return 0;
}
|