编写守护进程程序时需遵循一些基本规则,以防止产生不必要的交互作用,下面先说明这些规则,然后给出一个按照这些规则编写的函数deamonize.
(1)首先,调用umask将文件创建屏蔽字设置为一个已知值(通常为0)。
(2)调用fork,然后是父进程exit。
(3)调用setsid创建一个新会话。
(4)将当前工作目录更改为根目录。
(5)关闭不需要的文件描述符。
(6)将文件描述符0,1,2指向 /dev/null
以下是一个记录日志的守护进程。
1 #include "apue.h" //详解见另一片文章 2 #include <syslog.h> 3 #include <fcntl.h> 4 #include <sys/resource.h> 5 6 void deamonze(const char *cmd) 7 { 8 int i,fd0,fd1,fd2; 9 pid_t pid; 10 struct rlimit rl; 11 struct sigaction sa; 12 13 //1、调用umask将文件模式创建屏蔽字设置为一个已知值(通常为0) 14 umask(0); 15 if(getrlimit(RLIMIT_NOFILE,&rl)<0) //获取文件描述符的数量 16 err_quit("%s:can't get file limit",cmd); 17 18 //2、使子进程成为会话的组长 19 if((pid = fork())<0) //调用fork,然后父进程退出 20 err_quit("%s:can't fork",cmd); 21 else if(pid!=0) //父进程 22 exit(0); //退出父进程 23 setsid(); //调用setsid创建一个新会话 24 25 //3、确保未来的打开不能分配控制终端 26 sa.sa_handler = SIG_IGN; 27 sigemptyset(&sa.sa_mask); 28 sa.sa_flags = 0; 29 if(sigaction(SIGHUP,&sa,NULL)<0) 30 err_quit("%s:can't fork",cmd); 31 else if(pid != 0) 32 exit(0); 33 34 //4、切换工作目录到到根目录,避免无法卸载可卸载设备 35 if(chdir("/")<0) 36 err_quit("%s:can't change directory to /",cmd); 37 38 //6、关闭所有打开的文件描述符 39 if(rl.rlim_max == RLIM_INFINTY) 40 rl.rlim_max = 1024; 41 42 for(i=0;i<rl.rlim_max;i++) 43 close(i); 44 45 //6、把文件描述符0,1,2绑定到 /dev/null 46 fd = open("/dev/null",O_RDWR); 47 fd1 = dup(0); 48 fd1 = dup(0); 49 50 //初始化日志文件 51 openlog(cmd,LOG_CONS,LOG_DEAMON); 52 if(fd1!=0||fd1!=1||fd2!=2) 53 { 54 syslog(LOG_ERR,"unexpected file descriptors %d %d %d",fd0,fd1,fd2); 55 exit(1); 56 } 57 58 }