Sunday, November 2, 2014

Unix Prog: Daemon Process Basic

1. Daemon Process

1) Process that live for a long time. They are often started when the system is bootstrapped and terminate only when the system is shut down.

2) The Daemon Process doesn't have controlling terminal

3) Typical Daemon Process:

init: system daemon responsible for starting system services specific to various run levels.
cron: daemon executes commands at specified dates and times.

4) Most daemons run with superuser privilege(a user ID of 0).Their terminal foreground process group is -1. All user-level daemons are process group leaders and session leaders and are the only processes in the process group and session. Note that the parent of most of these daemons is the init process.

2. Daemon Process Establishment Rules
1) Call umask to set the file mode creation mask to 0. Since daemon process may want to create files, and may want assign some permission to the new file. Then umask need to be called to set mask to 0 to enable all permissions.

2) Call fork and have the parent exit. The child process inherits the process group id of the parent but have its own process id. And the child process is not the process group leader

3) Call setsid to create a new session. So the process will become a session leader of a new session, become the process group leader of a new process group and has no controlling terminal.

4) Change the current working directory to root directory. Since for some daemon processes they are located at mounted file system, and daemon process will not terminate until the system shut down, in which case the mounted system will never be unmounted.

5) Unneeded file descriptors should be closed. It prevents the daemon from holding open any descriptors that it may have inherited from its parent.

6) Open file descriptors 0, 1, and 2 to /dev/null, since daemon process doesn't have the controlling terminal.

2. Establish Daemon Process
daemon.c:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
 #include<syslog.h>  
 #include<fcntl.h>  
 #include<sys/resource.h>  
 #include<signal.h>  
   
 int main(int argc, char* argv[])  
 {  
  int i, fd0, fd1, fd2;  
  pid_t pid;  
  struct rlimit rl;  
  struct sigaction sa;  
   
  // Clear file creation mask  
  umask(0);  
   
  // Get max number of file descriptors  
  if(getrlimit(RLIMIT_NOFILE, &rl) < 0) {  
   printf("getrlimit error!\n");  
   exit(1);  
  }  
   
  // Become a session leader to lose controlling terminal  
  if((pid = fork()) < 0) {  
   printf("fork error!\n");  
   exit(2);  
  }  
  else if(pid != 0) { // parent  
   exit(0);  
  }  
   
  setsid();  
   
  // Ensure future opens won't allocate controlling terminals  
  sa.sa_handler = SIG_IGN;  
  sigemptyset(&sa.sa_mask);  
  sa.sa_flags = 0;  
  if(sigaction(SIGHUP, &sa, NULL) < 0) {  
   printf("sigaction error!\n");  
   exit(3);  
  }  
  if((pid = fork()) < 0) {  
   printf("fork error!\n");  
   exit(2);  
  }  
  else if(pid != 0) { // parent  
   exit(0);  
  }  
   
  // Change the current working directory to root  
  if(chdir("/") < 0) {  
   printf("chdir error!\n");  
   exit(3);  
  }  
   
  // 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);  
   
  // Attache file descriptors 0 1 2 to /dev/null  
  fd0 = open("/dev/null", O_RDWR);  
  fd1 = dup(0);  
  fd2 = dup(0);  
   
  // Initialize the log file  
  openlog(argv[1], LOG_CONS, LOG_DAEMON);  
  if(fd0 != 0 || fd1 != 1 || fd2 != 2) {  
   syslog(LOG_ERR, "unexpected file descriptors %d %d %d", fd0, fd1, fd2);  
   exit(4);  
  }  
   
  exit(0);  
 }  

No comments:

Post a Comment