编写守护进程

[1] Clear file creation mask. 
The file mode creation mask that's inherited could be set to deny certain permissions.
If the daemon process is going to create files, it may want to set specific permissions.
For example, if it specifically creates files with group-read and group-write enabled,
a file mode creation mask that turns off either of these permissions would undo its efforts(不起作用).
(processes in the same group may have no permissions to access the file created by the daemon process)

[2] Call fork() and have the parent exit, call setsid() to create a new session.
The child inherits the process group ID of the parent but gets a new process ID, so we're guaranteed that the child is
not a process group leader. This is a prerequisite for the call to setsid().
By calling setsid(), the child process (a)becomes a session leader of a new session, (b) becomes the process group leader
of a new process group, and (c) has no controlling terminal.

[3] Call fork() secondly and have the first child exit.
Some operations may acquire controlling TTYs, but if a process is not a session leader, it has no chance of allocating a controlling terminal.

[4] Change the current working directory to the root directory.
The current working directory inherited from the parent could be on a mounted file system. Since daemons normally exist until the system is rebooted,
if the daemon stays on a mounted file system, that file system cannot be unmounted.

[5] Unneeded file descriptors should be closed.

[6]
Some daemons open file descriptors 0, 1, and 2 to /dev/null so that any library routines that
try to read from standard input or write to standard output or standard error will have no effect.
Since the daemon is not associated with a terminal device, there is nowhere for output to be displayed; nor
is there anywhere to receive input from an interactive user. Even if the daemon was started from an interactive session,
the daemon runs in the background, and the login session can terminate without affecting the daemon.
If other users log in on the same terminal device, we wouldn't want output from the daemon showing up on the terminal,
and the users wouldn't expect their input to be read by the daemon.

[7] (optional)Avoid creating zombie processes.

The method used in the following program may have no effects in some system, you can try other ways to do this.(seehttp://blog.csdn.net/duyiwuer2009/article/details/7964795 )

/**
 * 待完善:
 * 1、防止多次 daemonize
 */
#include	<stdio.h>
#include	<stdlib.h>
#include	<string.h>
#include	<errno.h>
#include	<sys/resource.h>
#include	<sys/stat.h>
#include	<unistd.h>
#include	<fcntl.h>
#include	<syslog.h>
#include	<signal.h>


static void daemonize(const char *cmd)
{
	pid_t				pid;
	struct rlimit 		rl;
	int 				fd0, fd1, fd2;
	int					i;
	struct sigaction	sa;
	
	/* [1] Clear file creation mask */
	umask(0);
	
	/* [2] Become a session leader to lose controlling TTY */
	if( (pid = fork()) < 0 )
	{
		perror("fork error");
		exit(errno);
	}
	else if(pid > 0)	/* parent */
	{
		exit(0);
	}
	setsid();
	
	/* [3] Ensure future opens won't allocate controlling TTYs */
	/* [Q] 此处有些不理解为什么还要处理 SIGHUP 信号,按道理 SIGHUP 信号是永远不可能产生了的 */
	sa.sa_handler = SIG_IGN;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	if(sigaction(SIGHUP, &sa, NULL) < 0)
	{
		perror("sigaction(SIGHUP) error");
		exit(errno);
	}
	if( (pid = fork()) < 0 )
	{
		perror("fork error");
		exit(errno);
	}
	else if(pid > 0)	/* parent */
	{
		exit(0);
	}
	
	/* [4] Change the current working directory to root */
	if(chdir("/") < 0)
	{
		perror("can't change directory to /");
		exit(errno);
	}
	
	/* [5] Close all open file descriptors */
	if(getrlimit(RLIMIT_NOFILE, &rl) < 0)
	{
		perror("getrlimit(RLIMIT_NOFILE)");
		exit(errno);
	}
	if(rl.rlim_max == RLIM_INFINITY)
	{
		rl.rlim_max = 1024;
	}
	for(i = 0; i < rl.rlim_max; i++)
	{
		close(i);
	}


	/* [6] Attach file descriptors 0, 1, 2 to /dev/null */
	fd0 = open("/dev/null", O_RDWR);
	fd1 = dup(0);
	fd2 = dup(0);
	
	/* Initialize the log file */
	openlog(cmd, LOG_CONS, LOG_DAEMON);
	if(fd0 != 0 || fd1 != 1 || fd2 != 2)
	{
		syslog(LOG_ERR, "unexpected file descriptor %d %d %d", fd0, fd1, fd2);
		exit(1);
	}
}


int main(int argc, char *argv[])
{
	daemonize(argv[0]);
	pause();
	return 0;
}


【参考资料】

APUE-2e

杜鹏,李伟. Linux守护进程的编程方法

http://www-theorie.physik.unizh.ch/~dpotter/howto/daemonize

http://www.enderunix.org/docs/eng/daemon.php

http://www.netzmafia.de/skripten/unix/linux-daemon-howto.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值