//标准库自带函数,通常以 daemon(0, 0) 方式调用 int daemon(int nochdir, int noclose) Linux: #include <unistd.h> FreeBSD: #include <stdlib.h>
//自主实现原理如下
[a] 编写守护进程的要点
- 指定 umask 值,由环境继承来的默认权限有可能存在问题
- 使该守护进程成为一个孤儿进程组中的唯一成员:
- fork 之后终止父进程,此举确保不是进程组首进程,然后 setsid 创建新会话
- 丢弃会话首进程身份(再次 fork),从而确保了该进程不会获得控制终端
- 切换到正确的工作目录中
- 如果没有关联的配置文件,则可以设置 SIG_IGN 忽略 SIG_HUP 信号
- 关闭不需要的文件描术符,可以将常用的 0、1、2 三个描述符关联至 /dev/null,以防止意外 I/O
[b] 样例
1 #include <sys/types.h> 2 #include <sys/time.h> 3 #include <sys/stat.h> 4 #include <sys/resource.h> 5 #include <fcntl.h> 6 #include <unistd.h> 7 #include <stdio.h> 8 #include <signal.h> 9 10 void daemonize(const char *); 11 char *workdir = "/"; 12 13 int 14 main(void) 15 { 16 daemonize(workdir); 17 while(1) 18 { 19 sleep(10); 20 } 21 } 22 23 void 24 daemonize(const char *workdir) 25 { 26 pid_t pid; 27 int fd0, fd1, fd2; 28 struct rlimit rl; 29 struct sigaction sa; 30 31 umask(0); 32 chdir(workdir); 33 34 pid = fork(); 35 if (pid < 0) 36 { 37 perror("fork"); 38 } 39 else if (pid > 0) 40 { 41 _exit(0); 42 } 43 44 setsid(); 45 46 pid = fork(); 47 if (pid < 0) 48 { 49 perror("fork"); 50 } 51 else if (pid > 0) 52 { 53 _exit(0); 54 } 55 56 if (-1 == getrlimit(RLIMIT_NOFILE, &rl)) 57 { 58 perror("getrlimit"); 59 } 60 if (rl.rlim_max == RLIM_INFINITY) 61 { 62 rl.rlim_max = 1024; 63 } 64 for(pid = 0; pid < rl.rlim_max; ++pid) 65 { 66 close(pid); 67 } 68 69 fd0 = open("/dev/null", O_RDWR); 70 fd1 = dup2(fd0, 1); 71 fd2 = dup2(fd0, 2); 72 73 sa.sa_handler = SIG_IGN; 74 sa.sa_flags = 0; 75 sigemptyset(&sa.sa_mask); 76 if (sigaction(SIGHUP, &sa, NULL) < 0) 77 { 78 perror("sigaction"); 79 } 80 }
...