ps -axj
-a 顯示由其他用戶所擁有的進程的狀態;-x 顯示沒有控制終端的進程狀態;-j 顯示與作業有關的信息
ps -efj
3. 編程規則
- kswapd,內存換頁守護進程。
- flush守護進程在可用內存達到設置的最小閥值時將臟頁面沖洗至磁盤。
- sync_supers守護進程定期將文件系統元數據沖洗至磁盤。
- jbd守護進程幫助實現了ext4文件系統中的日志功能。
- rpcbind守護進程提供了將遠程過程調用程序號映射為網絡端口號的服務。
- rsyslogd守護進程可以被由管理員啟用的將系統消息記入日志的任何程序使用。
- inetd守護進程。超級因特網服務進程。
- crond守護進程在定期安排的日期和時間執行命令。
- atd守護進程,允許用戶在指定的時間執行任務,但是每個任務只執行一次。
- sshd守護進程提供了安全的遠程登錄和執行設施。
- cuPSD守護進程,打印假脫機進程,處理對系統提出的各個打印請求。
- 調用umask將文件模式創建屏蔽字設置為一個已知值(通常為0)。
- 調用fork,然后使父進程exit。因為:第一,如果守護進程是通過shell啟動的,這可以讓shell認為這條命令已經執行完畢;第二,子進程繼承了父進程的進程組ID,但獲得一個新的進程ID,這保證了子進程不是一個進程組的組長進程。這是setsid的先決條件。
- 調用setsid創建一個新會話。使調用進程:a. 成為新會話的首進程;b. 成為一個新進程組的組長進程;c. 沒有控制終端
- 將當期工作目錄更改為根目錄,以免占有某文件系統,使得其不能被卸載。或者,某寫守護進程還可能把當前工作目錄更改到某個指定位置。
- 關閉不再需要的文件描述符。使守護進程不再持有從其父進程繼承來的任何文件描述符。可以使用open_max函數或getrlimit函數來判定最高文件描述符的值,并關閉直到該值的所有描述符。
- 某些守護進程打開/dev/null使其具有文件描述符0、1、2 。這樣,任何一個試圖讀標準輸入、寫標準輸出或標準錯誤的庫例程都不會產生任何效果。
#include "apue.h"#include <syslog.h>#include <fcntl.h>#include <sys/resource.h>void daemonize(const char *cmd){ int i, fd0, fd1, fd2; pid_t pid; struct rlimit rl; struct sigaction sa; /** Clear file creation mask.*/ umask(0); /** Get maximum number of file descriptors.*/ if (getrlimit(RLIMIT_NOFILE, &rl) < 0) err_quit("%s: can’t get file limit", cmd); /** Become a session leader to lose controlling TTY.*/ if ((pid = fork()) < 0) err_quit("%s: can’t fork", cmd); else if (pid != 0) /* parent */ exit(0); setsid(); /** Ensure future opens won’t allocate controlling TTYs.*/ sa.sa_handler = SIG_IGN; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (sigaction(SIGHUP, &sa, NULL) < 0) err_quit("%s: can’t ignore SIGHUP", cmd); if ((pid = fork()) < 0) err_quit("%s: can’t fork", cmd); else if (pid != 0) /* parent */ exit(0); /** Change the current working directory to the root so* we won’t PRevent file systems from being unmounted.*/ if (chdir("/") < 0) err_quit("%s: can’t change directory to /", cmd); /** Close all open file descriptors.*/ if (rl.rlim_max == RLIM_INFINITY) rl.rlim_max = 1024; for (i = 0; i < rl.rlim_max; i++) close(i); /** Attach file descriptors 0, 1, and 2 to /dev/null.*/ fd0 = open("/dev/null", O_RDWR); fd1 = dup(0); fd2 = dup(0); /** Initialize the log file.*/ openlog(cmd, LOG_CONS, LOG_DAEMON); if (fd0 != 0 || fd1 != 1 || fd2 != 2) { syslog(LOG_ERR, "unexpected file descriptors %d %d %d", fd0, fd1, fd2); exit(1); }}
4. 出錯記錄
- 內核例程可以調用log函數。
- 大多數用戶進程(守護進程)調用syslog函數來產生日志消息。
- 無論一個用戶進程是在此主機上,還是在通過TCP/IP網絡連接到此主機的其他主機上,都可將日志消息發送到UDP端口514 。
#include <syslog.h>
void openlog(const char *ident, int option, int facility);
void syslog(int priority, const char *format, ...);
void closelog(void);
int setlogmask(int maskpri);
Returns: previous log priority mask value
5. 單實例守護進程
#include <unistd.h>#include <stdlib.h>#include <fcntl.h>#include <syslog.h>#include <string.h>#include <errno.h>#include <stdio.h>#include <sys/stat.h>#define LOCKFILE "/var/run/daemon.pid"#define LOCKMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)extern int lockfile(int); int already_running(void){ int fd; char buf[16]; fd = open(LOCKFILE, O_RDWR|O_CREAT, LOCKMODE); if (fd < 0) { syslog(LOG_ERR, "can’t open %s: %s", LOCKFILE, strerror(errno)); exit(1); } if (lockfile(fd) < 0) { if (errno == EACCES || errno == EAGAIN) { close(fd); return(1); } 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);}
6. 守護進程的慣例
- 若守護進程使用鎖文件,那么該文件通常存儲在/var/run目錄中。守護進程可能需要具有超級用戶權限才能在此目錄中創建文件。鎖文件的名字通常是name.pid。
- 若守護進程支持配置選項,那么配置文件通常存放在/etc目錄中。配置文件的名字通常是name.conf。
- 守護進程可用命令行啟動,但通常它們是由系統初始化腳本之一啟動的。
- 某些守護進程捕捉SIGHUP信號,當它們接收到該信號時,重新讀配置文件。
新聞熱點
疑難解答