daemon_int
摘自 UNP
#include "unp.h"
#include <syslog.h> #define MAXFD 64 extern int daemon_proc; // defined in error.c int daemon_init(const char* pname, int facility)
{
int i;
pid_t pid; if ( (pid = fork()) < )
return -;
else if (pid)
_exit(); // parent terminates // child 1 continue... if (setsid() < ) // become session leader
return -; signal(SIGHUP, SIG_IGN);
if ( (pid = fork()) < )
return -;
else if (pid)
_exit(); // child 1 terminates // child 2 continue... daemon_proc = ; // for err_XXX() functions chdir("/"); // change working directory // close off file descriptors
for (i=; i<MAXFD; ++i)
close(i); // redirect stdin, stdout, and stderr to /dev/null
open("/dev/null", O_RDONLY);
open("/dev/null", O_RDWR);
open("/dev/null", O_RDWR); openlog(pname, LOG_PID, facility); return ; // success
}
fork
13~16 首先调用 fork,然后终止父进程,留下子进程继续运行。如果本进程是从前台作为一个 shell 命令启动的,当父进程终止时,shell 就认为该命令已执行完毕。这样子进程就自动在后台运行。另外,子进程继承了父进程的进程组 ID,不过它有自己的进程 ID。这就保证子进程不是一个进程组的头进程,这是接下去调用 setsid 的必要条件。
setsid
20~21 setsid 是一个 POSIX 函数,用于创建一个新的会话(session)。当前进程变为新会话的会话头进程以及新进程组的进程组头进程,从而不再有控制终端。
忽略 SIGHUP 信号并再次 fork
23~27 忽略 SIGHUP 信号并再次调用 fork。该函数返回时,父进程实际上是上一次调用 fork 产生的子进程,它被终止掉,留下新的子进程继续运行。再次 fork 的目的是确保本守护进程将来即使打开了一个终端设备,也不会自动获得控制终端。当没有控制终端的一个会话头进程打开一个终端设备时(该终端不会是当前某个其他会话的控制终端),该终端自动成为这个会话头进程的控制终端。然而再次调用 fork 之后,我们确保新的子进程不再是一个会话头进程,从而不能自动获得一个控制终端。这里必须忽略 SIGHUP 信号,因为当会话头进程(即首次 fork 产生的子进程)终止时,其会话中的所有进程(即再次 fork 产生的子进程)都收到 SIGHUP 信号。
为错误处理函数设置标识
31 把全局变量 daemon_proc 置为非 0 值。这个外部变量由我们的 err_XXX 函数定义,其值非 0 是在告知它们改为调用 syslog,以取代 fprintf 到标准错误输出。该变量省得我们从头到尾修改程序代码,在服务器不是作为守护进程运行的场合(例如测试服务器程序时)调用某个错误处理函数,在服务器作为守护进程运行的场合调用 syslog。
改变工作目录
33 把工作目录改到根目录,不过有些守护进程另有原因需改到其他目录。举例来说,打印机守护进程可能改到打印机的假脱机处理(spool)目录,因为那里是它做全部工作的地方。要是守护进程产生了某个 core 文件,该文件就存放在当前工作目录中。改变工作目录的另一个理由是,守护进程可能是在某个任意的文件系统中启动,如果仍然在其中,那么该文件系统就无法拆卸(unmounting),除非使用潜在破坏性的强制措施。
关闭所有打开的描述符
36~37 关闭本守护进程从执行它的进程(通常是一个 shell)继承来的所有打开着的描述符。问题是怎样监测正在使用的最大描述符:没有现成的 Unix 函数提供该值。监测当前进程能够打开的最大描述符数目自有办法,然而由于这个限制可以是无限的,这样的监测也变得复杂起来。我们的解决办法是干脆关闭前 64 个描述符,即使其中大部分可能并没有打开。
Solaris 提供了一个名为 closefrom 的函数,可以用于解决守护进程的这个问题。
将 stdin、stdout 和 stderr 重定向到 /dev/null
40~42 打开 /dev/null 作为本守护进程的标准输入、标准输出和标准错误输出。这一点保证这些常用描述符是打开的,针对它们的 read 系统调用返回 0(EOF),write 系统调用则由内核丢弃所写数据。打开这些描述符的理由在于,守护进程调用的那些假设能从标准输入读或者往标准输出或标准错误输出写的库函数将不会因为这些描述符未打开而失败。这种失败是一种隐患。要是一个守护进程未打开这些描述符,却作为服务器打开了与某个客户关联的一个套接字,那么这个套接字很可能占用这些描述符(譬如标准输出或标准错误输出的描述符 1 或 2),这种情况下如果守护进程调用诸如 perror 之类函数,那就会把非预期的数据发送给那个客户。
使用 syslog 处理错误
44 调用 openlog。其中第一个参数来自调用者,通常是程序的名字(譬如 argv[0])。第二个参数指定把进程 ID 加到每个日志消息中。第三个参数同样由调用者指定,其值为图13-2所示的常值之一或为0(如果默认值 LOG_USER 可以接受的话)。
我们指出,既然守护进程在没有控制终端的环境下运行,它绝不会收到来自内核的 SIGHUP 信号。许多守护进程因此把这个信号作为来自系统管理员的一个通知,表示其配置文件已发生改动,守护进程应该重新读入其配置文件。守护进程同样绝不会收到来自内核的 SIGINT 信号和 SIGWINCH 信号,因此这些信号也可以安全地用作系统管理员的通知手段,指示守护进程应该做出反应的某种变动已经发生。
daemon_int的更多相关文章
随机推荐
- HTML5新协议介绍 WebSocket
WebSocket protocol 是HTML5一种新的协议(protocol).它是实现了浏览器与服务器全双工通信(full-duplex). 现在,很多网站为了实现即时通讯(real-time) ...
- 用 PHP-GTK2 做 Win32 GUI 程序
PHP通常是做为服务器端脚本执行,如果告诉你PHP可以编写普通的GUI程序,你应该很感兴趣.下面介绍的PHP-GTK就是PHP的GUI扩展.GTK是一个业界标准的图形库,具有良好的移植性.如果你用过l ...
- Codeforces 665A. Buses Between Cities 模拟
A. Buses Between Cities time limit per test: 1 second memory limit per test: 256 megabytes input: s ...
- jquery判断显示的元素并获取显示元素数据
// 获取显示元素的数据 jQuery(this).find("a:visible").attr("href"); // 多级标签选择器 jQuery(&quo ...
- 2018.09.25 bzoj1856: [Scoi2010]字符串(组合数学)
传送门 如果有n==m的条件就是卡特兰数. 但现在n不一定等于m. 我们可以考虑用求卡特兰数一样的方法来求答案. 我们知道有一种求卡特兰数的方法是转到二维平面求答案. 这道题就可以这样做. 我们将这个 ...
- centos6 mysql 安装与配置
MySQL简介: 由于其体积小.速度快.总体拥有成本低,尤其是开放源码这一特点,许多中小型网站为了降低网站总体拥有成本而选择了MySQL作为网站数据库.MySQL是一个多用户.多线程的关系型数据库管理 ...
- float 为什么不能用== ,或者大于等于,或者小于等于
本文尝试着将以下内容做一个浅显的解释,主要包括浮点数为什么是不精确的,浮点数为什么不能用==和!=直接比较,以及浮点数的比较方法等几个方面.如果那个地方说的不对还请各位看官不吝赐教!欢迎大家评论区讨论 ...
- spring案列——xml配置
一.需要的jar包 spring.jar(官网下载) commons-logging.jar 二.项目结构 三.entity(实体类) package com.team.model; public c ...
- 软件工程 wc.exe 代码统计作业
软件工程 wc.exe 代码统计作业分享 1. Github 项目地址 https://github.com/EdwardLiu-Aurora/WordCount 更好地阅读本文,可点击这里 基本要求 ...
- [php] cookie 跨域共享
<?php // m.hinabian.com class Controller_Cookie extends Hnb_Base_Controller { public function ini ...