Ok, lets make stuff! Today, we will begin the construction of a basic, but working, example of a Linux daemon. Daemons are programs that work in the background, invisible, helping or hurting your machine … explaining the reason why they are called daemon’s (“nature spirits”). During this first part, we will make a program that runs on a timer. On the second part, we will make it run in the background as a daemon. Once we have constructed the final program, you can make him do background tasks as you please.
We will be building a timer in C today. I named my program “d_prog.c”. The goal will be to make a program that will make posts on your system log. We will make it so that messages are posted on startup, on regular timed intervals, and on exit. The system log is commonly located at /var/log/syslog. You can check if your program is working correctly by looking for your program’s output within that log. I will look for output of the program “d_prog”. Below is the basic setup.
#include <signal> // for dealing with SIGALRM
#include <stdio> // for use of printf()
#include <stdlib> // for EXIT_SUCCESS / EXIT_FAILURE
#include <sys/time.h> // for itimerval struct
#include <syslog.h> // for using the system log
int g_running = 0;
void setTimerAlarm ()
{
}
int main ()
{
g_running = 1;
setTimerAlarm ();
while(g_running); // run the program while g_running == 1
// for now, the program will run in an infinite loop
exit(EXIT_SUCCESS);
}
We will flesh out the details of the program using the above layout. main () will set up the environment and setTimerAlarm () will set up a timer that posts messages. I have written comments next to the header files that we must include so you will know why they are included.
In order for our timer to work, we definitely need more things.
itimerval struct (from sys/time.h)- This is a struct that can hold parameters needed to set up a timer. We will use this to set up our timer the way we want.
setitimer() (from sys/time.h) – We will use this function call to set up the timer. We will pass in the itimerval struct we made to make the timer work the way we want. Note: the timer made by this function works by sending us a signal called “SIGALRM”. Imagine your alarm clock yelling “SIGALRM!” It works just like that!
handleTimerAlarm() (we will make this function) – This function will handle the “SIGALRM” signal. Imagine your hand turning off the yelling alarm clock – it will work like that. We call the function signal(SIGALRM, handleTimerAlarm), from sys/time.h, to let the system know that handleTimerAlarm() will handle SIGALRM signals.
handleClose() (we will make this too)- This function will catch signals that are meant to close the program, like SIGTERM.
void handleTimerAlarm (int sig)
{
syslog (LOG_INFO, "dprog timer finished.\n");
}
void handleClose (int sig)
{
g_running = 0; // handling signals to close this program
// by setting g_running to 0 (stops the
// while () loop in main ())
}
void setTimerAlarm ()
{
struct itimerval timer;
timer.it_value.tv_sec = 2; // period til 1st interrupt
timer.it_value.tv_usec = 0;
timer.it_interval.tv_sec = 1; // period between following interrupts
timer.it_interval.tv_usec = 0;
signal (SIGALRM, handleTimerAlarm); // set handleTimerAlarm to handle SIGALRM - see setitimer
signal(SIGHUP, handleClose); // handleClose () will handle signals
signal(SIGTERM, handleClose); // that close this program.
signal(SIGINT, handleClose); //
signal(SIGQUIT, handleClose); //
setitimer (ITIMER_REAL, &timer, 0); // timer will send "SIGALRM" signal
}
Before we compile and run this program, lets add a few more lines to main() which will write an entry to the system log when the program begins and when it ends.
int main ()
{
g_running = 1;
openlog("d_prog", LOG_PID, LOG_DAEMON);
syslog(LOG_INFO, "d_prog begin.");
setTimerAlarm ();
while(g_running);
syslog(LOG_INFO, "d_prog end.\n");
closelog ();
exit(EXIT_SUCCESS);
}
Before you compile and run it, remember, that this program will run in an infinite loop, so be ready to hit Ctrl+C to end it. Ok! Now, lets compile and run it!
user@host-$ gcc d_prog.c -o d_prog
user@host-$ ./d_prog
Viewing the system log, you should see something like this near the end:
Mar 15 19:23:18 HOST-PC d_prog[5533]: d_prog begin.
Mar 15 19:23:20 HOST-PC d_prog[5533]: dprog timer finished.
Mar 15 19:23:22 HOST-PC d_prog[5533]: message repeated 2 times: [ dprog timer finished.]
Mar 15 19:23:22 HOST-PC d_prog[5533]: d_prog end.
As we can see, the program works as intended! Next time, we will work on turning this program into a daemon, however, in the meantime, have fun putting your timer to use in other projects!