最近在看APUE,记录一下如何创建一个完整的守护进程。以备不时查看。(注:RedHat在/var/log/messages文件中,可查看syslog函数记录的日志。)
- #include <stdio.h>
- #include <stdlib.h>
- #include <sys/time.h>
- #include <sys/resource.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <signal.h>
- #include <syslog.h>
- #include <fcntl.h>
- #include <errno.h>
- #include <string.h>
- #define LOCKFILE "/var/run/daemon.pid"
- #define LOCKMODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
- void daemonize(const char *);
- void my_err(char *);
- int lockfile(int);
- int already_running(void);
- void reread(void);
- void *thread_fn(void *);
- sigset_t mask;
- int main(int argc,char *argv[])
- {
- printf("start\n");
- int err;
- pthread_t tid;
- char *cmd;
- struct sigaction sa;
- if((cmd=strchr(argv[0],'/'))==NULL)
- {
- cmd=argv[0];
- }
- else
- cmd++;
- //Become a daemon
- daemonize(cmd);
- //Make sure only one copy of the daemon is running
- if(already_running()){
- syslog(LOG_ERR,"daemon already running.");
- exit(1);
- }
- //Restore SIGHUP default and block all signals.
- sa.sa_handler=SIG_DFL;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags=0;
- if(sigaction(SIGHUP,&sa,NULL)<0)
- {
- syslog(LOG_ERR,"sigaction SIGHUP error:%s",strerror(err));
- exit(1);
- }
- sigfillset(&mask);
- if((err=pthread_sigmask(SIG_BLOCK,&mask,NULL))<0)
- {
- syslog(LOG_ERR,"pthread_sigmask error:%s",strerror(err));
- exit(1);
- }
- //Create a thread to handle SIGHUP and SIGTERM
- err=pthread_create(&tid,NULL,thread_fn,NULL);
- if(err<0)
- {
- syslog(LOG_ERR,"pthread_create error:%s",strerror(err));
- exit(1);
- }
- //Proceed with the rest of daemon
- sleep(100);
- printf("end\n");
- exit(0);
- }
- //Reread the configuration file
- void reread(void)
- {
- //read configuration file...etc
- }
- void *thread_fn(void *arg)
- {
- int err,signo;
- for(;;)
- {
- err=sigwait(&mask,&signo);
- if(err!=0)
- {
- syslog(LOG_ERR,"sigwait error:%s",strerror(err));
- exit(1);
- }
- switch(signo)
- {
- case SIGHUP:
- syslog(LOG_INFO,"reread configuration.");
- reread();
- break;
- case SIGTERM:
- syslog(LOG_INFO,"got SIGTERM,exiting");
- exit(0);
- default:
- syslog(LOG_INFO,"unexpected signal:%d",signo);
- }
- }
- return 0;
- }
- //Whether a daemon process is already running
- //running: return 1
- //no run:return 0
- int already_running(void)
- {
- int fd;
- char buf[16];
- fd=open(LOCKFILE,O_WRONLY|O_CREAT,LOCKMODE);
- if(fd<0)
- {
- syslog(LOG_ERR,"can't open %s:%s",LOCKFILE,strerror(errno));
- return 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));
- return 1;
- }
- ftruncate(fd,0);
- sprintf(buf,"%ld",(long)getpid());
- write(fd,buf,strlen(buf));
- return 0;
- }
- //Lock the whole file pointed by fd
- int lockfile(int fd)
- {
- struct flock fl;
- fl.l_type=F_WRLCK;
- fl.l_start=0;
- fl.l_whence=SEEK_SET;
- fl.l_len=0;
- int r=fcntl(fd,F_SETLK,&fl);
- return r;
- }
- //Make a process to a daemon.
- void daemonize(const char *cmd)
- {
- int i,fd0,fd1,fd2;
- pid_t pid;
- struct rlimit rl;
- struct sigaction sa;
- //Clear file creation mask.
- umask(0);
- //Get maximum number of file descriptors.
- if(getrlimit(RLIMIT_NOFILE,&rl)<0)
- my_err("getrlimit error");
- //Become a session leader to lose controlling tty.
- if((pid=fork())<0)
- my_err("first fork error");
- else if(pid!=0) //parent
- exit(0);
- else //child
- setsid();
- //Ensure future opens won't allocate controlling ttys.
- sa.sa_handler=SIG_IGN;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags=0;
- if(sigaction(SIGHUP,&sa,NULL)<0)
- my_err("sigaction error");
- if((pid=fork())<0)
- my_err("second fork error");
- else if(pid!=0) //parent process
- exit(0);
- //child process
- //Change the current working directory to the root,so
- //we won't prevent file systems from being unmounted.
- if(chdir("/")<0)
- my_err("chdir error");
- //Close all open file descriptors.
- if(rl.rlim_max==RLIM_INFINITY)
- rl.rlim_max=1024;
- for(i=0;i<rl.rlim_max;i++)
- {
- close(i);
- }
- //Attach file descriptors 0,1,and 2 to /dev/null
- fd0=open("/dev/null",O_RDWR);
- fd1=dup(0);
- fd2=dup(0);
- //Initialize the log file
- openlog(cmd,LOG_CONS,LOG_DAEMON);
- if(fd0!=0 || fd1!=1 || fd2!=2)
- {
- syslog(LOG_ERR,"unexpected file descriptors %d %d %d",fd0,fd1,fd2);
- exit(0);
- }
- }
- void my_err(char *str)
- {
- perror(str);
- exit(1);
- }