/* 
 * Rumpfprogramm fuer einen Daemon-Prozess
 */

#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>

/*** user ID of daemon - please change */
#define UID 500
/*** group ID of daemon  - please change */
#define GID 500
/*** location of PID file  - please change */
#define PIDFILE "/var/run/dummy"

int fd0, fd1, fd2;    /* file descriptors for standard files */
struct sigaction sa;  /* for signal handler */


/* generate PID file */
void make_pidfile(char *pidfilename)
  {
  FILE    *pf;         /* We use a FILE to use fscanf */
  int      fd;         /* File descriptor for pid file */
  int      fpid;       /* PID found in existing pidfile */
  int      opid;       /* Our PID */

  pf = fopen(pidfilename, "r");
  if (pf)
    {
    if (fscanf(pf, "%d", &fpid))
      {
      /* We've gotten a PID out of the file.  Is it running? */
      if (!(kill(fpid, 0) == -1 && errno == ESRCH))
        {
        /* Looks like another daemon is running.  Exit. */
        fclose(pf);
        /* Log the failure */
        exit(EXIT_FAILURE);
        }
      }
    /* stale PID file.  remove it */
    fclose(pf);
    if (unlink(pidfilename) != 0)
      {
      /* Could not remove PID file.  Exit.  */
      /* Log the failure */
      exit(EXIT_FAILURE);
      }
    }

  /* Write a new  PID file. */
  fd = creat(pidfilename, 0644);
  if (fd < 0)
    {
    /* Log the failure */
    exit(EXIT_FAILURE);
    }
  if (flock(fd, LOCK_EX | LOCK_NB) < 0)
    {
    /* Log the failure */
    exit(EXIT_FAILURE);
    }
  opid = getpid();     /* get our pid */
  /* Get a FILE pointer so we can use fprintf */
  pf = fdopen(fd, "w");
  if (!pf)
    {
    /* Log the failure */
    exit(EXIT_FAILURE);
    }
  fprintf(pf, "%d\n", opid);
  fflush(pf);
  flock(fd, LOCK_UN);
  close(fd);
  }


/* signal handler hangup -- should be more sophisticated */
void handle_sighup(int recv_sig)
  {
  /*** do something */
  
  exit(EXIT_SUCCESS);
  }

/* signal handler quit -- should be more sophisticated */
void handle_sigquit(int recv_sig)
  {
  /*** do something */

  exit(EXIT_SUCCESS);
  }

/* open any logs here if needed */
void open_logs(void)
  {
  /*** open logfiles, 
       return 0 on success, -1 on failure */

  return(0);
  }


int main(void)
  {
  pid_t pid, sid;     /* process ID and Session ID */

  /* fork off the parent process */
  pid = fork();
  if (pid < 0)
    {
    exit(EXIT_FAILURE);
    }
    /* exit the parent process. */
    if (pid > 0)
      {
      exit(EXIT_SUCCESS);
      }

    if (open_logs() < 0)
      {
      /* Log the failure */
      exit(EXIT_FAILURE);
      }

    /* Create a new SID for the child process */
    sid = setsid();
    if (sid < 0)
      {
      /* Log the failure */
      exit(EXIT_FAILURE);
      }

    /* Change the current working directory */
    if ((chdir("/")) < 0)
      {
      /* Log the failure */
      exit(EXIT_FAILURE);
      }

    /* Close out the standard file descriptors */
    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);
    /* reopen them pointing to /dev/null */
    fd0 = open ("/dev/null", (O_RDONLY | O_NOCTTY | O_NOFOLLOW));
    fd1 = open ("/dev/null", (O_WRONLY | O_NOCTTY | O_NOFOLLOW));
    fd2 = open ("/dev/null", (O_WRONLY | O_NOCTTY | O_NOFOLLOW));
    if (fd0 != 0 || fd1 != 1 || fd2 != 2 )
      {
      /* Log the failure */
      exit(EXIT_FAILURE);
      }

    /* change user id */
    if (setuid(UID) != 0)
      {
      /* Log the failure */
      exit(EXIT_FAILURE);
      }

    /* change group id */
    if (setgid(GID) != 0)
      {
      /* Log the failure */
      exit(EXIT_FAILURE);
      }

    /* make PID file */
    make_pidfile(PIDFILE);

    /* Change the file mode mask */
    umask(0);

    /* invoke signal handler */
    sa.sa_handler = handle_sighup;
    sa.sa_flags = 0;
    if (sigaction(SIGHUP,&sa,NULL))
      {
      /* Log the failure */
      exit(EXIT_FAILURE);
      }

    sa.sa_handler = handle_sigquit;
    sa.sa_flags = 0;
    if (sigaction(SIGQUIT,&sa,NULL))
      {
      /* Log the failure */
      exit(EXIT_FAILURE);
      }


    /*** daemon-specific initialization goes here */


   /* The Big Loop */
   while (1)
     {
     /*** do some task here ... */

     }
  exit(EXIT_SUCCESS);
  }
