int daemonize(int dump_core)
{
int status;
pid_t pid, sid;
int fd;
pid = fork();
if ((pid = fork()) == -1) {//means error occur
fprintf(stderr, "fork failed:%s", strerror(errno));
return -1;
}else if (pid > 0){//means this is the parent process, they can quit at once
_exit(0);
}
//means this is the child process
/* 1st child continues and becomes the session leader */
//fork twice to avoid zombie process
sid = setsid();//creates a session and sets the process group ID
if (sid < 0) {
fprintf(stderr, "setsid() failed:%s", strerror(errno));
return -1;
}
if (signal(SIGHUP, SIG_IGN) == SIG_ERR) {
fprintf(stderr, "signal(SIGHUP, SIG_IGN) failed: %s", strerror(errno));
return -1;
}
///<use fork twice to avoid zombie process
pid = fork();
if ((pid = fork()) == -1) {//means error occur
fprintf(stderr, "fork failed:%s", strerror(errno));
return -1;
}else if (pid > 0){//means this is the 1st child process, they can quit at once
_exit(0);
}
/* 2nd child continues */
/* change working directory */
if (dump_core == 0) {
status = chdir("/");
if (status < 0) {
fprintf(stderr, "chdir(\"/\") failed: %s", strerror(errno));
return -1;
}
}
/* clear file mode creation mask */
umask(0);
/* redirect stdin, stdout and stderr to "/dev/null" */
fd = open("/dev/null", O_RDWR);
if (fd < 0) {
fprintf(stderr,"open(\"/dev/null\") failed: %s", strerror(errno));
return NC_ERROR;
}
status = dup2(fd, STDIN_FILENO);
if (status < 0) {
fprintf(stderr,"dup2(%d, STDIN) failed: %s", fd, strerror(errno));
close(fd);
return NC_ERROR;
}
status = dup2(fd, STDOUT_FILENO);
if (status < 0) {
fprintf(stderr,"dup2(%d, STDOUT) failed: %s", fd, strerror(errno));
close(fd);
return NC_ERROR;
}
status = dup2(fd, STDERR_FILENO);
if (status < 0) {
fprintf(stderr,"dup2(%d, STDERR) failed: %s", fd, strerror(errno));
close(fd);
return NC_ERROR;
}
if (fd > STDERR_FILENO) {
status = close(fd);
if (status < 0) {
fprintf(stderr,"close(%d) failed: %s", fd, strerror(errno));
return NC_ERROR;
}
}
return NC_OK;
}
需要遵循几大原则:
- 设置mask,避免出现文件权限的问题
- fork两次,避免出现僵尸进程(父进程终止可以让shell结束退出)
- 使用set_id() 生成新的会话,并且将fork出的子进程作为groupid
- 重新设定工作目录
- 将标准输出重定向到/dev/null