Linux下守护进程的创建一般遵守以下规则:
1. 设置umask为一个已知的值,通常为0;
因为要确保守护进程对创建的进程具有正确的权限,避免默认的umask造成影响;
2. 调用fork( ),之后使父进程退出;
首先,守护进程是由shell进程启动的,调用fork,使父进程退出,让shell进程认为该程序已经结束;其次,子进程继承了父进程的组ID,但是获得了一个新的进程ID,所以保证了子进程不是一个进程组的leader,这也是接下来要调用setsid的先决条件;
3. 调用setsid创建一个新的会话;
当调用setsid后,该子进程创建了一个新的会话;并且成为了进程组的leader;而且和控制终端脱离了;
4. 将目录改为root;
当前工作目录是由父进程继承而来,有可能会被unmount掉,不好说,所以为了保证文件系统的有效性,将目录切换为root更目录更加保险;
5. 关闭所有不需要的文件描述符;
该步骤阻止了守护进程持有父进程的一些打开的文件描述符,可以使用getrlimit函数去确定最大的文件描述符的值并关闭所有的文件描述符;
6. 将文件描述符 0,1,2指向/dev/null;
下面创建一个守护进程,每隔5秒向日志文件中写入一条记录:
-
#include <unistd.h>
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <fcntl.h>
-
#include <sys/resource.h>
-
#include <sys/types.h>
-
#include <syslog.h>
-
#include <string.h>
-
#include <errno.h>
-
#include <signal.h>
-
#include <time.h>
-
-
#define error_handle(en,msg) \
-
do{errno=en;perror(msg);exit(EXIT_FAILURE);}while(0)
-
-
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)
-
error_handle(1,"getrlimit error");
-
-
/* Become a session leader to lose controlling TTY. */
-
if((pid=fork())<0)
-
error_handle(1,"fork error");
-
else if(pid!=0) /* parent */
-
exit(0);
-
setsid();
-
-
/* Ensure future opens won't allocate controlling TTYs. */
-
sa.sa_handler=SIG_IGN;
-
sigemptyset(&sa.sa_mask);
-
sa.sa_flags=0;
-
// SIGHUP is a signal sent to a process when its controlling terminal is closed
-
if(sigaction(SIGHUP,&sa,NULL)<0)
-
error_handle(1,"SIGHUP error");
-
if((pid=fork())<0)
-
error_handle(1,"fork error");
-
else if(pid!=0) /* parent */
-
exit(0);
-
-
/* Change the current working directory to the root so
-
we won't prevent file system from being unmounted. */
-
if(chdir("/")<0)
-
error_handle(1,"chdir root 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 descriptos 0,1,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_PID,LOG_DAEMON|LOG_USER);
-
if(fd0!=0||fd1!=1||fd2!=2){
-
syslog(LOG_ERR,"unexpected file descriptors %d %d %d\n",fd0,fd1,fd2);
-
exit(EXIT_FAILURE);
-
}
-
-
time_t cur_t;
-
-
while(1){
-
time(&cur_t);
-
syslog(LOG_INFO,"current time is %s\n",ctime(&cur_t));
-
sleep(3);
-
}
-
-
exit(EXIT_SUCCESS);
-
}
-
-
int main(void){
-
daemonize("mydeamon");
-
exit(0);
-
}
在Ubuntu下可以查看 /var/log/syslog 文件变化;
tail -n 50 /var/log/syslog 查看最后50行 为该daemon进程输出的时间
阅读(839) | 评论(0) | 转发(0) |