Sunday, November 2, 2014

Unix Prog: Daemon Conventions

1. Daemon Conventions:
1) If the daemon uses a lock file, the file is usually stored in /var/run. And the name of file is usually name.pid, where name is the name of the daemon or the service.

 ubuntu@ip-172-31-23-227:~$ ls -lrt /var/run/*.pid  
 -rw-r--r-- 1 root root 4 Oct 11 20:56 /var/run/upstart-udev-bridge.pid  
 -rw-r--r-- 1 root root 4 Oct 11 20:56 /var/run/dhclient.eth0.pid  
 -rw-r--r-- 1 root root 4 Oct 11 20:56 /var/run/upstart-socket-bridge.pid  
 -rw-r--r-- 1 root root 4 Oct 11 20:56 /var/run/rsyslogd.pid  
 -rw-r--r-- 1 root root 4 Oct 11 20:56 /var/run/upstart-file-bridge.pid  
 -rw-r--r-- 1 root root 4 Oct 11 20:56 /var/run/acpid.pid  
 -rw-r--r-- 1 root root 4 Oct 11 20:56 /var/run/sshd.pid  
 -rw-r--r-- 1 root root 4 Oct 11 20:56 /var/run/crond.pid  
 -rw-r--r-- 1 root root 4 Oct 11 20:56 /var/run/atd.pid  

2) If the daemon supports configuration options, they are usually stored in /etc. The configuration file is named name.conf

 ubuntu@ip-172-31-23-227:~$ ls -lrt /etc/*.conf  
 -rw-r--r-- 1 root root 2584 Oct 10 2012 /etc/gai.conf  
 -rw-r--r-- 1 root root 2084 Apr 1 2013 /etc/sysctl.conf  
 -rw-r--r-- 1 root root 1245 Apr 18 2013 /etc/rsyslog.conf  
 -rw-r--r-- 1 root root  771 May 18 2013 /etc/insserv.conf  
 -rw-r----- 1 root fuse  280 May 24 2013 /etc/fuse.conf  
 ......  

3) the daemon process can be started from the command line, but they are usually started from one of the system initialization scripts .

4) If the daemon has a configuration file, the daemon reads it when it starts, but usually won't look at it again. If the admin want to change the config, he/she needs to restart the daemon.

2. Re-read config file example:
daemon.c:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
 #include<fcntl.h>  
 #include<syslog.h>  
 #include<errno.h>  
 #include<string.h>  
 #include<pthread.h>  
 #include<signal.h>  
   
 sigset_t mask;  
   
 int already_running(void)  
 {  
  // Code to lock the file and detect if the daemon process  
  // is already running  
  // ......  
  return 0;  
 }  
   
 void reread()  
 {  
  // Code to reread configuration file  
 }  
   
 void * thr_fn(void *arg)  
 {  
  int err, signo;  
   
  for(;;) {  
   // wait for signal coming  
   err = sigwait(&mask, &signo);  
   if(err != 0) {  
    syslog(LOG_ERR, "sigwait failed");  
    exit(1);  
   }  
   
   // Process signals  
   switch(signo) {  
   case SIGHUP:  
    printf("Re-reading configuration file");  
    reread();  
    break;  
   
   case SIGTERM:  
    printf("got SIGTERM, exiting");  
    exit(0);  
   
   default:  
    syslog(LOG_INFO, "unexpected signal %d\n", signo);  
   }  
  }  
   
  return(0);  
 }  
   
 void daemonize()  
 {  
  // code to make the process to become a daemon  
  // ......  
 }  
 int main(int argc, char* argv[])  
 {  
  int err;  
  pthread_t tid;  
  struct sigaction sa;  
   
  // Become a daemon  
  daemonize();  
   
  // Make sure only one 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) {  
   printf("sigaction error!\n");  
   exit(2);  
  }  
   
  // block all signals for main thread, so the newly created thread  
  // is responsible for handling signals  
  sigfillset(&mask);  
  if((err = pthread_sigmask(SIG_BLOCK, &mask, NULL)) != 0) {  
   printf("pthread_sigmask error!\n");  
   exit(3);  
  }  
   
  // Create a thread to handle SIGHUP AND SIGTERM  
  err = pthread_create(&tid, NULL, thr_fn, 0);  
  if(err != 0) {  
   printf("pthread_create error!\n");  
   exit(4);  
  }  
   
  sleep(5);  
   
  exit(0);  
 }  

shell:
The program launches a separate thread to help handle signals and re-read configuration if SIGHUP comes.
 ubuntu@ip-172-31-23-227:~$ kill -1 30893  
 ubuntu@ip-172-31-23-227:~$ Re-reading configuration file  
 [1]+ Done          ./daemon.out  
 ubuntu@ip-172-31-23-227:~$ ./daemon.out &  
 [1] 30895  
 ubuntu@ip-172-31-23-227:~$ kill -15 30895  
 ubuntu@ip-172-31-23-227:~$ got SIGTERM, exiting  
 [1]+ Done          ./daemon.out  

3. Re-read config without using multithreading
daemon.c:
 #include<stdio.h>  
 #include<stdlib.h>  
 #include<unistd.h>  
 #include<syslog.h>  
 #include<errno.h>  
 #include<string.h>  
 #include<signal.h>  
   
 sigset_t mask;  
   
 int already_running(void)  
 {  
  // Code to lock the file and detect if the daemon process  
  // is already running  
  // ......  
  return 0;  
 }  
   
 void reread()  
 {  
  // Code to reread configuration file  
 }  
   
 void daemonize()  
 {  
  // code to make the process to become a daemon  
  // ......  
 }  
   
 void sigterm(int signo)  
 {  
  printf("got SIGTERM: exiting");  
  exit(0);  
 }  
   
 void sighup(int signo)  
 {  
  printf("got SIGHUP: re-read config file");  
  reread();  
 }  
   
 int main(int argc, char* argv[])  
 {  
  int err;  
  struct sigaction sa;  
   
  // Become a daemon  
  daemonize();  
   
  // Make sure only one daemon is running  
  if(already_running()) {  
   syslog(LOG_ERR, "daemon already running!");  
   exit(1);  
  }  
   
  // Handle signals  
  sa.sa_handler = sigterm;  
  sigemptyset(&sa.sa_mask);  
  sigaddset(&sa.sa_mask, SIGHUP);  
  sa.sa_flags = 0;  
  if(sigaction(SIGTERM, &sa, NULL) < 0) {  
   printf("sigaction error!\n");  
   exit(2);  
  }  
   
  sa.sa_handler = sighup;  
  sigemptyset(&sa.sa_mask);  
  sigaddset(&sa.sa_mask, SIGTERM);  
  sa.sa_flags = 0;  
  if(sigaction(SIGHUP, &sa, NULL) < 0) {  
   printf("sigaction error!\n");  
   exit(2);  
  }  
   
  sleep(5);  
   
  exit(0);  
 }  

shell:
 ubuntu@ip-172-31-23-227:~$ kill -1 31808  
 ubuntu@ip-172-31-23-227:~$ got SIGHUP: re-read config file  
 [1]+ Done          ./daemon.out  
 ubuntu@ip-172-31-23-227:~$ ./daemon.out &  
 [1] 31809  
 ubuntu@ip-172-31-23-227:~$ kill -15 31809  
 ubuntu@ip-172-31-23-227:~$ got SIGTERM: exiting  
 [1]+ Done          ./daemon.out  

No comments:

Post a Comment