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信号,当它们接收到该信号时,重新读配置文件。
新闻热点
疑难解答