13-Daemon Processes

Please indicate the source: http://blog.csdn.net/gaoxiangnumber1

Welcome to my github: https://github.com/gaoxiangnumber1

13.1 Introduction

  • Daemons are processes that live for a long time. They are often started when the system is bootstrapped and terminate only when the system is shut down. Because they don’t have a controlling terminal, we say that they run in the background.

13.2 Daemon Characteristics

  • The ps(1) command prints the status of various processes in the system. We execute ps -axj:
    -a shows the status of processes owned by others;
    -x shows processes that don’t have a controlling terminal;
    -j displays the job-related information(the session ID, process group ID, controlling terminal, and terminal process group ID).
    UID         PID    PPID     PGID      SID    TTY     CMD
    root           1        0       1        1   ?       /sbin/init
    root           2        0       0        0   ?       [kthreadd]
    root          26        2       0        0   ?       [sync_supers]
    root          35        2       0        0   ?       [kswapd0]
    root        256         2       0        0   ?       [jbd2/sda5-8]
    root        257         2       0        0   ?       [ext4-dio-unwrit]
    syslog      847         1    843      843    ?       rsyslogd -c5
    root       1037         1   1037     1037    ?       /usr/sbin/inetd
    root       1067         1   1067     1067    ?       cron
    daemon     1068         1   1068     1068    ?       atd
    root       8196         1   8196     8196    ?       /usr/sbin/sshd -D
    root      14596         2       0        0   ?       [flush-8:0]
    root      26464         1  26464    26464    ?       rpcbind -w
  • Anything with a parent process ID of 0 is usually a kernel process started as part of the system bootstrap procedure.(Exception is init: a user-level command started by the kernel at boot time). Kernel processes generally exist for the entire lifetime of the system. They run with superuser privileges and have no controlling terminal and no command line.
  • Linux uses kernel process kthreadd to create other kernel processes, so kthreadd is the parent of the other kernel daemons. Each kernel component that needs to perform work in a process context, but that isn’t invoked from the context of a user-level process, will usually have its own kernel daemon. On Linux:
    • The kswapd daemon is also known as the pageout daemon. It supports the virtual memory subsystem by writing dirty pages to disk slowly over time, so the pages can be reclaimed.
    • The flush daemon flushes dirty pages to disk when available memory reaches a configured minimum threshold. It also flushes dirty pages back to disk at regular intervals to decrease data loss in the event of a system failure. Several flush daemons can exist, one for each backing device.
    • The sync_supers daemon periodically flushes file system meta-data to disk.
    • The jbd daemon helps implement the journal in the ext4 file system.
  • Process 1 is usually init. It is a system daemon responsible for starting system services specific to various run levels. These services are usually implemented with the help of their own daemons.
    • The rpcbind daemon provides the service of mapping RPC(Remote Procedure Call) program numbers to network port numbers.
    • The rsyslogd daemon is available to any program to log system messages for an administrator. The messages may be printed on a console device and also written to a file.(the syslog facility in Section 13.4.)
    • The inetd daemon(Section 9.3) listens on the system’s network interfaces for incoming requests for various network servers.
    • The cron daemon executes commands at regularly scheduled dates and times. Numerous system administration tasks are handled by cron running programs at regularly intervals.
    • The atd daemon allows users to execute jobs at specified times, but it executes each job once only.
    • The sshd daemon provides secure remote login and execution facilities.
  • Most of daemons run with root privileges. None of daemons has a controlling terminal: the terminal name is set to a question mark. The kernel daemons are started without a controlling terminal. Most of the user-level daemons are process group leaders and session leaders, and are the only processes in their process group and session. The parent of the user-level daemons is the init process.

13.3 Coding Rules

  • Some basic rules to coding a daemon prevent unwanted interactions from happening.
    1. Call umask to set the file mode creation mask to a known value, usually 0. The inherited file mode creation mask could be set to deny certain permissions. If the daemon process creates files, it may want to set specific permissions. For example, if it 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. On the other hand, if the daemon calls library functions that result in files being created, then it might make sense to set the file mode create mask to a more restrictive value(such as 007), since the library functions might not allow the caller to specify the permissions through an explicit argument.
    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 the leader of a new session, (b) becomes the leader of a new process group, and (c) is disassociated from its controlling terminal.
    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 a specific location where they will do all their work. For example, a line printer spooling daemon might change its working directory to its 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 open_max function(Figure 2.17) or 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.
  • Figure 13.1 shows a function that can be called from a program that wants to initialize itself as a daemon.

  • If 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 -efj
UID PID     PPID    PGID    SID     TTY CMD
sar     13800   1       13799   13799   ?       ./a.out
$ ps -efj | grep 13799
sar     13800   1       13799   13799   ?       ./a.out
  • We can use ps to verify that no active process exists with ID 13799. This means that our daemon is in an orphaned process group(Section 9.10) and is not a session leader and, therefore, 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.

13.4 Error Logging

  • One problem with daemon is how to handle error messages. It can’t simply write to standard error, since it shouldn’t have a controlling terminal. Most daemons use syslog facility. Figure 13.2 illustrates its structure.

  • Three ways to generate log messages:
    1. Kernel routines can call the log function. These messages can be read by any user process that opens and reads the /dev/klog device.
    2. Most user processes(daemons) call the syslog(3) function to generate log messages. This causes the message to be sent to the UNIX domain datagram socket /dev/log.
    3. A user process on this host, or on some other host that is connected to this host by a TCP/IP network, can send log messages to UDP port 514. The syslog function never generates these UDP datagrams: they require explicit network programming by the process generating the log message.
  • Normally, the syslogd daemon reads all three forms of log messages. On start-up, this daemon reads a configuration file, usually /etc/syslog.conf, which determines where different classes of messages are to be sent. For example, urgent messages can be sent to the system administrator(if logged in) and printed on the console, whereas warnings may be logged to a file.
  • Our interface to this facility is through the syslog function.
#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
  • Calling openlog is optional. If it’s not called, the first time syslog is called, openlog is called automatically.
  • Calling openlog lets us specify an ident that is added to each log message. This is normally the name of the program(e.g. cron, inetd).
    The option argument is a bit-mask specifying various options. Figure 13.3 describes the available options.
    The facility argument is taken from Figure 13.4. The reason for the facility argument is to let the configuration file specify that messages from different facilities are to be handled differently. If we don’t call openlog, or if we call it with a facility of 0, we can still specify the facility as part of the priority argument to syslog.

  • Calling closelog is also optional: it only closes the descriptor that was being used to communicate with the syslogd daemon
  • void syslog(int priority, const char *format, ...);
    We call syslog to generate a log message.
    The priority argument is a combination of the facility(Figure 13.4) and a level(Figure 13.5). These levels are ordered by priority, from highest to lowest.
    The format argument and any remaining arguments are passed to the vsprintf function for formatting. Any occurrences of the characters %m in format are first replaced with the error message string(strerror) corresponding to the value of errno.

  • int setlogmask(int maskpri);
    The setlogmask function can be used to set the log priority mask for the process. This function returns the previous mask. When the log priority mask is set, messages are not logged unless their priority is set in the log priority mask. Attempts to set the log priority mask to 0 will have no effect.
  • In a (hypothetical) line printer spooler daemon, you might encounter the sequence
openlog("lpd", LOG_PID, LOG_LPR);
syslog(LOG_ERR, "open error for %s: %m", filename);
  • The first call sets the ident string to the program name, specifies that the process ID should always be printed, and sets the default facility to the line printer system.
  • The call to syslog specifies an error condition and a message string.
  • If we had not called openlog, the second call could have been
    syslog(LOG_ERR | LOG_LPR, "open error for %s: %m", filename);
    We specify the priority argument as a combination of a level and a facility.
#include <syslog.h>
#include <stdarg.h>
void vsyslog(int priority, const char *format, va_list arg);
  • vsyslog handles variable argument lists. To make its declaration visible to your application, you need to define an additional symbol(__USE_BSD on Linux). Most syslogd implementations will queue messages for a short time. If a duplicate message arrives during this period, the syslog daemon will not write it to the log. Instead, the daemon prints a message similar to “last message repeated N times.”

13.5 Single-Instance Daemons

  • Some daemons are implemented so that only a single copy of the daemon should be running at a time for proper operation. Such a daemon might need exclusive access to a device. For the cron daemon, if multiple instances were running, each copy might try to start a single scheduled operation, resulting in duplicate operations and probably an error.
  • If the daemon needs to access a device, the device driver will sometimes prevent multiple attempts to open the corresponding device node in /dev. This restricts us to one copy of the daemon running at a time. If no such device is available, we need to do the work ourselves.
  • The file- and record-locking(Section 14.3) mechanism provides the basis for one way to ensure that only one copy of a daemon is running. If each daemon creates a file with a fixed name and places a write lock on the entire file, only one such write lock will be allowed to be created. Successive attempts to create write locks will fail, serving as an indication to successive copies of the daemon that another instance is already running.
  • File and record locking provides a convenient mutual-exclusion mechanism. If the daemon obtains a write-lock on an entire file, the lock will be removed automatically if the daemon exits. This simplifies recovery, eliminating the need for us to clean up from the previous instance of the daemon.

  • The function shown in Figure 13.6 illustrates the use of file and record locking to ensure that only one copy of a daemon is running.
  • Each copy of the daemon will try to create a file and write its process ID in the file. This will allow administrators to identify the process easily. If the file is already locked, the lockfile function will fail with errno set to EACCES or EAGAIN, so we return 1, indicating that the daemon is already running. Otherwise, we truncate the file, write our process ID to it, and return 0.
  • We need to truncate the file, because the previous instance of the daemon might have had a process ID larger than ours, with a larger string length. Truncating the file prevents data from the previous daemon appearing as if it applies to the current daemon.

13.6 Daemon Conventions

  • Several conventions are followed by daemons in the UNIX System.
    • If the daemon uses a lock file, the file is usually stored in /var/run. The daemon might need superuser permissions to create a file here. The name of the file is usually name.pid, where name is the name of the daemon or the service.
    • If the daemon supports configuration options, they are usually stored in /etc. The configuration file is named name.conf, where name is the name of the daemon or the name of the service.
    • Daemons can be started from the command line, but they are usually started from one of the system initialization scripts(/etc/rc* or /etc/init.d/*). If the daemon should be restarted automatically when it exits, we can arrange for init to restart it if we include a re-spawn entry for it in /etc/inittab(System V style init command).
    • If a daemon has a configuration file, the daemon reads the file when it starts, but usually won’t look at it again. If an administrator changes the configuration, the daemon would need to be stopped and restarted to account for the configuration changes. To avoid this, some daemons will catch SIGHUP and reread their configuration files when they receive the signal. Since they aren’t associated with terminals and are either session leaders without controlling terminals or members of orphaned process groups, daemons have no reason to expect to receive SIGHUP. Thus they can safely reuse it.

  • The program shown in Figure 13.7 shows one way a daemon can reread its configuration file.
  • We call daemonize(Figure 13.1) to initialize the daemon. When it returns, we call already_running(Figure 13.6) to ensure that only one copy of the daemon is running. At this point, SIGHUP is still ignored, so we need to reset the disposition to the default behavior; otherwise, the thread calling sigwait may never see the signal.
  • We block all signals(recommended for multithreaded programs) and create a thread to handle signals. The thread’s only job is to wait for SIGHUP and SIGTERM.
    1. When receives SIGHUP, the thread calls reread to reread its configuration file.
    2. When receives SIGTERM, the thread logs a message and exits.
  • Figure 10.1: The default action for SIGHUP and SIGTERM is to terminate the process. Because we block these signals, the daemon will not die when one of them is sent to the process. Instead, the thread calling sigwait will return with an indication that the signal has been received.
  • Not all daemons are multithreaded. The program in Figure 13.8 shows how a single- threaded daemon can catch SIGHUP and reread its configuration file.

  • After initializing the daemon, we install signal handlers for SIGHUP and SIGTERM. We can either place the reread logic in the signal handler or just set a flag in the handler and have the main thread of the daemon do all the work instead.

13.7 Client–Server Model

  • A common use for a daemon process is as a server process. A server is a process that waits for a client to contact it, requesting some type of service. In Figure 13.2, we can call the syslogd process a server that has messages sent to it by user processes(clients) using a UNIX domain datagram socket. The service being provided by the syslogd server is the logging of an error message.
  • It is common for servers to fork and exec another program to provide service to a client. These servers often manage multiple file descriptors.
    1. At best, it would be careless to leave these file descriptors open in the child process, because they probably won’t be used in the program executed by the child, especially if the program is unrelated to the server.
    2. At worst, leaving them open could pose a security problem. The program executed could do something malicious to gain access to unauthorized information.
  • One solution is to set the close-on-exec flag for all file descriptors that the executed program won’t need. Figure 13.9 shows a function that we can use in a server process to do this.

13.8 Summary

Please indicate the source: http://blog.csdn.net/gaoxiangnumber1

Welcome to my github: https://github.com/gaoxiangnumber1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值