Daemon-izing a Process in Linux

Daemon-izing a Process in Linux

Introduction

A Linux process works either in foreground or background.

A process running in foreground can interact with the user in front of the terminal. To run a.out in foreground we execute as shown below.
./a.out
When a process runs as background process then it runs by itself without any user interaction. The user can check its status but he doesn't (need to) know what it is doing. To run a.out in background we execute as shown below.
$ ./a.out &
[1] 3665
As shown above when we run a process with & at the end then the process runs in background and returns the process id (3665 in above example).

what is a DAEMON Process?

A 'daemon' process is a process that runs in background, begins execution at startup
(not neccessarily), runs forever, usually do not die or get restarted, waits for requests to arrive and respond to them and frequently spawn other processes to handle these requests.

So running a process in BACKGROUND with a while loop logic in code to loop forever makes a Daemon ? Yes and also No. But there are certain things to be considered when we create a daemon process. We follow a step-by-step procedure as shown below to create a daemon process.

Daemonizing a process is different from making a process run in the background ?

If I start a program in the background using & (for example './script &' ), what makes this process' execution different from the case when the program turns itself into a daemon ?
A program running in the background is no longer, directly controlled by the terminal (you can't simply ^C it), but it can still write to the terminal and interfere with your work. Typically a daemon will separate itself from the terminal (in addition to forking) and its output/error would be redirected to files.

1. Create a separate child process - fork() it.
Using fork() system call create a copy of our process(child), then let the parent process exit. Once the parent process exits the Orphaned child process will become the child of init process (this is the initial system process, in other words the parent of all processes). As a result our process will be completely detached from its parent and start operating in background.
pid=fork();

if (pid<0) exit(1); /* fork error */

if (pid>0) exit(0); /* parent exits */

/* child (daemon) continues */


2. Make child process In-dependent - setsid()
Before we see how we gonna make a child process independent let us talk Process group and Session ID.

A process group denotes a collection of one or more processes. Process groups are used to control the distribution of signals. A signal directed to a process group is delivered individually to all of the processes that are members of the group.

Process groups are themselves grouped into sessions. Process groups are not permitted to migrate from one session to another, and a process may only create new process groups belonging to the same session as it itself belongs to. Processes are not permitted to join process groups that are not in the same session as they themselves are.

New process images created by a call to a function of the exec family and fork() inherit the process group membership and the session membership of the parent process image.

A process receives signals from the terminal that it is connected to, and each process inherits its parent's controlling tty. A daemon process should not receive signals from the process that started it, so it must detach itself from its controlling tty.

In Unix systems, processes operates within a process group, so that all processes within a group is treated as a single entity. Process group or session is also inherited. A daemon process should operate independently from other processes.
setsid();
setsid() system call is used to create a new session containing a single (new) process group, with the current process as both the session leader and the process group leader of that single process group. (setpgrp() is an alternative for this).

NOTE: We have to create a child process and use setsid() to make it independent. Trying on a parent process returns error saying EPERM.

3. Change current Running Directory - chdir()
A daemon process should run in a known directory. There are many advantages, in fact the opposite has many disadvantages: suppose that our daemon process is started in a user's home directory, it will not be able to find some input and output files. If the home directory is a mounted filesystem then it will even create many issues if the filesystem is accidentally un-mounted.
chdir("/server/");
The root "/" directory may not be appropriate for every server, it should be chosen carefully depending on the type of the server.

4. Close Inherited Descriptors and Standard I/O Descriptors
A child process inherits default standard I/O descriptors and opened file descriptors from a parent process, this may cause the use of resources un-neccessarily. Unnecessary file descriptors should be closed before fork() system call (so that they are not inherited) or close all open descriptors as soon as the child process starts running as shown below.
for ( i=getdtablesize(); i>=0; --i) 
close(i); /* close all descriptors */
There are three standard I/O descriptors:
standard input 'stdin' (0),
standard output 'stdout' (1),
standard error 'stderr' (2).
For safety, these descriptors should be opened and connected to a harmless I/O device (such as /dev/null).
int fd;

fd = open("/dev/null",O_RDWR, 0);

if (fd != -1) 
{   
  dup2 (fd, STDIN_FILENO);
  dup2 (fd, STDOUT_FILENO);
  dup2 (fd, STDERR_FILENO);
  
  if (fd > 2)
  close (fd);
}
5. Reset File Creation Mask - umask()
Most Daemon processes runs as super-user, for security reasons they should protect files that they create. Setting user mask will prevent unsecure file priviliges that may occur on file creation.
umask(027);
This will restrict file creation mode to 750 (complement of 027).

Let us see a sample 'C' code which creates a daemon.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define EXIT_SUCCESS 0
#define EXIT_FAILURE 1

static void daemonize(void)
{
    pid_t pid, sid;
    int fd; 

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

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

    if (pid > 0)  
    {   
        exit(EXIT_SUCCESS); /*Killing the Parent Process*/
    }   

    /* At this point we are executing as the child process */

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

    /* Change the current working directory. */
    if ((chdir("/")) < 0)
    {
        exit(EXIT_FAILURE);
    }


    fd = open("/dev/null",O_RDWR, 0);

    if (fd != -1)
    {
        dup2 (fd, STDIN_FILENO);
        dup2 (fd, STDOUT_FILENO);
        dup2 (fd, STDERR_FILENO);

        if (fd > 2)
        {
            close (fd);
        }
    }

    /*resettign File Creation Mask */
    umask(027);
}

int main( int argc, char *argv[] )
{
    daemonize();

    while(1)
    {
      /* Now we are a daemon -- do the work for which we were paid */

      sleep(10);
    }

    return 0;
}






C program on how to use command line arguments in main function


#include <stdio.h>

#include <stdlib.h>


int main(int argc, char *argv[])   //  command line arguments

{

if(argc!=5)

{

   printf("Arguments passed through command line " \

          "not equal to 5");

   return 1;

}


   printf("\n Program name  : %s \n", argv[0]);

   printf("1st arg  : %s \n", argv[1]);

   printf("2nd arg  : %s \n", argv[2]);

   printf("3rd arg  : %s \n", argv[3]);

   printf("4th arg  : %s \n", argv[4]);

   printf("5th arg  : %s \n", argv[5]);


return 0;

}


C program for client-server UNIX domain socket

C program for client-server UNIX domain socket


/**************************************************************
* server.c
***************************************************************/
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <stdlib.h>

#define CLIENT_SOCK_FILE                 "/home/labuser/unix_domain_socket/client_n"
#define SERVER_SOCK_FILE                 "/home/labuser/unix_domain_socket/server_n"

struct msg {
    char a[10];
    char b[10];
    char c[10];
};

int main(int argc, char *argv[])
{
    int fd;
    struct sockaddr_un addr;
    char buff[512];
    struct sockaddr_un from;
    int len;
    socklen_t fromlen = sizeof(from);

    struct msg sent_message;
    memset(&sent_message, '\0', sizeof(sent_message));

    /* create dispatcher socket */
    if ((fd = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
        perror("socket");
        exit(1);
    }

    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strcpy(addr.sun_path, SERVER_SOCK_FILE);
    unlink(SERVER_SOCK_FILE);

    if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        perror("bind");
        exit(1);
    }
    memset(buff, '\0', sizeof(buff));

    /*  Receive Message from process Client */
    while ((len = recvfrom(fd, &sent_message, sizeof(sent_message)+1, 0, (struct sockaddr *)&from, &fromlen)) > 0)
    {
        buff[len] = '\0';
        /* Foward the received message from process Client to PCD server */
        fprintf(stderr, "message received %s\n", sent_message.a);
        fprintf(stderr, "message received %s\n", sent_message.b);
        fprintf(stderr, "message received %s\n", sent_message.c);
    }

    if (fd >= 0) {
        close(fd);
    }

    return 0;
}

/**************************************************************
* client.c
***************************************************************/

#include <sys/socket.h>
#include <sys/un.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define CLIENT_SOCK_FILE                 "/home/labuser/unix_domain_socket/client_n"
#define SERVER_SOCK_FILE                 "/home/labuser/unix_domain_socket/server_n"

struct msg {
   char a[10];
   char b[10];
   char c[10];
};


int main(int argc, char *argv[]) {

    int fd;
    struct sockaddr_un addr;
    int ret = 0;
    struct msg sent_message;

    memset(&sent_message, '\0', sizeof(sent_message));
    strcpy(sent_message.a, "abc");
    strcpy(sent_message.b, "def");
    strcpy(sent_message.c, "ghi");



    if ((fd = socket(PF_UNIX, SOCK_DGRAM, 0)) < 0) {
        ret = -1;
        perror("socket");
        return ret;
    }

    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strcpy(addr.sun_path, CLIENT_SOCK_FILE);

    unlink(CLIENT_SOCK_FILE);
    if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        ret = -1;
        perror("bind");
        close(fd);
        return ret;
    }

    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strcpy(addr.sun_path, SERVER_SOCK_FILE);

    if (connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        ret = -1;
        perror("connect");
        close(fd);
        return ret;
    }

    //if (send(fd, message, strlen(message)+1, 0) < 0) {
    if (send(fd, &sent_message, sizeof(sent_message)+1, 0) < 0) {
        ret = -1;
        perror("send");
        close(fd);
        return ret;
    }

    close(fd);

    return 0;
}



C program to write 2 -D array into file (one string on each line of the file)

C program to write 2 -D array into file (one string on each line of the file)


#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

int main ()
{
    int fd;
    char a[10][20] = {"google", "aricent", "sparrow", "jumanji"};


    fd = open("/home/labuser/open_file", O_CREAT | O_RDWR | O_SYNC, 0755);
    if (fd < 0) {
        return 1;
    }

    a[0][strlen(a[0])] = '\n';
    write(fd, a[0], sizeof(a[0]));

    a[1][strlen(a[1])] = '\n';
    write(fd, a[1], sizeof(a[1]));

    a[2][strlen(a[2])] = '\n';
    write(fd, a[2], sizeof(a[2]));

    a[3][strlen(a[3])] = '\n';
    write(fd, a[3], sizeof(a[3]));
}