创建子进程,父进程退出
编写守护进程第一步,就是要使得进程独立于终端后台运行。为避免终端挂起,将父进程退出,造成程序已经退出的假象,所有后面的工作都在子进程完成,这样控制终端也可以继续执行其他命令,从而在形式上脱离控制终端的控制。
由于父进程先于子进程退出,子进程就变为孤儿进程,并由 init 进程作为其父进程收养。
子进程创建新会话
经过上一步,子进程已经后台运行,然而系统调用 fork 创建子进程,子进程便复制了原父进程的进程控制块(PCB),相应地继承了一些信息,包括会话、进程组、控制终端等信息。尽管父进程已经退出,但子进程的会话、进程组、控制终端的信息没有改变。为使子进程完全摆脱父进程的环境,需要调用 setsid 函数。
/* Daemonize a process */
void goDaemon()
{
int fd;
pid_t pid;
pid = fork();
if (pid < 0) {
merror(FORK_ERROR, errno, strerror(errno));
return;
} else if (pid) {
exit(0);
}
/* Become session leader */
if (setsid() < 0) {
merror(SETSID_ERROR, errno, strerror(errno));
return;
}
/* Fork again */
pid = fork();
if (pid < 0) {
merror(FORK_ERROR, errno, strerror(errno));
return;
} else if (pid) {
exit(0);
}
/* Dup stdin, stdout and stderr to /dev/null */
if ((fd = open("/dev/null", O_RDWR)) >= 0) {
dup2(fd, 0);
dup2(fd, 1);
dup2(fd, 2);
close(fd);
}
/* Go to / */
if (chdir("/") == -1) {
merror(CHDIR_ERROR, "/", errno, strerror(errno));
}
nowDaemon();
}