守護(hù)進(jìn)程運(yùn)行在后臺,不與任何控制終端相關(guān)聯(lián).守護(hù)進(jìn)程以root用戶運(yùn)行或者其他特殊的用戶,并處理一些系統(tǒng)級的任務(wù), 習(xí)慣上守護(hù)進(jìn)程的名字以d結(jié)尾,但不是必須的.
對守護(hù)進(jìn)程的兩個(gè)基本要求: 它必須是init進(jìn)程的子進(jìn)程; 不與任何控制終端相關(guān)聯(lián).
一般來講, 進(jìn)程可以通過以下步驟成為守護(hù)進(jìn)程:
1. 調(diào)用fork(), 創(chuàng)建新的進(jìn)程, 它會是將來的守護(hù)進(jìn)程.
2. 在守護(hù)進(jìn)程的父進(jìn)程中調(diào)用exit(). 這保證祖父進(jìn)程(守護(hù)進(jìn)程的祖父進(jìn)程)確認(rèn)父進(jìn)程已經(jīng)結(jié)束. 還保證父進(jìn)程不再繼續(xù)運(yùn)行, 守護(hù)進(jìn)程不是組長進(jìn)程. 最后一點(diǎn)是順利完成一下步驟的前提.
3. 調(diào)用setsid(), 使得守護(hù)進(jìn)程有一個(gè)新的進(jìn)程組和新的會話, 兩者都把它作為首進(jìn)程, 這也保證它不會與控制終端相關(guān)聯(lián).
4. 用chdir()將當(dāng)前工作目錄改為根目錄. 因?yàn)榍懊嬲{(diào)用fork()創(chuàng)建了新進(jìn)程, 它所繼承來的當(dāng)前工作目錄可能在文件系統(tǒng)的任何地方. 而守護(hù)進(jìn)程通常在系統(tǒng)啟動時(shí)運(yùn)行, 同時(shí)不希望一些隨機(jī)目錄保持打開狀態(tài), 也就阻止了管理員卸載守護(hù)進(jìn)程工作目錄所在的那個(gè)文件系統(tǒng).
5. 關(guān)閉所有的文件描述符. 不需要繼承任何打開的文件描述符, 對于無法確認(rèn)的文件描述符, 讓它們繼續(xù)處于打開狀態(tài).
6. 打開0, 1和2號文件描述符(標(biāo)準(zhǔn)輸入, 標(biāo)準(zhǔn)輸出和標(biāo)準(zhǔn)錯(cuò)誤), 把它們重定向到/dev/null.
根據(jù)這些規(guī)則, 下面程序可以成為守護(hù)進(jìn)程:
1 #include<sys/types.h>
2 #include<sys/stat.h>
3 #include<stdlib.h>
4 #include<stdio.h>
5 #include<fcntl.h>
6 #include<unistd.h>
7 #include<linux/fs.h>
8
9 int main(void)
10 {
11 pid_t pid;
12 int i;
13 /* create new process */
14 pid = fork();
15 if(pid == -1) return -1;
16 else if(pid != 0) exit(EXIT_SUCCESS);
17 /* create new session and process group */
18 if(setsid() == -1) return -1;
19 /* set the working directory to the root directory*/
20 if(chdir("/") == -1) return -1;
21 /* close all open files -- NR_OPEN is overkill, but works */
22 for(i = 0; i < NR_OPEN; i++) close(i);
23 /* redirect fd's 0, 1, 2 to /dev/null */
24 open("/dev/null", O_RDWR); /* stdin */
25 dup(0); /* stdout */
26 dup(0); /* stderr */
27 /* do it daemon thing
.*/
28
29 return 0;
30 }
許多Unix系統(tǒng)在它們的C函數(shù)庫中提供了daemon()函數(shù)來完成這些工作:
#include <unistd.h>
int daemon(int nochdir, int noclose);