标签:守护进程 inetd syslog函数 syslogd
守护进程是在后台运行并独立于所有终端控制的进程。守护进程没有控制终端源于它们通常是由系统初始化脚本启动,但是也有可能从某个终端由用户在 shell 提示符下键入命令行启动,这种启动方式的守护进程必须亲自脱离与控制终端的关联,从而避免与作业控制、终端会话管理、终端产生信号等发生任何不期望的交互,也可以避免在后台运行的守护进程非预期地输出到终端。有关作业控制、终端控制的内容可参考文章《作业控制、终端控制 和 守护进程》
由于守护进程没有控制终端,当守护进程出错时,必须通过某种输出函数输出错误消息,而不能使用标准输出函数。syslog 函数是输出这些消息的标准方法,它把这些消息发送给 syslogd 守护进程。
Unix 系统中的 syslogd 守护进程通常由某个系统初始化脚本启动,而且在系统工作期间一直运行。其启动步骤如下:
以下是守护进程产生日志消息的方式:
syslog 函数
由于守护进程没有控制终端,所以不能把错误日志消息 fprintf 到 stderr 上,但是可以使用 syslog 函数进行处理日志消息。其定义如下:
/* 守护进程 */ #include <syslog.h> void syslog(int priority, const char *message, ...); void openlog(const char *ident, int options, int facility); void closelog(void); /* * 说明: * 函数openlog和closelog是可选的,若不调用openlog函数,则在第一次调用syslog函数时,会自动调用openlog函数; * openlog可以在首次调用syslog前调用,closelog可以在应用进程不再需要发送日志消息时调用; * ident参数是一个由syslog冠于每个日志消息之前的字符串,通常是程序名; * ****************************************************************** * options参数由以下值一个或多个逻辑“或”组成: * ****************************************************************** * (1)LOG_CONS 若无法发送到syslogd守护进程,则将消息登记到控制台 * (2)LOG_NDELAY 不延迟打开,立即创建套接字 * (3)LOG_PERROR 既发送到syslogd守护进程,又登记到标准错误输出 * (4)LOG_PID 每条日志消息都登记进程ID * (5)LOG_NOWAIT 不等待在消息记入日志过程中可能已创建的子进程 * (6)LOG_ODELAY 在记录第一条消息之前延迟打开至syslogd守护进程的连接 ********************************************************************* * 参数 priority是级别(level)和设施(facility)两者的组合; * level和facility的目的在于允许在/dev/syslog.conf文件中统一配置来自同一个给定设施的所有消息, * 或统一配置具有相同级别的所有消息; * ********************************************************* * 其中level取值如下:(注:以下按优先级从高到低) * ********************************************************* * LOG_EMERG 系统不可使用 * LOG_ALERT 必须立即采取修复 * LOG_CRIT 临界条件 * LOG_ERR 出错条件 * LOG_WARNING 警告条件 * LOG_NOTICE 正常然而重要的条件(默认值) * LOG_INFO 通告消息 * LOG_DEBUG 调试级消息 *********************************************************** *********************************************************** * facility取值如下: * ********************************************************* * LOG_AUTH 安全/授权消息 * LOG_AUTHPRIV 安全/授权消息(私用) * LOG_CRON cron守护进程 * LOG_DAEMON 系统守护进程 * LOG_FTP FTP守护进程 * LOG_KERN 内核产生的消息 * LOG_LOCAL0 保留由本地使用 * LOG_LOCAL1 保留由本地使用 * LOG_LOCAL2 保留由本地使用 * LOG_LOCAL3 保留由本地使用 * LOG_LOCAL4 保留由本地使用 * LOG_LOCAL5 保留由本地使用 * LOG_LOCAL6 保留由本地使用 * LOG_LOCAL7 保留由本地使用 * LOG_LPR 行打印机系统 * LOG_MALL 邮件系统 * LOG_NEWS 网络新闻系统 * LOG_SYSLOG 由syslogd内部产生的消息 * LOG_USER 任意用户级消息(默认) * LOG_UUCP UUCP系统 * ********************************************************* */
当 openlog 函数被应用程序调用时,通常并不立即创建 Unix 域套接字,直到首次调用 syslog 函数时套接字才被创建并打开。但是 openlog 函数可以指定选项 LOG_NDELAY 要求调用 openlog 函数时立即创建套接字。
守护进程编程步骤
1. 创建子进程,父进程退出
?所有工作在子进程中进行
?形式上脱离了控制终端
2. 在子进程中创建新会话
?setsid()函数
?使子进程完全独立出来,脱离控制
3. 改变当前目录为根目录
?chdir()函数
?防止占用可卸载的文件系统
?也可以换成其它路径
4. 重设文件权限掩码
?umask()函数
?防止继承的文件创建屏蔽字拒绝某些权限
?增加守护进程灵活性
5. 关闭文件描述符
?继承的打开文件不会用到,浪费系统资源,无法卸载
?返回所在进程的文件描述符表的项数,即该进程打开的文件数目
守护进程创建的流程图如下:
/* 初始化守护进程 */ #include <unistd.h> #include <stdlib.h> #include <sys/stat.h> #include <syslog.h> #include <fcntl.h> #include <signal.h> #include <sys/resource.h> extern void err_quit(const char *,...); void daemonize(const char *pname, int facility) { int i, fd0, fd1, fd2; pid_t pid; struct rlimit rl; struct sigaction sa; umask(0); /* 限制进程资源,参数RLIMIT_NOFILE指定进程不能超过资源最大数 */ if(getrlimit(RLIMIT_NOFILE, &rl) < 0) err_quit("%s: can't get file limit", pname); /* 创建子进程*/ if((pid =fork()) < 0) err_quit("%s: can't fork", pname); else if(pid != 0) exit(0);/* 父进程退出 */ setsid();/* 创建会话 */ 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", pname); else if(pid != 0) exit(0); /* 把工作目录改为根目录 */ if(chdir("/") < 0) err_quit("%s: can't change directory to /"); if(rl.rlim_max == RLIM_INFINITY) rl.rlim_max = 1024; /* 关闭所有打开的描述符 */ for(i = 0; i < (int)rl.rlim_max; i++) close(i); fd0 = open("/dev/null", O_RDWR); fd1 = dup(0); fd2 = dup(0); /* 使用syslogd处理错误 */ openlog(pname, LOG_CONS, facility); if(fd0 != 0 || fd1 != 1 || fd2 != 2) { syslog(LOG_ERR, "unexpectrd file descriptors %d %d %d", fd0, fd1, fd2); exit(1); } }
#include "unp.h" #include <syslog.h> extern int daemon_proc; /* defined in error.c */ void daemon_inetd(const char *pname, int facility) { daemon_proc = 1; /* for our err_XXX() functions */ openlog(pname, LOG_PID, facility); }
标签:守护进程 inetd syslog函数 syslogd
原文地址:http://blog.csdn.net/chenhanzhun/article/details/41946459