HAL.c

From Organic Design wiki
Revision as of 21:25, 23 July 2009 by Jack (talk | contribs) (test daemon)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
  1. include <stdio.h>
  2. include <stdlib.h>
  3. include <string.h>
  4. include <unistd.h>
  5. include <sys/types.h>
  6. include <sys/stat.h>
  7. include <fcntl.h>
  8. include <syslog.h>
  9. include <errno.h>
  10. include <pwd.h>
  11. include <signal.h>

/* Change this to whatever your daemon is called */

  1. define DAEMON_NAME "HAL"

/* Change this to the user under which to run */

  1. define RUN_AS_USER "jack"
  1. define EXIT_SUCCESS 0
  2. define EXIT_FAILURE 1

static void child_handler(int signum) { switch(signum) { case SIGALRM: exit(EXIT_FAILURE); break; case SIGUSR1: exit(EXIT_SUCCESS); break; case SIGCHLD: exit(EXIT_FAILURE); break; } }

static void daemonize( const char *lockfile ) { pid_t pid, sid, parent; int lfp = -1;

/* already a daemon */ if ( getppid() == 1 ) return;

/* Create the lock file as the current user */ if ( lockfile && lockfile[0] ) {

   lfp = open(lockfile,O_RDWR|O_CREAT,0640);
   if ( lfp < 0 ) {
       syslog( LOG_ERR, "unable to create lock file %s, code=%d (%s)",
               lockfile, errno, strerror(errno) );
       exit(EXIT_FAILURE);
   }

}

/* Drop user if there is one, and we were run as root */ if ( getuid() == 0 || geteuid() == 0 ) {

   struct passwd *pw = getpwnam(RUN_AS_USER);
   if ( pw ) {
       syslog( LOG_NOTICE, "setting user to " RUN_AS_USER );
       setuid( pw->pw_uid );
   }

}

/* Trap signals that we expect to receive */ signal(SIGCHLD,child_handler); signal(SIGUSR1,child_handler); signal(SIGALRM,child_handler);

/* Fork off the parent process */ pid = fork(); if (pid < 0) {

   syslog( LOG_ERR, "unable to fork daemon, code=%d (%s)",
           errno, strerror(errno) );
   exit(EXIT_FAILURE);

} /* If we got a good PID, then we can exit the parent process. */ if (pid > 0) {

   /* Wait for confirmation from the child via SIGTERM or SIGCHLD, or
      for two seconds to elapse (SIGALRM).  pause() should not return. */
   alarm(2);
   pause();
   exit(EXIT_FAILURE);

}

/* At this point we are executing as the child process */ parent = getppid();

/* Cancel certain signals */ signal(SIGCHLD,SIG_DFL); /* A child process dies */ signal(SIGTSTP,SIG_IGN); /* Various TTY signals */ signal(SIGTTOU,SIG_IGN); signal(SIGTTIN,SIG_IGN); signal(SIGHUP, SIG_IGN); /* Ignore hangup signal */ signal(SIGTERM,SIG_DFL); /* Die on SIGTERM */

/* Change the file mode mask */ umask(0);

/* Create a new SID for the child process */ sid = setsid(); if (sid < 0) {

   syslog( LOG_ERR, "unable to create a new session, code %d (%s)",
           errno, strerror(errno) );
   exit(EXIT_FAILURE);

}

/* Change the current working directory. This prevents the current

  directory from being locked; hence not being able to remove it. */

if ((chdir("/")) < 0) {

   syslog( LOG_ERR, "unable to change directory to %s, code %d (%s)",
           "/", errno, strerror(errno) );
   exit(EXIT_FAILURE);

}

/* Redirect standard files to /dev/null */ freopen( "/dev/null", "r", stdin); freopen( "/dev/null", "w", stdout); freopen( "/dev/null", "w", stderr);

/* Tell the parent process that we are A-okay */ kill( parent, SIGUSR1 ); }

int main( int argc, char *argv[] ) { /* Initialize the logging interface */ openlog( DAEMON_NAME, LOG_PID, LOG_LOCAL5 ); syslog( LOG_INFO, "starting" );

/* One may wish to process command line arguments here */

/* Daemonize */ daemonize( "/var/lock/subsys/" DAEMON_NAME );

/* Now we are a daemon -- do the work for which we were paid */


/* Finish up */ syslog( LOG_NOTICE, "terminated" ); closelog(); return 0; }