第十三章 守護程序
守護程序也稱精靈程序是生存期較長的一種程序,它們常常在系統自舉時啟動,關閉時才終止,因為它們沒有控制終端,所以說它們是在後台執行的。
系統程序依賴於作業系統實現。父程序id為0的程序通常是核心程序,它們作為系統自舉過程的一部分而啟動。
一、程式設計規則
在編寫守護程序程式時需遵循一些基本規則,以便防止產生並不需要的互動作用:
(1)首先要做的是呼叫umask將檔案模式建立遮蔽字設定為0。由繼承得來的檔案模式建立遮蔽字可能會拒絕設定 某些許可權。
(2)呼叫fork,然後使父程序退出。
(3)呼叫setsid以建立乙個新會話。
(4)將當前工作目錄更改為新目錄。
(5)關閉不在需要的檔案描述符。
(6)
例項:初始化乙個守護程序
#include "apue.h"
#include #include #include void
daemonize(const char *cmd)
if ((pid == fork()) < 0)
else if(pid != 0)
setsid();
sa.sa_handler = sig_ign;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(sighup, &sa, null) < 0)
if ((pid = fork()) < 0)
else if (pid != 0)
if (rl.rlim_max == rlim_infinity)
for (i = 0; i < rl.rlim_max; i++)
fd0 = open("/dev/null", o_rdwr);
fd1 = dup(0);
fd2 = dup(0);
openlog(cmd, log_cons, log_daemon);
if (fd0 != 0 || fd1 != 1 || fd2 != 2)
}
二、出錯記錄
有三種方法產生日誌訊息:
(1)核心例程可以呼叫log函式。
(2)大多數使用者程序(守護程序)呼叫syslog(3)函式以產生日誌資訊。
(3)在此主機上的乙個使用者程序,或通過tcp/ip網路鏈結到此主機的其它主機上的乙個使用者程序可將日誌訊息發向udp埠514.
void openlog(const char *ident, int option, int facility);
void syslog(int priority , const char *format, ...);
void closelog(void);
int setlogmask(int maskpri);
呼叫openlog是可選擇的。如果不呼叫openlog,則在第一次呼叫syslog時, 自動呼叫openlog。呼叫closelog也是可選擇的——它只是關閉曾被用於與syslog守護程序通訊的描述符。
呼叫syslog產生乙個日誌訊息。
setlogmask函式用於設定程序的記錄優先順序遮蔽字。
三、單例項守護程序
為了正常運作,某些守護程序實現為單例項的,也就是在任一時刻只執行該守護程序的乙個副本。
檔案鎖和記錄鎖機制是一種方法的基礎,該方法用來保護乙個守護程序只有乙個副本在執行。
檔案鎖個記錄鎖提供了一種方便的互斥機制。如果守護程序在整個檔案上得到一把寫鎖,那麼在該守護程序終止時,這把鎖將被自動刪除,這就簡化了復原所需的處理,去除了對以前守護程序例項需要進行清理的有關操作。
例項:保證只執行某個守護程序的乙個副本
#include #include #include #include #include #include #include #include #define lockfile "/var/run/daemon.pid"
#define lockmode (s_irusr | s_iwusr | s_irgrp | s_iroth)
extern int lockfile(int);
int already_running(void)
if (lockfile(fd) < 0)
syslog(log_err, "can't lock %s: %s",lockfile, strerror(errno));
exit(1);
}ftruncate(fd, 0);
sprintf(buf, "%ld", (long)getpid());
write(fd, buf, strlen(buf) + 1);
return(0);
}
四、守護程序的慣例
1.若守護程序使用鎖檔案,那麼該檔案通常存放在/var/run目錄中。
2.若守護程序支援配置選項,那麼配置檔案通常放在/etc目錄中。
3.守護程序可用命令列啟動,但通常它們是由系統初始化指令碼之一(/etc/rc* 或 /etc/init.d/*)啟動的。
4.若一守護程序有一配置檔案,那麼當該守護程序啟動時,它讀改檔案,但在此後一般就不會再檢視它.
例項:守護程序重讀配置檔案
#include "apue.h"
#include #include #include #include #include #include #include #include #include #define lockfile "/var/run/daemon.pid"
#define lockmode (s_irusr | s_iwusr | s_irgrp | s_iroth)
extern int lockfile(int);
static int already_running(void);
sigset_t mask;
void
reread(void)
void *
thr_fn(void *arg)
switch (signo)
}return(0);
}int
main(int argc, char *argv)
else
daemonize(cmd);
if (alreadyrunning())
sa.sa_handler = sig_dfl;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(sighup, &sa, null) < 0)
sigfillset(&mask);
if ((err = pthread_sigmask(sig_block, &mask, null)) != 0)
err = pthread_create(&tid, null, thr_fn, 0);
if (err != 0)
exit(0);
}int already_running(void)
if (lockfile(fd) < 0)
syslog(log_err, "can't lock %s: %s",lockfile, strerror(errno));
exit(1);
}ftruncate(fd, 0);
sprintf(buf, "%ld", (long)getpid());
write(fd, buf, strlen(buf) + 1);
return(0);
}
例項:守護程序重讀配置檔案的另一種實現
#include "apue.h"
#include #include #include #include #include #include #include #include #include extern int lockfile(int);
static int already_running(void);
void
reread(void)
void
sigterm(int signo)
void
sighup(int signo)
intmain(int argc, char *argv)
else
daemonize(cmd);
if (alreadyrunning())
sa.sa_handler = sigterm;
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask, sighup);
sa.sa_flags = 0;
if (sigaction(sigterm, &sa, null) < 0)
sa.sa_handler = sighup;
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask, sigterm);
sa.sa_flags = 0;
if (sigaction(sighup, &sa, null) < 0)
exit(0);
}int already_running(void)
if (lockfile(fd) < 0)
syslog(log_err, "can't lock %s: %s",lockfile, strerror(errno));
exit(1);
}ftruncate(fd, 0);
sprintf(buf, "%ld", (long)getpid());
write(fd, buf, strlen(buf) + 1);
return(0);
}
unix 環境高階程式設計 讀書筆記
unix環境高階程式設計 讀書筆記 第8章exit和 exit區別 exit會直接進入核心,不會關閉io流。程序基本控制函式還有 wait,fork,exec。atexit 程式正常退出時呼叫,如果因為signal退出則不能呼叫。功能 註冊函式可以完成一些清理工作,比如全域性log類,可以不設定析構...
unix環境高階程式設計 讀書筆記
檔案 unix支援在不同程序之間共享開啟的檔案。核心使用三種資料結構表示開啟的檔案 原子操作 一般而言,原子操作指的是由多步組成的操作。如果該操作原子的執行,要麼執行完所有步,要麼一步也不執行,不可能只執行所有步驟的乙個子集。2 注意 原子操作函式 pread,pwrite pread 相當於呼叫r...
Unix環境高階程式設計 讀書筆記一
unix 基礎知識 這一章主要是unix系統的概論以及一些概念的介紹,主要分為10個小節 1 登陸 2 檔案和目錄 3 輸入和輸出 4 程式和程序 5 ansi c 6 出錯處理 7 使用者標識 8 訊號 9 unix時間值 10 系統呼叫和庫函式 這個都比較簡單,就不再重複敘述了。在標頭檔案中定義...