《APUE:chapter 13 》守护进程测试

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不仅结束线程,进程也会跟着结束);

运行结果:

《APUE:chapter 13 》守护进程测试_第1张图片

从上图运行结果可以看到,没有产生守护进程,原因是什么呢?我们看一下syslog文件
这里写图片描述
从log文件中可以看到,守护进程初始化成功了,但是当运行already_running函数中的open创建/var/run/daemon.pid文件时,守护进程的权限不够,无法open创建文件,导致守护进程退出结束;
接下来我们以root运行

这里写图片描述
运行成功:守护进程为图中标出
看一下log:
这里写图片描述
看一下/var/run/daemon.pid文件,中的pid正是9202
这里写图片描述

我们给其守护进程发送信号,看log:
《APUE:chapter 13 》守护进程测试_第2张图片
可见运行正确
《APUE:chapter 13 》守护进程测试_第3张图片
只要我们不给守护进程发送SIGTERM信号,则守护进程永远挂起,线程一直处理信号

你可能感兴趣的:(linux)