读书人

UNIX编程(13)-看护进程

发布时间: 2012-08-10 12:19:33 作者: rapoo

UNIX编程(13)-守护进程

1.守护进程的编程规则

1)用umask将文件模式创建屏蔽字设置为0

2)调用fork,然后使父进程退出

3)调用setsid创建一个新会话

4)将当前工作目录更改为根目录

5)关闭不再需要的的文件描述符

6)某些守护进程打开/dev/null使其具有文件描述符0,1,2,

例:初始化一个守护进程

?

?

#include "apue.h"#include <syslog.h>#include <fcntl.h>#include <sys/resource.h>voiddaemonize(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");    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 /");    /*     * 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);    }}


2.出错记录

使用syslog设施产生日志

有三种方法产生日志信息:

1)内核调用log函数

2)调用syslog函数以产生日志消息

3)用网络程序发送到其他主机的514端口

?

syslogd守护进程读取三种格式的日志信息,此守护进程在启动时读一个配置文件,/etc/syslog.conf,该文件决定了不同种类的消息送向何处。

?

?4.守护进程的惯例

例:守护进程重新读配置文件

#include "apue.h"#include <pthread.h>#include <syslog.h>sigset_t    mask;extern int already_running(void);voidreread(void){    /* ... */}void *thr_fn(void *arg){    int err, signo;    for (;;) {        err = sigwait(&mask, &signo);        if (err != 0) {            syslog(LOG_ERR, "sigwait failed");            exit(1);        }        switch (signo) {        case SIGHUP:            syslog(LOG_INFO, "Re-reading configuration file");            reread();            break;        case SIGTERM:            syslog(LOG_INFO, "got SIGTERM; exiting");            exit(0);        default:            syslog(LOG_INFO, "unexpected signal %d\n", signo);        }    }    return(0);}intmain(int argc, char *argv[]){    int                 err;    pthread_t           tid;    char                *cmd;    struct sigaction    sa;    if ((cmd = strrchr(argv[0], '/')) == NULL)        cmd = argv[0];    else        cmd++;    /*     * Become a daemon.     */    daemonize(cmd);    /*     * Make sure only one copy of the daemon is running.     */    if (already_running()) {        syslog(LOG_ERR, "daemon already running");        exit(1);    }    /*     * Restore SIGHUP default and block all signals.     */    sa.sa_handler = SIG_DFL;    sigemptyset(&sa.sa_mask);    sa.sa_flags = 0;    if (sigaction(SIGHUP, &sa, NULL) < 0)        err_quit("%s: can't restore SIGHUP default");    sigfillset(&mask);    if ((err = pthread_sigmask(SIG_BLOCK, &mask, NULL)) != 0)        err_exit(err, "SIG_BLOCK error");    /*     * Create a thread to handle SIGHUP and SIGTERM.     */    err = pthread_create(&tid, NULL, thr_fn, 0);    if (err != 0)        err_exit(err, "can't create thread");    /*     * Proceed with the rest of the daemon.     */    /* ... */    exit(0);}

?

另外一种实现

?

#include "apue.h"#include <syslog.h>#include <errno.h>extern int lockfile(int);extern int already_running(void);voidreread(void){    /* ... */}voidsigterm(int signo){    syslog(LOG_INFO, "got SIGTERM; exiting");    exit(0);}voidsighup(int signo){    syslog(LOG_INFO, "Re-reading configuration file");    reread();}intmain(int argc, char *argv[]){    char                *cmd;    struct sigaction    sa;    if ((cmd = strrchr(argv[0], '/')) == NULL)        cmd = argv[0];    else        cmd++;    /*     * Become a daemon.     */    daemonize(cmd);    /*     * Make sure only one copy of the daemon is running.     */    if (already_running()) {        syslog(LOG_ERR, "daemon already running");        exit(1);    }    /*     * Handle signals of interest.     */    sa.sa_handler = sigterm;    sigemptyset(&sa.sa_mask);    sigaddset(&sa.sa_mask, SIGHUP);    sa.sa_flags = 0;    if (sigaction(SIGTERM, &sa, NULL) < 0) {        syslog(LOG_ERR, "can't catch SIGTERM: %s", strerror(errno));        exit(1);    }    sa.sa_handler = sighup;    sigemptyset(&sa.sa_mask);    sigaddset(&sa.sa_mask, SIGTERM);    sa.sa_flags = 0;    if (sigaction(SIGHUP, &sa, NULL) < 0) {        syslog(LOG_ERR, "can't catch SIGHUP: %s", strerror(errno));        exit(1);    }    /*     * Proceed with the rest of the daemon.     */    /* ... */    exit(0);}

?

读书人网 >编程

热点推荐