程序清单 13-1 初始化一个守护进程
/**
* 程序清单 13-1 初始化一个守护进程 P343
* zy:
* 书上解释的很清楚了,我只是敲了一遍代码
*/
#include "apue.h"
#include <syslog.h> //功能:记录至系统记录。
#include <fcntl.h> //File Control Operations
#include <sys/resource.h> //sys/resource.h - definitions for XSI resource operations
void daemonize(const char *cmd){
int i,fd0,fd1,fd2;
pid_t pid;
struct rlimit rl;
struct sigaction sa;
/**
* 清楚文件创建的屏蔽字
*/
umask(0);
/**
* 拿到最大的文件描述符
*/
if(getrlimit(RLIMIT_NOFILE,&rl)<0){
err_quit("%s,can't get file limit",cmd);
}
/**
* 成为会话首进程,并且没有控制TTY的权利
*/
if((pid=fork())<0){
err_quit("%s,can't fork",cmd);
}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",cmd);
}else if(pid!=0){//父进程退出
exit(0);
}
/**
* 改变现在工作目录
*/
if(cddir("/")<0){
err_quit("can't change directory");
}
/**
* 关闭所有的文件标识符
*/
if(rl.rlim_max==RLIM_INFINITY){
rl.rlim_max=1024;//很奇怪,为什么要这样做
}
for(i=0;i<rl.rlim_max;i++){
close(i);
}
/**
* 将文件标识符0、1、2都输出至/dev/null
*/
fd0=open("/dev/null",O_RDWR);
fd1=dup(0);
fd2=dup(0);
/**
* 初始化log文件
*/
openlog(cmd,LOG_CONS,LOG_DAEMON); //P346 Open connection to system logger
if(fd0!=0||fd1!=1||fd2!=2){ //因为上面把所有的FD都关了,所以才会是这个样子
syslog(LOG_ERR,"unexpected file descriptors %d %d %d",fd0,fd1,fd2);
exit(1);
}
}
程序清单 13-2 保证只运行某个守护进程的一个副本
/**
* 程序清单 13-2 保证只运行某个守护进程的一个副本 P349
* zy:
* 没什么特别要说的了
*
#include <unistd.h> //对于类 Unix 系统,unistd.h 中所定义的接口通常都是大量针对系统调用的封装
//(英语:wrapper functions),如 fork、pipe 以及
//各种 I/O 原语(read、write、close 等等)
#include <stdlib.h> //标准库函数的定义:定义了五种类型、一些宏和通用工具函数
#include <fcntl.h> //File Control Operations
#include <syslog.h> //功能:记录至系统记录。
#include <string.h>
#include <errno.h>
#include <stdio.h>
#include <sys/stat.h>
#define LOCKFILE "/var/run/daemon.pid"
#define LOCKMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
extern int lockfile(int); //这个函数在14.3节中会实现
int already_running(void){
int fd;
char buf[16];
fd=open(LOCKFILE,O_RDWR|O_CREAT,LOCKMODE);
if(fd<0){
syslog(LOG_ERR,"can't open %s:%s",LOCKFILE,strerror(errno));
exit(1);
}
if(lockfile(fd)<0){
if(errno==EACCES||errno==EAGAIN){
close(fd);
return 1;
}
syslog(LOG_ERR,"can't lock %s:%s",LOCKFILE,strerror(errno));
exit(1);
}
ftruncate(fd,0);
sprintf(buf,"%ld",(long)getpid());
write(fd,buf,strlen(buf)+1);
return 0;
}
程序清单 13-3 守护进程重读配置文件
/**
* 程序清单 13-3 守护进程重读配置文件 P350
* zy:
* 这是使用了多线程和sigwait的方式
*/
#include <syslog.h> //功能:记录至系统记录。
#include <pthread.h>
#include "apue.h"
sigset_t mask;
extern int already_running(void);
void reread(void){
/*....*/
}
void *thr_fn(void *arg){
int err,signo;
err=sigwait(&mask,&signo);
for(;;){
if(err!=0){
syslog(LOG_ERR,"sigwait failed");
exit(1);
}
switch (signo) {
case SIGHUP:
syslog(LOG_INFO,"RE-reading configuration file");
reread();
break;
case SIGTERM:
syslog(LOG_INFO,"got SIGTERM; exiting");
break;
default:
syslog(LOG_INFO,"unexpected signal %d \n",signo);
break;
}
}
return 0;
}
int main(int argc,char *argv[]){
int err;
pthread_t tid;
char *cmd;
struct sigaction sa;
//下面这个if就是想拿到我们给守护线程取得名字
if((cmd=strrchr(argv[0],'/'))==NULL){//查找一个字符c在另一个字符串str中末次出现的位置
cmd=argv[0];
}else{
cmd++;
}
daemonize(cmd);
/*
* 确定其只有一个在运行
*
*/
if(already_running()){
syslog(LOG_ERR,"daemon already running");
exit(1);
}
/**
* 恢复SIGHUP 默认,堵塞其他信号
*/
sa.sa_handler=SIG_DFL;
sigemptyset(&sa.sa_mask);
sa.sa_flags=0;
if(sigaction(SIGHUP,&sa,NULL)<0){
err_quit("%s:can't restore SIGHUP default");
}
sigfillset(&mask);
if((err=pthread_sigmask(SIG_BLOCK,&mask,NULL))!=0){
err_exit(err,"SIG_BLOCK error");
}
/**
* 有一个线程负责处理SIGHUP和SIGTERM
* 但是实际上他也接受所有的信号
*/
err=pthread_create(&tid,NULL,thr_fn,0);
if(err!=0){
err_exit(err,"can't create thread");
}
/**
* 处理其他的对守护线程的初始化
*/
exit(0);
}
程序清单 13-4 守护进程重读配置文件的另一种方式
/**
* 程序清单 13-4 守护进程重读配置文件的另一种方式 P352
* zy:
* 不用多线程也可以完成
*/
#include <syslog.h> //功能:记录至系统记录。
#include <errno.h>
#include <error.c>
#include "apue.h"
extern int already_running(void);
void reread(void){
/*....*/
}
void sigterm(int signo){
syslog(LOG_INFO,"got SIGTERM; exiting");
exit(0);
}
void sighup(int signo){
syslog(LOG_INFO,"Re-reading configuration file");
reread();
}
void *thr_fn(void *arg){
int err,signo;
err=sigwait(&mask,&signo);
for(;;){
if(err!=0){
syslog(LOG_ERR,"sigwait failed");
exit(1);
}
switch (signo) {
case SIGHUP:
syslog(LOG_INFO,"RE-reading configuration file");
reread();
break;
case SIGTERM:
syslog(LOG_INFO,"got SIGTERM; exiting");
break;
default:
syslog(LOG_INFO,"unexpected signal %d \n",signo);
break;
}
}
return 0;
}
int main(int argc,char *argv[]){
char *cmd;
struct sigaction sa;
//下面这个if就是想拿到我们给守护线程取得名字
if((cmd=strrchr(argv[0],'/'))==NULL){//查找一个字符c在另一个字符串str中末次出现的位置
cmd=argv[0];
}else{
cmd++;
}
daemonize(cmd);
/*
* 确定其只有一个在运行
*/
if(already_running()){
syslog(LOG_ERR,"daemon already running");
exit(1);
}
sa.sa_handler=sigterm;
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask,SIGHUP); //处理SIGTERM的时候会堵塞这个信号SIGHUP
sa.sa_flags=0;
if(sigaction(SIGTERM,&sa,NULL)<0){
syslog(LOG_ERR,"can't catch SIGHUP:%s",strerror(errno));
exit(1);
}
sa.sa_handler=sighup;
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask,SIGTERM); //处理SIGTERM的时候会堵塞这个信号SIGHUP
sa.sa_flags=0;
if(sigaction(SIGHUP,&sa,NULL)<0){
syslog(LOG_ERR,"can't catch SIGHUP:%s",strerror(errno));
exit(1);
}
/**
* 其他代码
*/
exit(0);
}