P375
想要初始化为守护进程的程序调用daemonize函数
#include
2 #include
3 #include
4 #include
5
6 void daemonize(const char *cmd)
7 {
8 int i,fd0,fd1,fd2;
9 pid_t pid;
10 struct rlimit rl;
11 struct sigaction sa;
12
13 umask(0);
14 if(getrlimit(RLIMIT_NOFILE,&rl) < 0)
15 err_quit("%s: can't get file limit",cmd);
16
17 if((pid = fork()) < 0)
18 err_quit("%s: can't fork",cmd);
19 else if(pid != 0)
20 exit(0);
21
22 setsid();
sa.sa_handler = SIG_IGN;
25 sigemptyset(&sa.sa_mask);
26 sa.sa_flags = 0;
27 if(sigaction(SIGHUP,&sa,NULL) < 0)
28 err_quit("%s: can't ignore SIGHUP",cmd);
29
30 if((pid = fork()) < 0)
31 err_quit("%s : can't fork",cmd);
32 else if(pid != 0)
33 exit(0);
34
35 if(chdir("/") < 0)
36 err_quit("%s : can't change current directory to /",cmd);
37
38 if(rl.rlim_max == RLIM_INFINITY)
39 rl.rlim_max = 1024;
>* 40 for(i = 0; i < rl.rlim_max; i++)
41 close(i);
42
43 fd0 = open("/dev/null", O_RDWR);
44 fd1 = dup(0);
45 fd2 = dup(0);
46
47 openlog(cmd,LOG_CONS,LOG_DAEMON);
48 if(fd0 != 0 || fd1 != 1 || fd2 != 2){
49 syslog(LOG_ERR,"unexcepted file descriptors %d %d %d", fd0,fd1,fd2);
50 exit(1);
51 }
52 syslog(LOG_INFO,"Daemonize is running........"); //添加的输出打印,cat /var/log/syslog | tail -10 可以看到输出的打印
53 }
P381
单实例守护进程—通过文件/记录锁机制,保证一个守护进程只有一个副本在运行
#include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #include
9
10 #define LOCKFILE "/var/run/daemon.pid"
11 #define LOCKMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
12
13 int lockfile(int);
14
15 int already_running(void)
16 {
17 int fd;
18 char buf[16];
19
20 fd = open(LOCKFILE,O_RDWR|O_CREAT,LOCKMODE);
21 if(fd < 0){
22 syslog(LOG_ERR,"can't open %s: %s",LOCKFILE,strerror(errno)) ;
23 exit(1);
24 }
25 if(lockfile(fd) < 0){
26 if(errno == EACCES || errno == EAGAIN){
27 close(fd);
28 return (1);
29 }
30 syslog(LOG_ERR,"can't lock %s: %s ",LOCKFILE,strerror(errno));
31 exit(1);
32 }
ftruncate(fd,0);
35 sprintf(buf,"%ld",(long)getpid());
36 write(fd, buf, strlen(buf)+1);
37 return (0);
38 }
39
40 int lockfile(int fd)
41 {
42 struct flock fl;
43 fl.l_type = F_WRLCK;
44 fl.l_start = 0;
45 fl.l_whence = SEEK_SET;
46 fl.l_len = 0;
47 return (fcntl(fd,F_SETLK,&fl));
48 }
P382 守护进程重读其配置的一种方法
#include
2 #include
3 #include
4
5 sigset_t mask;
6 extern int already_running(void);
7 extern void daemonize(const char *);
8 void reread(void);
9 void *thr_func(void *);
10
>* 11 int main(int argc,char **argv)
12 {
13 int err;
14 pthread_t tid;
15 char *cmd;
16 struct sigaction sa;
17
18 if((cmd = strrchr(argv[0],'/')) == NULL)
19 cmd = argv[0];
20 else
21 cmd++;
22
23 daemonize(cmd);
24 if(already_running()){
25 syslog(LOG_ERR,"daemon already running");
26 exit(1);
27 }
28
29 sa.sa_handler = SIG_DFL;
30 sigemptyset(&sa.sa_mask);
31 sa.sa_flags = 0;
32 if(sigaction(SIGHUP,&sa,NULL) < 0)
33 err_quit("%s: can't restore SIGHUP default",cmd);
34 sigfillset(&mask);
35 if((err = pthread_sigmask(SIG_BLOCK,&mask,NULL)) != 0)
36 err_exit(err,"SIG_BLOCK ERROR");
37
38 err = pthread_create(&tid,NULL,thr_func,(void *)0);
39 if(err != 0)
40 err_exit(err,"can't create thread");
41
42 syslog(LOG_INFO,"waiting...."); //标记输出打印
43 pause(); //暂停守护进程,使其挂起
44 /*exit(0);*/
45 }
46
>* 47 void *thr_func(void *arg)
48 {
49 int err,signo;
50 while(1){
51 err = sigwait(&mask,&signo);
52 if(err != 0){
53 syslog(LOG_ERR,"sigwait failed");
54 exit(1);
55 }
switch(signo){
58 case SIGHUP :
59 {
60 syslog(LOG_INFO,"Re-reading configuration file");
61 reread();
62 break;
63 }
64 case SIGTERM :
65 {
66 syslog(LOG_INFO,"got SIGTERM exiting");
67 exit(0);
68 }
69 default :
70 syslog(LOG_INFO,"unexcepted signal %d\n",signo);
71 }
72 }
73 return(0);
74 }
75
76 void reread(void)
77 {
78 //
79 }
注意:
1. main中,调用daemonize函数使其成为守护进程,然后调用 already_running函数使其只有一个守护进程副本运行,接着创建一个线程用于处理信号(替代信号处理函数),最后调用pause 函数(P269,pause函数使其调用进程挂起,直至捕捉到一个信号,只有执行了一个信号处理程序并从其返回时,pause才返回),守护进程被挂起(因为此处使用线程处理信号代替信号处理函数,守护进程一直被挂起,什么时候退出呢?当发送信号SIGTERM时,因为线程处理SIGTERM信号,它会调用exit(0),exit不仅结束线程,进程也会跟着结束);
运行结果:
从上图运行结果可以看到,没有产生守护进程,原因是什么呢?我们看一下syslog文件
从log文件中可以看到,守护进程初始化成功了,但是当运行already_running函数中的open创建/var/run/daemon.pid文件时,守护进程的权限不够,无法open创建文件,导致守护进程退出结束;
接下来我们以root运行
运行成功:守护进程为图中标出
看一下log:
看一下/var/run/daemon.pid文件,中的pid正是9202
我们给其守护进程发送信号,看log:
可见运行正确
只要我们不给守护进程发送SIGTERM信号,则守护进程永远挂起,线程一直处理信号