Linux守护进程
redis版:
void daemonize(void) {
int fd;
if (fork() != 0) exit(0); /* parent exits */
setsid(); /* create a new session */
/* Every output goes to /dev/null. If Redis is daemonized but
* the 'logfile' is set to 'stdout' in the configuration file
* it will not log at all. */
if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
if (fd > STDERR_FILENO) close(fd);
}
}
memcached版:
int daemonize(int nochdir, int noclose)
{
int fd;
switch (fork()) {
case -1:
return (-1);
case 0:
break;
default:
_exit(EXIT_SUCCESS);
}
if (setsid() == -1)
return (-1);
if (nochdir == 0) {
if(chdir("/") != 0) {
perror("chdir");
return (-1);
}
}
if (noclose == 0 && (fd = open("/dev/null", O_RDWR, 0)) != -1) {
if(dup2(fd, STDIN_FILENO) < 0) {
perror("dup2 stdin");
return (-1);
}
if(dup2(fd, STDOUT_FILENO) < 0) {
perror("dup2 stdout");
return (-1);
}
if(dup2(fd, STDERR_FILENO) < 0) {
perror("dup2 stderr");
return (-1);
}
if (fd > STDERR_FILENO) {
if(close(fd) < 0) {
perror("close");
return (-1);
}
}
}
return (0);
}
lighttpd版:
#ifdef HAVE_FORK
static void daemonize(void) {
#ifdef SIGTTOU
signal(SIGTTOU, SIG_IGN);
#endif
#ifdef SIGTTIN
signal(SIGTTIN, SIG_IGN);
#endif
#ifdef SIGTSTP
signal(SIGTSTP, SIG_IGN);
#endif
if (0 != fork()) exit(0);
if (-1 == setsid()) exit(0);
signal(SIGHUP, SIG_IGN);
if (0 != fork()) exit(0);
if (0 != chdir("/")) exit(0);
}
#endif
nginx版:
ngx_int_t
ngx_daemon(ngx_log_t *log)
{
int fd;
switch (fork()) {
case -1:
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "fork() failed");
return NGX_ERROR;
case 0:
break;
default:
exit(0);
}
ngx_pid = ngx_getpid();
if (setsid() == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "setsid() failed");
return NGX_ERROR;
}
umask(0);
fd = open("/dev/null", O_RDWR);
if (fd == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
"open(\"/dev/null\") failed");
return NGX_ERROR;
}
if (dup2(fd, STDIN_FILENO) == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDIN) failed");
return NGX_ERROR;
}
if (dup2(fd, STDOUT_FILENO) == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDOUT) failed");
return NGX_ERROR;
}
#if 0
if (dup2(fd, STDERR_FILENO) == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "dup2(STDERR) failed");
return NGX_ERROR;
}
#endif
if (fd > STDERR_FILENO) {
if (close(fd) == -1) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, "close() failed");
return NGX_ERROR;
}
}
return NGX_OK;
}
注释版:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
int daemonize(void)
{
int fd;
switch(fork()) {
case -1:
return (-1);
case 0:
break;
default:
//将父进程结束,让子进程变成真正的孤儿进程,并被init进程接管
exit(0);
}
//子进程成为新的会话组长和新的进程组长,并与原来的登录会话和进程组脱离
setsid();
if ((fd = open("daemon.log", O_CREAT|O_RDWR|O_APPEND, 0)) != -1) {
//dup2(int oldhandle, int newhandle)复制文件句柄
dup2(fd, STDIN_FILENO);
dup2(fd, STDOUT_FILENO);
dup2(fd, STDERR_FILENO);
//0,1和2文件句柄分别与标准输入,标准输出,标准错误输出相关联
//所以用户应用程序调用open函数打开文件时,默认都是以3索引为开始句柄
//fd已经由新的句柄代替,关闭fd句柄
if (fd > STDERR_FILENO) (void)close(fd);
}
return 0;
}
int main(int argc, char *argv[])
{
daemonize();
printf("%s\n","hello");
return 0;
}
# cc daemonize.c -o daemonize
# ./daemonize
# ps aux | grep daemonize
参考:
http://blog.linuxphp.org/archives/1476/
http://www.cnblogs.com/xuxm2007/archive/2011/07/29/2121280.html
http://blog.youkuaiyun.com/yyyzlf/article/details/5267954
http://docs.linuxtone.org/ebooks/C&CPP/c/ch34s03.html