zoukankan      html  css  js  c++  java
  • apue2 阅读笔记第十三章

    1. 编写规则
    Some basic rules to coding a daemon prevent unwanted interactions from happening. We state these rules and then show a function, daemonize, that implements them.
    1. The first thing to do is call umask to set the file mode creation mask to 0. The file mode creation mask that's inherited could be set to deny certain permissions. If the daemon process is going to create files, it may want to set specific permissions. For example, if it specifically creates files with group-read and group-write enabled, a file mode creation mask that turns off either of these permissions would undo its efforts.

    2. Call fork and have the parent exit. This does several things. First, if the daemon was started as a simple shell command, having the parent terminate makes the shell think that the command is done. Second, the child inherits the process group ID of the parent but gets a new process ID, so we're guaranteed that the child is not a process group leader. This is a prerequisite for the call to setsid that is done next.

    3. Call setsid to create a new session. The three steps listed in Section 9.5 occur. The process (a) becomes a session leader of a new session, (b) becomes the process group leader of a new process group, and (c) has no controlling terminal.

      Under System Vbased systems, some people recommend calling fork again at this point and having the parent terminate. The second child continues as the daemon. This guarantees that the daemon is not a session leader, which prevents it from acquiring a controlling terminal under the System V rules (Section 9.6). Alternatively, to avoid acquiring a controlling terminal, be sure to specify O_NOCTTY whenever opening a terminal device.

    4. Change the current working directory to the root directory. The current working directory inherited from the parent could be on a mounted file system. Since daemons normally exist until the system is rebooted, if the daemon stays on a mounted file system, that file system cannot be unmounted.

      Alternatively, some daemons might change the current working directory to some specific location, where they will do all their work. For example, line printer spooling daemons often change to their spool directory.

    5. Unneeded file descriptors should be closed. This prevents the daemon from holding open any descriptors that it may have inherited from its parent (which could be a shell or some other process). We can use our open_max function (Figure 2.16) or the getrlimit function (Section 7.11) to determine the highest descriptor and close all descriptors up to that value.

    6. Some daemons open file descriptors 0, 1, and 2 to /dev/null so that any library routines that try to read from standard input or write to standard output or standard error will have no effect. Since the daemon is not associated with a terminal device, there is nowhere for output to be displayed; nor is there anywhere to receive input from an interactive user. Even if the daemon was started from an interactive session, the daemon runs in the background, and the login session can terminate without affecting the daemon. If other users log in on the same terminal device, we wouldn't want output from the daemon showing up on the terminal, and the users wouldn't expect their input to be read by the daemon.

    Example

    Figure 13.1 shows a function that can be called from a program that wants to initialize itself as a daemon.

    If the daemonize function is called from a main program that then goes to sleep, we can check the status of the daemon with the ps command:

       $ ./a.out
       $ ps -axj
        PPID   PID   PGID   SID TTY TPGID UID   COMMAND
           1  3346   3345  3345 ?      -1 501   ./a.out
       $ ps -axj |  grep 3345
           1  3346   3345  3345 ?      -1 501   ./a.out

    We can also use ps to verify that no active process exists with ID 3345. This means that our daemon is in an orphaned process group (Section 9.10) and is not a session leader and thus has no chance of allocating a controlling terminal. This is a result of performing the second fork in the daemonize function. We can see that our daemon has been initialized correctly.

    示例代码:

    #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");
        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. 错误处理
    QQ截图未命名

  • 相关阅读:
    自定义排序方式
    Ajax 调用(传值)一般处理程序(.ashx)
    把一个文件夹下的所有excel添加到datatable
    list比较交集
    禁用未登录通过连接下载文件
    加密方式
    使用response.write输出excel
    linux安装OpenCV以及windows安装numpy、cv2等python2.7模块
    哈希长度扩展攻击(Hash Length Extension Attack)利用工具hexpand安装使用方法
    yafu安装使用方法以及mismatched parens解决方法
  • 原文地址:https://www.cnblogs.com/liujiahi/p/2277360.html
Copyright © 2011-2022 走看看