[转] Linux Daemon Writing HOWTO
Linux Daemon Writing HOWTO
Devin Watson
v1.0, May 2004
This document shows how to write a daemon in Linux using GCC. Knowledge of Linux and a familiarity with C are necessary to use this document. This HOWTO is Copyright by Devin Watson, under the terms of the BSD License.
1. Introduction: What is a Daemon?
2. Getting Started
3. Planning Your Daemon
- 3.1 What Is It Going To Do?
- 3.2 How Much Interaction?
4. Basic Daemon Structure
- 4.1 Forking The Parent Process
- 4.2 Changing The File Mode Mask (Umask)
- 4.3 Opening Logs For Writing
- 4.4 Creating a Unique Session ID (SID)
- 4.5 Changing The Working Directory
- 4.6 Closing Standard File Descriptors
5. Writing the Daemon Code
- 5.1 Initialization
- 5.2 The Big Loop
6. Putting It All Together
- 6.1 Complete Sample
1. Introduction: What is a Daemon?
A daemon (or service) is a background process that is designed to run autonomously,with little or not user intervention. The Apache web server http daemon (httpd) is one such example of a daemon. It waits in the background listening on specific ports, and serves up pages or processes scripts, based on the type of request.
Creating a daemon in Linux uses a specific set of rules in a given order. Knowing how they work will help you understand how daemons operate in userland Linux, but can operate with calls to the kernel also. In fact, a few daemons interface with kernel modules that work with hardware devices, such as external controller boards, printers,and PDAs. They are one of the fundamental building blocks in Linux that give it incredible flexibility and power.
Throughout this HOWTO, a very simple daemon will be built in C. As we go along, more code will be added, showing the proper order of execution required to get a daemon up and running.
2. Getting Started
First off, you'll need the following packages installed on your Linux machine to develop daemons, specifically:
GCC 3.2.2 or higherLinux Development headers and libraries
If your system does not already have these installed (not likely, but check anyway), you'll need them to develop the examples in this HOWTO. To find out what version of GCC you have installed, use:
gcc --version
3. Planning Your Daemon
3.1 What Is It Going To Do?
A daemon should do one thing, and do it well. That one thing may be as complex as managing hundreds of mailboxes on multiple domains, or as simple as writing a report and calling sendmail to mail it out to an admin.
In any case, you should have a good plan going in what the daemon should do. If it is going to interoperate with some other daemons that you may or may not be writing, this is something else to consider as well.
3.2 How Much Interaction?
Daemons should never have direct communication with a user through a terminal. In fact, a daemon shouldn't communicate directly with a user at all. All communication should pass through some sort of interface (which you may or may not have to write), which can be as complex as a GTK+ GUI, or as simple as a signal set.
4. Basic Daemon Structure
When a daemon starts up, it has to do some low-level housework to get itself ready for its real job. This involves a few steps:
- Fork off the parent process
- Change file mode mask (umask)
- Open any logs for writing
- Create a unique Session ID (SID)
- Change the current working directory to a safe place
- Close standard file descriptors
- Enter actual daemon code
4.1 Forking The Parent Process
A daemon is started either by the system itself or a user in a terminal or script. When it does start, the process is just like any other executable on the system. To make it truly autonomous, a child process must be created where the actual code is executed. This is known as forking, and it uses the fork() function:
pid_t pid; /* Fork off the parent process */
pid = fork();
if (pid < 0) {
exit(EXIT_FAILURE);
}
/* If we got a good PID, then
we can exit the parent process. */
if (pid > 0) {
exit(EXIT_SUCCESS);
}
Notice the error check right after the call to fork(). When writing a daemon, you will have to code as defensively as possible. In fact, a good percentage of the total code in a daemon consists of nothing but error checking.
The fork() function returns either the process id (PID) of the child process (not equal to zero), or -1 on failure. If the process cannot fork a child, then the daemon should terminate right here.
If the PID returned from fork() did succeed, the parent process must exit gracefully. This may seem strange to anyone who hasn't seen it, but by forking, the child process continues the execution from here on out in the code.
4.2 Changing The File Mode Mask (Umask)
In order to write to any files (including logs) created by the daemon, the file mode mask (umask) must be changed to ensure that they can be written to or read from properly. This is similar to running umask from the command line, but we do it programmatically here. We can use the umask() function to accomplish this:
pid_t pid, sid; /* Fork off the parent process */
pid = fork();
if (pid < 0) {
/* Log failure (use syslog if possible) */
exit(EXIT_FAILURE);
}
/* If we got a good PID, then
we can exit the parent process. */
if (pid > 0) {
exit(EXIT_SUCCESS);
} /* Change the file mode mask */
umask(0);
By setting the umask to 0, we will have full access to the files generated by the daemon. Even if you aren't planning on using any files, it is a good idea to set the umask here anyway, just in case you will be accessing files on the filesystem.
4.3 Opening Logs For Writing
This part is optional, but it is recommended that you open a log file somewhere in the system for writing. This may be the only place you can look for debug information about your daemon.
4.4 Creating a Unique Session ID (SID)
From here, the child process must get a unique SID from the kernel in order to operate. Otherwise, the child process becomes an orphan in the system. The pid_t type, declared in the previous section, is also used to create a new SID for the child process:
pid_t pid, sid; /* Fork off the parent process */
pid = fork();
if (pid < 0) {
exit(EXIT_FAILURE);
}
/* If we got a good PID, then
we can exit the parent process. */
if (pid > 0) {
exit(EXIT_SUCCESS);
} /* Change the file mode mask */
umask(0); /* Open any logs here */ /* Create a new SID for the child process */
sid = setsid();
if (sid < 0) {
/* Log any failure */
exit(EXIT_FAILURE);
}
Again, the setsid() function has the same return type as fork(). We can apply the same error-checking routine here to see if the function created the SID for the child process.
4.5 Changing The Working Directory
The current working directory should be changed to some place that is guaranteed to always be there. Since many Linux distributions do not completely follow the Linux Filesystem Hierarchy standard, the only directory that is guaranteed to be there is the root (/). We can do this using the chdir() function:
pid_t pid, sid; /* Fork off the parent process */
pid = fork();
if (pid < 0) {
exit(EXIT_FAILURE);
}
/* If we got a good PID, then
we can exit the parent process. */
if (pid > 0) {
exit(EXIT_SUCCESS);
} /* Change the file mode mask */
umask(0); /* Open any logs here */ /* Create a new SID for the child process */
sid = setsid();
if (sid < 0) {
/* Log any failure here */
exit(EXIT_FAILURE);
} /* Change the current working directory */
if ((chdir("/")) < 0) {
/* Log any failure here */
exit(EXIT_FAILURE);
}
Once again, you can see the defensive coding taking place. The chdir() function returns -1 on failure, so be sure to check for that after changing to the root directory within the daemon.
4.6 Closing Standard File Descriptors
One of the last steps in setting up a daemon is closing out the standard file descriptors (STDIN, STDOUT, STDERR). Since a daemon cannot use the terminal, these file descriptors are redundant and a potential security hazard.
The close() function can handle this for us:
pid_t pid, sid; /* Fork off the parent process */
pid = fork();
if (pid < 0) {
exit(EXIT_FAILURE);
}
/* If we got a good PID, then
we can exit the parent process. */
if (pid > 0) {
exit(EXIT_SUCCESS);
} /* Change the file mode mask */
umask(0); /* Open any logs here */ /* Create a new SID for the child process */
sid = setsid();
if (sid < 0) {
/* Log any failure here */
exit(EXIT_FAILURE);
} /* Change the current working directory */
if ((chdir("/")) < 0) {
/* Log any failure here */
exit(EXIT_FAILURE);
} /* Close out the standard file descriptors */
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
It's a good idea to stick with the constants defined for the file descriptors, for the greatest portability between system versions.
5. Writing the Daemon Code
5.1 Initialization
At this point, you have basically told Linux that you're a daemon, so now it's time to write the actual daemon code. Initialization is the first step here. Since there can be a multitude of different functions that can be called here to set up your daemon's task, I won't go too deep into here.
The big point here is that, when initializing anything in a daemon, the same defensive coding guidelines apply here. Be as verbose as possible when writing either to the syslog or your own logs. Debugging a daemon can be quite difficult when there isn't enough information available as to the status of the daemon.
5.2 The Big Loop
A daemon's main code is typically inside of an infinite loop. Technically, it isn't an infinite loop, but it is structured as one:
pid_t pid, sid; /* Fork off the parent process */
pid = fork();
if (pid < 0) {
exit(EXIT_FAILURE);
}
/* If we got a good PID, then
we can exit the parent process. */
if (pid > 0) {
exit(EXIT_SUCCESS);
} /* Change the file mode mask */
umask(0); /* Open any logs here */ /* Create a new SID for the child process */
sid = setsid();
if (sid < 0) {
/* Log any failures here */
exit(EXIT_FAILURE);
} /* Change the current working directory */
if ((chdir("/")) < 0) {
/* Log any failures here */
exit(EXIT_FAILURE);
} /* Close out the standard file descriptors */
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO); /* Daemon-specific initialization goes here */ /* The Big Loop */
while (1) {
/* Do some task here ... */
sleep(30); /* wait 30 seconds */
}
This typical loop is usually a while loop that has an infinite terminating condition, with a call to sleep in there to make it run at specified intervals.
Think of it like a heartbeat: when your heart beats, it performs a few tasks, then waits until the next beat takes place. Many daemons follow this same methodology.
6. Putting It All Together
6.1 Complete Sample
Listed below is a complete sample daemon that shows all of the steps necessary for setup and execution. To run this, simply compile using gcc, and start execution from the command line. To terminate, use the kill command after finding its PID.
I've also put in the correct include statements for interfacing with the syslog, which is recommended at the very least for sending start/stop/pause/die log statements, in addition to using your own logs with the fopen()/fwrite()/fclose() function calls.
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <syslog.h>
#include <string.h> int main(void) { /* Our process ID and Session ID */
pid_t pid, sid; /* Fork off the parent process */
pid = fork();
if (pid < 0) {
exit(EXIT_FAILURE);
}
/* If we got a good PID, then
we can exit the parent process. */
if (pid > 0) {
exit(EXIT_SUCCESS);
} /* Change the file mode mask */
umask(0); /* Open any logs here */ /* Create a new SID for the child process */
sid = setsid();
if (sid < 0) {
/* Log the failure */
exit(EXIT_FAILURE);
} /* Change the current working directory */
if ((chdir("/")) < 0) {
/* Log the failure */
exit(EXIT_FAILURE);
} /* Close out the standard file descriptors */
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO); /* Daemon-specific initialization goes here */ /* The Big Loop */
while (1) {
/* Do some task here ... */ sleep(30); /* wait 30 seconds */
}
exit(EXIT_SUCCESS);
}
From here, you can use this skeleton to write your own daemons. Be sure to add in your own logging (or use the syslog facility), and code defensively, code defensively, code defensively!
转载自 http://www.netzmafia.de/skripten/unix/linux-daemon-howto.html
[转] Linux Daemon Writing HOWTO的更多相关文章
- 创建 SysV 风格的 linux daemon 程序
本文介绍如何使用 C 语言创建 Linux 系统中 SysV 风格的 daemon 程序.注意:这是一种旧式的 daemon 程序写法,进入 systemd 时代后是不需要通过这样的方式创建 daem ...
- Linux Daemon 类程序
1.后台daemon程序(精灵程序) 在Linux中专门提供了一个函数来完成这个daemon化的过程,这个函数的原型如下 int daemon (int __nochdir, int __noclos ...
- python to be linux daemon
所需第三方库:python-daemon[https://pypi.python.org/pypi/python-daemon/] 使用方式: python linux_service.py star ...
- Linux TC流量控制HOWTO中文版
<本文摘自Linux的高级路由和流量控制HOWTO中文版 第9章节>网人郭工进行再次编译: 利用队列,我们可以控制数据发送的方式.记住我们只能对发送数据进行控制(或称为整形).其实,我们无 ...
- Creating a Linux Daemon (service) in Delphi
With the introduction of the Linux target for Delphi, a wide range of possibilities are opened up to ...
- linux daemon
参考 鸟哥的私房菜 http://linux.vbird.org/linux_basic/0560daemons.php
- Linux daemon与service 学习笔记
service 常驻在内存中的进程,且可以提供一些系统或网络功能,就是服务. daemon service的提供需要进程的运行,所以实现service的程序我们称为daemon. eg: 实现 ...
- Linux Daemon进程
模型 创建孤儿进程 fork() 创建新的会话 setid() 改变当前目录为根目录chdir() 重设文件权限掩码umask() 关闭文件描述符close() 创建孤儿进程 创建孤儿进程只需要将父进 ...
- 一个简单的 Web 服务器 [未完成]
最近学习C++,linux和网络编程,想做个小(mini)项目. 就去搜索引擎, 开源中国, Sourceforge上找http server的项目. 好吧,也去了知乎. 知乎上程序员氛围好, ...
随机推荐
- 在循环中使用鼠标悬停时表示当前悬停选中,传入this关键字即可
在前端循环中使用鼠标悬停事件 <div class="message-widget contact-widget"> <!-- Message --> {% ...
- C#之数据类型学习
C#有以下几种数据类型: 数据类型案例以及取值范围: 界面: 选择int时: 选中long时: 选中float时: 选中double时: 选中decimal时: 选中string时: 选中char时: ...
- js 利用数组实现类似于asp中的数据字典
---恢复内容开始--- 首先声明一个数组 var dictNew=new Array; var key; var value; for (var i = 0; i <50; i++) { // ...
- RTOS双向链表数据结构
在学习RTOS操作系统时,在任务优先级设置时用到了双向链表,说实话数据结构的东西只是停留在大学上课阶段,并未实践过,在操作系统中看得云里雾里,遂将其单独拿来了进行了一下思考,经过一个上午的摸索逐渐领会 ...
- 关于ORACLE的字符窜存储(未完善,欢迎补充)
oracle中常见的用于存储字符串的数据类型有: 数据类型 是否定长 最多存储数 效率排行 备注 是否oracle特有 英文占位 中文占位 char 是 2000 比VARCHAR2稍高 char的长 ...
- JEECG(二) JEECG框架下调用webservice java springmvc maven 调用 webservice
JEECG系列教程二 如何在JEECG框架下使用webservice 本文所使用的webservice是c#开发的 其实无论是什么语言开发的webservice用法都一样 java springmvc ...
- c# 输入多个数字,当输入不是数字时显示出刚输入的所有数并按降序
输入多个数字,当输入不是数字时显示出刚输入的所有数并按降序 class Program { static void Main(string[] args) { //定于一个集合 List<int ...
- 《Python黑帽子:黑客与渗透测试编程之道》 Web攻击
Web的套接字函数库:urllib2 一开始以urllib2.py命名脚本,在Sublime Text中运行会出错,纠错后发现是重名了,改过来就好: #!/usr/bin/python #coding ...
- django 使用celery 实现异步任务
celery 情景:用户发起request,并等待response返回.在本些views中,可能需要执行一段耗时的程序,那么用户就会等待很长时间,造成不好的用户体验,比如发送邮件.手机验证码等. 使用 ...
- jvm内存结构(二)(栈的变化,机器指令的格式/执行模式)
栈的结构: <Java虚拟机原理图解>4.JVM机器指令集 局部变量表: 方法执行时,虚拟机会把字节码中方法数据区的code类型的属性中的局部变量放到栈的局部变量表中. 操作栈: jvm指 ...