Sunday, June 20, 2010

Create daemon process in C

#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>

#define LOCKFILE "/var/lock/PROCESSNAME"

#ifdef CREATE_PID_FILE
#define PIDFILE "/var/run/PROCESSNAME.pid"
#endif

void deamon (void)
{
  pid_t pid, sid;
#ifdef CREATE_PID_FILE
  pid_t child;
  FILE *pidfp = NULL;
#endif  
  int lockfd = -1;

  /* Create the lock file */
  lockfd = open (LOCKFILE, O_RDWR | O_CREAT | O_EXCL, 0640);
  if (-1 == lockfd)
  {
    syslog (LOG_ERR, "ERROR: Unable to create lock file [" LOCKFILE "] -> %s.", strerror(errno));
    if (EEXIST == errno)
    {
      syslog (LOG_ERR, "ERROR: Another instance of this process might be already running. "
              "Please kill that process or delete the lock file and try again.");
      exit (EXIT_FAILURE);
    }
  }
  
  /* Fork the child */
  pid = fork();
  if (-1 == pid)
  {
    syslog (LOG_ERR, "ERROR: Unable to fork the child process -> %s.", strerror(errno));

    /* On failure, delete the lock file */
    if (-1 == unlink (LOCKFILE))
    {
      syslog (LOG_ERR, "ERROR: Unable to delete the lock file [" LOCKFILE "] -> %s.", strerror(errno));
    }

    exit (EXIT_FAILURE);
  }

  /* Exit from the parent */
  if (0 != pid)
  {
    exit (EXIT_SUCCESS);
  }

#ifdef CREATE_PID_FILE
  child = getpid();

  pidfp = fopen (PIDFILE, "w");
  if (NULL == pidfp)
  {
    syslog (LOG_ERR, "ERROR: Unable to open the pid file [" PIDFILE "] -> %s", strerror(errno));
    
    /* On failure, delete the lock file */
    if (-1 == unlink (LOCKFILE))
    {
      syslog (LOG_ERR, "ERROR: Unable to delete the lock file [" LOCKFILE "] -> %s.", strerror(errno));
    }

    exit (EXIT_FAILURE);
  }

  fprintf (pidfp, "%d\n", child);
  fclose (pidfp);
#endif

  /* Make the child as the leader of the process */
  sid = setsid ();
  if ((pid_t)-1 == sid)
  {
    syslog (LOG_ERR, "ERROR: Unable to create new seesion -> %s", strerror(errno));

    /* On failure, delete the lock file and pid file */
    if (-1 == unlink (LOCKFILE))
    {
      syslog (LOG_ERR, "ERROR: Unable to delete the lock file [" LOCKFILE "] -> %s.", strerror(errno));
    }

#ifdef CREATE_PID_FILE
    if (-1 == unlink (PIDFILE))
    {
      syslog (LOG_ERR, "ERROR: Unable to delete the lock file [" PIDFILE "] -> %s.", strerror(errno));
    }
#endif

    exit (EXIT_FAILURE);
  }

  /* Set the calling process's file mode creation mask */
  umask (0);

  /*
   * Changing working directory to '/' to make sure that
   * the process does not depend on any mounted partition
   * execpt the root of the filesystem
   */
  if(-1 == chdir ("/"))
  {
    syslog (LOG_ERR, "ERROR: Unable to change the directory to \"/\" -> %s", strerror(errno));

    /* On failure, delete the lock file and pid file */
    if (-1 == unlink (LOCKFILE))
    {
      syslog (LOG_ERR, "ERROR: Unable to delete the lock file [" LOCKFILE "] -> %s.", strerror(errno));
    }

#ifdef CREATE_PID_FILE
    if (-1 == unlink (PIDFILE))
    {
      syslog (LOG_ERR, "ERROR: Unable to delete the lock file [" PIDFILE "] -> %s.", strerror(errno));
    }
#endif

    exit (EXIT_FAILURE);
  }

  /* Close standard input file descriptor */
  close (0);

  /* Redirect standard output and errror to /dev/null */
  freopen ( "/dev/null", "w", stdout);
  freopen ( "/dev/null", "w", stderr);

}

Reference: http://www.netzmafia.de/skripten/unix/linux-daemon-howto.html