原文鏈接:daemon函數詳解原文鏈接
頭文件與函數原型
#include <unistd.h>
int daemon(int nochdir,int noclose)
創建守護進程前提條件
- 將進程的工作目錄修改爲"/"根目錄。daemon的參數nochdir爲0時,即可將工作目錄修改爲根目錄;
- 將標準輸入,輸出和錯誤輸出重定向到/dev/null daemon的參數noclose爲0時,輸入,輸出以及錯誤輸出重定向到/dev/null 。
返回值:成功返回0 錯誤返回1
deamon()函數解析
#include <unistd.h>
int main(int argc,char *argv[])
{
if (daemon(0, 0)) {//調用glibc庫函數daemon,創建daemon守護進程
perror("daemon");
return -1;
}
子進程內容
}
int daemon( int nochdir, int noclose )
{
pid_t pid;
if ( !nochdir && chdir("/") != 0 ) //如果nochdir=0,那麼改變到"/"根目錄
return -1;
if ( !noclose ) //如果沒有noclose=0,那麼開始輸入,輸出以及錯誤輸出重定向到/dev/null
{
int fd = open("/dev/null", O_RDWR);//打開神奇的黑洞文件.
if ( fd < 0 )
return -1;
//每個進程都擁有自己fds文件描述符表,
//fdt->fd[0],fdt->fd[1],fdt->fd[2],
//表中fd[0],fd[1],和fd[2]文件句柄位置對應的fops文件操作函數集,分別與標準輸入,標準輸出,標準錯誤輸出相關聯
//所以用戶應用程序調用open函數打開文件時,默認都是以3索引爲開始句柄,也就是fd[3],故當前open返回的文件句柄最小值爲3
//dup2(unsigned int oldfd, unsigned int newfd)系統調用就是用oldfd的fops操作文件集file,複製到newfd所在處
//即:fdt->fd[newfd] = fdt->fd[oldfd];
if ( dup2( fd, 0 ) < 0 || //使用字符設備/dev/null的fops函數操作集,替換0句柄對應的文件操作集.
dup2( fd, 1 ) < 0 || //使用字符設備/dev/null的fops函數操作集,替換1句柄對應的文件操作集.
dup2( fd, 2 ) < 0 ) //使用字符設備/dev/null的fops函數操作集,替換2句柄對應的文件操作集.
{
close(fd);
return -1;
}
//如果替換成功,那麼鍵盤的任何操作將不會對該進程產生任何影響,因爲0,1,2句柄所在處的fops文件操作集已經都變成了,
//被重定向爲"/dev/null"空洞設備的fops.所以對0,1,2句柄的讀寫操作,也就是在對/dev/null設備作讀寫操作.
close(fd); //關閉打開的/dev/null
}
pid = fork();//創建子進程.
if (pid < 0)
return -1;
if (pid > 0)
_exit(0); //返回執行的是父進程,那麼父進程退出,讓子進程變成真正的孤兒進程.
//ok,我們期望的daemon子進程執行到這裏了.
if ( setsid() < 0 ) //設置session id.
return -1;
return 0; //成功創建daemon子進程[luther.gliethttp].
}