Linux 下,如何创建守护进程

来源:互联网 发布:自学java看什么视频 编辑:程序博客网 时间:2024/05/16 05:15
最近在看APUE,记录一下如何创建一个完整的守护进程。以备不时查看。(注:RedHat在/var/log/messages文件中,可查看syslog函数记录的日志。)
[cpp] view plaincopy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <sys/time.h>  
  4. #include <sys/resource.h>  
  5. #include <unistd.h>  
  6. #include <sys/types.h>  
  7. #include <sys/stat.h>   
  8. #include <signal.h>  
  9. #include <syslog.h>  
  10. #include <fcntl.h>  
  11. #include <errno.h>  
  12. #include <string.h>  
  13.   
  14. #define LOCKFILE "/var/run/daemon.pid"  
  15. #define LOCKMODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)  
  16.   
  17. void daemonize(const char *);  
  18. void my_err(char *);  
  19. int lockfile(int);  
  20. int already_running(void);  
  21. void reread(void);  
  22. void *thread_fn(void *);  
  23.   
  24. sigset_t mask;  
  25.   
  26. int main(int argc,char *argv[])  
  27. {  
  28.     printf("start\n");  
  29.   
  30.     int err;  
  31.     pthread_t tid;  
  32.     char *cmd;  
  33.     struct sigaction sa;  
  34.   
  35.     if((cmd=strchr(argv[0],'/'))==NULL)   
  36.     {  
  37.         cmd=argv[0];  
  38.     }  
  39.     else      
  40.         cmd++;  
  41.     //Become a daemon  
  42.     daemonize(cmd);  
  43.     //Make sure only one copy of the daemon is running  
  44.     if(already_running()){  
  45.         syslog(LOG_ERR,"daemon already running.");  
  46.         exit(1);  
  47.     }  
  48.     //Restore SIGHUP default and block all signals.  
  49.     sa.sa_handler=SIG_DFL;  
  50.     sigemptyset(&sa.sa_mask);  
  51.     sa.sa_flags=0;  
  52.     if(sigaction(SIGHUP,&sa,NULL)<0)  
  53.     {  
  54.         syslog(LOG_ERR,"sigaction SIGHUP error:%s",strerror(err));  
  55.         exit(1);  
  56.     }  
  57.     sigfillset(&mask);   
  58.     if((err=pthread_sigmask(SIG_BLOCK,&mask,NULL))<0)  
  59.     {  
  60.         syslog(LOG_ERR,"pthread_sigmask error:%s",strerror(err));  
  61.         exit(1);  
  62.     }  
  63.     //Create a thread to handle SIGHUP and SIGTERM    
  64.     err=pthread_create(&tid,NULL,thread_fn,NULL);  
  65.     if(err<0)  
  66.     {  
  67.         syslog(LOG_ERR,"pthread_create error:%s",strerror(err));  
  68.         exit(1);  
  69.     }  
  70.     //Proceed with the rest of daemon  
  71.     sleep(100);  
  72.     printf("end\n");  
  73.     exit(0);  
  74. }  
  75.   
  76. //Reread the configuration file  
  77. void reread(void)  
  78. {  
  79.     //read configuration file...etc  
  80.       
  81. }  
  82.   
  83. void *thread_fn(void *arg)  
  84. {  
  85.     int err,signo;  
  86.     for(;;)  
  87.     {  
  88.         err=sigwait(&mask,&signo);  
  89.         if(err!=0)  
  90.         {  
  91.             syslog(LOG_ERR,"sigwait error:%s",strerror(err));  
  92.             exit(1);  
  93.         }  
  94.         switch(signo)  
  95.         {  
  96.             case SIGHUP:  
  97.                 syslog(LOG_INFO,"reread configuration.");  
  98.                 reread();  
  99.                 break;  
  100.             case SIGTERM:  
  101.                 syslog(LOG_INFO,"got SIGTERM,exiting");   
  102.                 exit(0);  
  103.             default:  
  104.             syslog(LOG_INFO,"unexpected signal:%d",signo);  
  105.         }  
  106.     }  
  107.     return 0;  
  108. }  
  109.   
  110. //Whether a daemon process is already running  
  111. //running: return 1  
  112. //no run:return 0  
  113. int already_running(void)  
  114. {  
  115.     int fd;  
  116.     char buf[16];  
  117.     fd=open(LOCKFILE,O_WRONLY|O_CREAT,LOCKMODE);  
  118.     if(fd<0)  
  119.     {  
  120.         syslog(LOG_ERR,"can't open %s:%s",LOCKFILE,strerror(errno));  
  121.         return 1;  
  122.     }  
  123.     if(lockfile(fd)<0)  
  124.     {  
  125.         if(errno==EACCES || errno==EAGAIN)  
  126.         {  
  127.             close(fd);  
  128.             return 1;  
  129.         }  
  130.         syslog(LOG_ERR,"can't lock %s:%s",LOCKFILE,strerror(errno));  
  131.         return 1;  
  132.     }  
  133.     ftruncate(fd,0);  
  134.     sprintf(buf,"%ld",(long)getpid());  
  135.     write(fd,buf,strlen(buf));  
  136.     return 0;  
  137. }  
  138.   
  139. //Lock the whole file pointed by fd  
  140. int lockfile(int fd)  
  141. {  
  142.     struct flock fl;  
  143.     fl.l_type=F_WRLCK;  
  144.     fl.l_start=0;  
  145.     fl.l_whence=SEEK_SET;  
  146.     fl.l_len=0;  
  147.     int r=fcntl(fd,F_SETLK,&fl);  
  148.     return r;  
  149. }  
  150.   
  151. //Make a process to a daemon.  
  152. void daemonize(const char *cmd)  
  153. {  
  154.     int i,fd0,fd1,fd2;  
  155.     pid_t pid;  
  156.     struct rlimit rl;  
  157.     struct sigaction sa;  
  158.     //Clear file creation mask.  
  159.     umask(0);  
  160.     //Get maximum number of file descriptors.  
  161.     if(getrlimit(RLIMIT_NOFILE,&rl)<0)  
  162.         my_err("getrlimit error");  
  163.     //Become a session leader to lose controlling tty.  
  164.     if((pid=fork())<0)  
  165.         my_err("first fork error");  
  166.     else if(pid!=0) //parent  
  167.         exit(0);  
  168.     else //child   
  169.     setsid();  
  170.     //Ensure future opens won't allocate controlling ttys.  
  171.     sa.sa_handler=SIG_IGN;  
  172.     sigemptyset(&sa.sa_mask);  
  173.     sa.sa_flags=0;  
  174.     if(sigaction(SIGHUP,&sa,NULL)<0)  
  175.         my_err("sigaction error");  
  176.     if((pid=fork())<0)  
  177.         my_err("second fork error");  
  178.     else if(pid!=0) //parent process  
  179.         exit(0);  
  180.     //child process  
  181.     //Change the current working directory to the root,so  
  182.     //we won't prevent file systems from being unmounted.  
  183.     if(chdir("/")<0)  
  184.         my_err("chdir error");  
  185.     //Close all open file descriptors.  
  186.     if(rl.rlim_max==RLIM_INFINITY)  
  187.         rl.rlim_max=1024;  
  188.     for(i=0;i<rl.rlim_max;i++)  
  189.     {  
  190.         close(i);  
  191.     }  
  192.     //Attach file descriptors 0,1,and 2 to /dev/null  
  193.     fd0=open("/dev/null",O_RDWR);  
  194.     fd1=dup(0);  
  195.     fd2=dup(0);  
  196.     //Initialize the log file  
  197.     openlog(cmd,LOG_CONS,LOG_DAEMON);  
  198.     if(fd0!=0 || fd1!=1 || fd2!=2)  
  199.     {  
  200.         syslog(LOG_ERR,"unexpected file descriptors %d %d %d",fd0,fd1,fd2);  
  201.         exit(0);  
  202.     }  
  203. }  
  204.   
  205. void my_err(char *str)  
  206. {  
  207.     perror(str);  
  208.     exit(1);  
  209. }