分类:
2008-12-25 19:08:01
13.3 coding rules
建立一个daemon的方法:
其实主要就是让他实现上面描述的特点:
1.设置进程的umask为0。这样当daemon要创建一些指定了permission mask的文件的时候,最终生成的文件的权限不会受到dameon进程的mask的影响
2. fork 然后parent exit,这是为了
让这个进程不是一个process group leader,这是调用setsid的前提.
3. setsid, 它会有如下结果
该进程会成为一个session leader, 会成为一个proces group leader,会不再拥有controlling terminal。(一个session leader 第一次打开的terminal 会被默认当作是session 的controlling terminal,当然如果你没有设置一些选项的话,如O_NOCTTY。)
4.降CWD目录更改为root目录
防止长期运行的daemon进程会影响到一些文件系统的umount。(例如如果你设置的目录恰好在一个要被umount的文件系统的路径下)
5.关闭一些不必要的file descriptors
6. 将0,1,2
file descriptor可以重定向到比如/dev/null
下面是一个例子:
#include "apue.h"
#include
#include
#include
void
daemonize(const char *cmd)
{
int i, fd0, fd1, fd2;
pid_t pid;
struct rlimit rl;
struct sigaction sa;
/*
* Clear file creation mask.
*/
umask(0);
/*
* Get maximum number of file descriptors.
*/
if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
err_quit("%s: can't get file limit", cmd);
/*
* Become a session leader to lose controlling TTY.
*/
if ((pid = fork()) < 0)
err_quit("%s: can't fork", cmd);
else if (pid != 0) /* parent */
exit(0);
setsid();
/*
* Ensure future opens won't allocate controlling TTYs.
*/
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGHUP, &sa, NULL) < 0)
err_quit("%s: can't ignore SIGHUP");
if ((pid = fork()) < 0)
err_quit("%s: can't fork", cmd);
else if (pid != 0) /* parent */
exit(0);
/*
* Change the current working directory to the root so
* we won't prevent file systems from being unmounted.
*/
if (chdir("/") < 0)
err_quit("%s: can't change directory to /");
/*
* Close all open file descriptors.
*/
if (rl.rlim_max == RLIM_INFINITY)
rl.rlim_max = 1024;
for (i = 0; i < rl.rlim_max; i++)
close(i);
/*
* Attach file descriptors 0, 1, and 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 descriptors %d %d %d",
fd0, fd1, fd2);
exit(1);
}
}
上面代码中,关于fd0,fd1,fd2就是将0,1,2给重定向了,为什么这么说,是因为,你在上面已经将所有的descriptor给关闭了,那么你次打开文件的时候,会默认的从0开始分配descriptor。可以测试一下。注意,在你测试的时候,由于你的1已经不对应标准输出,所以不能再用printf之类的输出了,我使用的是将结果写入一个文件。