// 创建子进程,并退出当前父进程
if((pid = fork()) < 0){
syslog(LOG_INFO,"sampled : fork error");
return -1;
}
if ( pid != 0) {
// 父进程直接退出
exit(0);
}
// 新建会话,成功返回值是会话首进程id,进程组id ,首进程id
pid = setsid();
if ( pid < -1 ){
syslog(LOG_INFO,"sampled : setsid error");
return -1;
}
// 将工作目录切换到根目录
if ( chdir("/") < 0 ) {
syslog(LOG_INFO,"sampled : chidr error");
return -1;
}
// 关闭所有打开的句柄,如果确定父进程未打开过句柄,此步可以不做
if ( rl.rlim_max == RLIM_INFINITY ){
rl.rlim_max = 1024;
}
for(i = 0 ; i < rl.rlim_max; i ++) {
close(i);
}
// 重定向输入输出错误
fd = open("/dev/null",O_RDWR,0);
if(fd != -1){
dup2(fd,STDIN_FILENO);
dup2(fd,STDOUT_FILENO);
dup2(fd,STDERR_FILENO);
if (fd > 2){
close(fd);
}
}
// 消除文件掩码
umask(0);
return 0;
}
int pidfile_write(){
// 这里不用fopen直接打开文件是不想创建666权限的文件
FILE * pidfile = NULL;
int pidfilefd = creat(PID_FILE,S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if(pidfilefd != -1){
pidfile = fdopen(pidfilefd,"w");
}
if (! pidfile){
syslog(LOG_INFO,"pidfile write : can't open pidfile:%s",PID_FILE);
return 0;
}
fprintf(pidfile,"%d",getpid());
fclose(pidfile);
return 1;
}
int main(){
int err,signo;
sigset_t mask;
if (sampled_running() > 0 ){
exit(0);
}
if ( sampled() != 0 ){
}
// 写记录锁文件
if (pidfile_write() <= 0) {
exit(0);
}
while(1) {
// 捕捉信号
err = sigwait(&mask,&signo);
if( err != 0 ){
syslog(LOG_INFO,"sigwait error : %d",err);
exit(1);
}
switch (signo){
default :
syslog(LOG_INFO,"unexpected signal %d \n",signo);
break;
case SIGTERM:
syslog(LOG_INFO,"got SIGTERM. exiting");
exit(0);
}
}
}
程序编译运行结果,可以看到pid 、进程组id、会话id是一样的,没有终端,并且直接由pid为1的进程接管。此时的进程已经成为一个守护进程。
sighup与nohup
sighup(挂断)信号在控制终端或者控制进程死亡时向关联会话中的进程发出,默认进程对SIGHUP信号的处理时终止程序,所以我们在shell下建立的程序,在登录退出连接断开之后,会一并退出。
nohup,故名思议就是忽略SIGHUP信号,一般搭配& 一起使用,&表示将此程序提交为后台作业或者说后台进程组。执行下面的命令
nohup bash -c "tail -f /var/log/messages | grep sys" &
nohup与&启动的程序, 在终端还未关闭时,完全不像传统的守护进程,因为其不是会话首进程且持有终端,只是其忽略了SIGHUP信号