Thursday, July 18, 2013

How to Code UNIX Daemons - Part One

In continuing with my time-honored tradition in bringing you the absolute latest in small code samples, here's an example of how to write a UNIX daemon. For the unfamiliar, daemons are background backgrounds that are typically started when the system starts up and have one specific task - typically ranging from serving web pages (the Apache web server, https, is a daemon, as is sshd, which listens for ssh requests on remote servers you can ssh into).

So, without further ado, here's the code sample:

 #include <unistd.h>  
 #include <fcntl.h>  
 #include <stdlib.h>  
 #include <string.h>  
 #include <stdio.h>  
 #include <syslog.h>  
 #include <sys/types.h>  
 #include <sys/stat.h>  
 int main(int argc, char *argv[]) {  
   // Set our uid to root so we get root permissions.  
   setuid(0);  
   // Fork off.  
   pid_t pid;  
   int current_arg = 0;  
   pid = fork();  
   if (pid < 0) {  
     exit(EXIT_FAILURE);  
   }  
   if (pid > 0) {  
     exit(EXIT_SUCCESS);  
   }  
   umask(0);  
   // Open a syslog so we can post messages, as daemons shouldn't access  
   // stdout.  
   openlog(argv[current_arg], LOG_NOWAIT|LOG_PID, LOG_USER);  
   syslog(LOG_NOTICE, "Successfully started daemon\n");  
   // Create a new process group.  
   pid_t sid;  
   sid = setsid();  
   if (sid < 0) {  
     syslog(LOG_ERR, "Could not create process group\n");  
     exit(EXIT_FAILURE);  
   }  
   // Set our working directory to / so we know where we're writing files  
   // from. Also good practice.  
   if ((chdir("/")) < 0) {  
     syslog(LOG_ERR, "Could not change working directory to /\n");  
     exit(EXIT_FAILURE);  
   }  
   // Close the standard streams like stdout so we're not attached to the  
   // console (and thus killable with Control-C).  
   close(STDIN_FILENO);  
   close(STDOUT_FILENO);  
   close(STDERR_FILENO);  
   // Now mimic some daemon activity. A real daemon would actually do  
   // something here, such as monitor CPU temperature or something...  
   do {  
     syslog(LOG_NOTICE, "Sending a message\n");  
     sleep(10);  
   } while (1);  
   // Close our access to the syslog.  
   closelog();  
 }  

Put this into a text file, and then compile it with your C compiler. You then go into the terminal, run your program, and… it exits immediately - what gives?

The truth is, something did happen - you just don't notice. Thanks to our fork() call, we split off from the main process and run in the background.

In the second part of this series, we'll write a more complicated daemon program. See you later!

No comments: