1. 程式人生 > >Unix/Linux程式設計-建立守護程序

Unix/Linux程式設計-建立守護程序

建立守護程序


#include <fcntl.h>
#include <sys/resource.h>
#include <syslog.h>
#include <unistd.h>
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>

// 守護程序通過 syslog 輸出的日誌資訊記錄在 /var/log/syslog 日誌檔案中

// 建立守護程序
void daemonize(const char *cmd)
{
	int i, fd0, fd1, fd2;
	pid_t pid;
	struct rlimit rl;
	struct sigaction sa;

	// 1. 清除建立檔案掩碼
	umask(0);

	// 2. 獲取最大檔案描述符
	if(getrlimit(RLIMIT_NOFILE, &rl) < 0)
	{
		printf("%s: cannot get file limit\n", cmd);
		return;
	}

	// 3. 成為脫離控制終端的會話組長
	if((pid = fork()) < 0)
	{
		printf("%s: cannot fork\n", cmd);
		return;
	}
	else if(pid != 0)	// 父程序退出
	{
		exit(0);
	}
	setsid();
	
	// 4. 確保將來啟動守護程序不會分配控制終端
	sa.sa_handler = SIG_IGN;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;
	if(sigaction(SIGHUP, &sa, NULL) < 0)
	{
		printf("%s: cannot ignore SIGHUP\n", cmd);
		return;
	}
	// 再次產生子程序,使其不會成為會話首程序,防止取得控制終端
	if((pid = fork()) < 0)  
	{
		printf("%s: cannot fork", cmd);
		return;
	}
	else if(pid != 0)		// 父程序退出
	{
		exit(0);
	}

	// 5. 工作目錄切換為根目錄,這樣防止檔案系統被解除安裝
	if(chdir("/") < 0)
	{
		printf("%s: cannot change directory to /", cmd);
		return;
	}

	// 6. 關閉所有開啟的檔案
	if(rl.rlim_max == RLIM_INFINITY)
	{
		rl.rlim_max = 1024;
	}
	for(i = 0; i < rl.rlim_max; i++)
	{
		close(i);
	}

	// 7. 將檔案描述符0,1,2指向 /dev/null
	fd0 = open("/dev/null", O_RDWR);
	fd1 = dup(0);
	fd2 = dup(0);

	// 8. 初始化日誌檔案
	openlog(cmd, LOG_CONS, LOG_DAEMON);
	if(fd0 != 0 || fd1 != 1 || fd2 != 2)
	{
		syslog(LOG_ERR, "unexcepted file descriptor %d %d %d", fd0, fd1, fd2);
		exit(1);
	}

	// 以上是使程序成為守護程序

	// 以下的工作才是這守護程序要做的工作
	i = 1;
	while (1)
	{
		syslog(LOG_INFO, "test - %d\n", i++);
		sleep(2);
	}
}