现在的位置: 首页 > 综合 > 正文

编写守护进程

2013年10月05日 ⁄ 综合 ⁄ 共 3668字 ⁄ 字号 评论关闭

[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

抱歉!评论已关闭.