Friday, May 12, 2017

Daemons

Fortunately, as a good Unix system, Solaris supports easy daemon creation by encapsulating all the necessary steps into a single system function called daemon(3C). Thus the whole process of becoming a daemon is greatly simplified when compared to the traditional / legacy approach:

#include <sys/types.h> 
#include <sys/stat.h> 
#include <unistd.h> 

#include <cerrno> 
#include <cstdlib> 
#include <cstdarg> 

#include "toolbox.hxx"

void error( toolbox::log & log, const char * message )
{
  int code = errno;
  log.write( "ERROR: %s (%d)\n", message, code );
  ::exit( EXIT_FAILURE );
}

int main( )
{
  toolbox::log log( "trace.log" );

  if ( ! log.open() )
    return EXIT_FAILURE;

  log.write( "Starting up...\n" );

  if ( ::daemon( 0, 0 ) < 0 )
    error( log, "Couldn't become a daemon." );

  log.write( "Successfully became a daemon!\n" );
 
  
  ::umask( 0 );
 
  const int seconds = 30;
  log.write( "Resting for %d seconds...\n", seconds );
  ::sleep( seconds );

  log.write( "Bye cruel world!\n\n" );
  log.close();

  return EXIT_SUCCESS;
}


A typical log output could be similar to:

$ cat trace.log
[2017-05-12 16:29:11] Starting up...
[2017-05-12 16:29:11] Successfully became a daemon!
[2017-05-12 16:29:11] Resting for 30 seconds...
[2017-05-12 16:29:41] Bye cruel world!


It may be interesting to take a look under the hood at the system calls encapsulated by daemon(3C) in order to compare it with the traditional / legacy approach:

$ truss -f ./daemon-01
...
... getcwd("/...", 1024) = 0
... open("/.../trace.log", O_WRONLY|O_APPEND|O_CREAT, 0640) = 3

...
3155:    write(3, " [ 2 0 1 7 - 0 5 - 1 2  ".., 22) = 22
3155:    write(3, " S t a r t i n g   u p .".., 15) = 15
...
3155:    forkx(0)                                   = 3156
 

3155:    _exit(0)
... 
3156:    forkx()        (returning as child ...)    = 3155
3156:    getpid()                                   = 3156 [3155]
...
3156:    setsid()                                   = 3156
...
3156:    forkx(0)                                   = 3158
3156:    _exit(0)
...
3158:    forkx()        (returning as child ...)    = 3156
3158:    getpid()                                   = 3158 [1]
...
3158:    chdir("/")                                 = 0

...
3158:    open("/dev/null", O_RDWR)                  = 4
3158:    fcntl(4, F_DUP2FD, 0x00000000)             = 0
3158:    fcntl(4, F_DUP2FD, 0x00000001)             = 1
3158:    fcntl(4, F_DUP2FD, 0x00000002)             = 2
3158:    close(4)                                   = 0
...
3158:    write(3, " [ 2 0 1 7 - 0 5 - 1 2  ".., 22) = 22
3158:    write(3, " S u c c e s s f u l l y".., 30) = 30
...

3158:    umask(0)                                   = 022
...
3158:    write(3, " [ 2 0 1 7 - 0 5 - 1 2  ".., 22) = 22
3158:    write(3, " R e s t i n g   f o r  ".., 26) = 26
3158:    nanosleep(...) (sleeping...)
3158:    nanosleep(...) = 0
...
3158:    write(3, " [ 2 0 1 7 - 0 5 - 1 2  ".., 22) = 22
3158:    write(3, " B y e   c r u e l   w o".., 18) = 18
3158:    close(3)                                   = 0
...
3158:    _exit(0)