c program to create daemonize process and signal handling for daemonized process

C program to create daemonize process and signal handling for daemonized process


/* A daemon is a process which runs in the background of your computer, periodically carrying out a specific task. The following is an example of a simple daemon written in C. It works by forking to create a child process, the parent then terminates but the child carries on in the background – entering a continuous loop of doing a task and then sleeping. The child process is of course an identical copy of the parent so care must be taken to close all file descriptors, thus detaching the child completely from the calling process. The deamonised process is controlled by sending it signals which it can catch and take action accordingly. In the example below, the process is terminated by sending SIGINT or SIGTERM, but you can of course add in your own handling 
 */

#include <stdio.h>
#include <signal.h>
#include <syslog.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

#define DAEMON_NAME "simpledaemon"


void daemonShutdown();
void signal_handler(int sig);
void daemonize(char *rundir, char *pidfile);


int pidFilehandle;


void signal_handler(int sig)
{
    switch(sig)
    {
        case SIGHUP:
            syslog(LOG_WARNING, "Received SIGHUP signal.");
            break;
        case SIGSEGV:
            syslog(LOG_WARNING, "Received SIGSEGV signal.");
            kill(getpid(), SIGKILL);
            break;
        case SIGINT:
        case SIGTERM:
            syslog(LOG_INFO, "Daemon exiting");
            daemonShutdown();
            exit(EXIT_SUCCESS);
            break;
        default:
            syslog(LOG_WARNING, "Unhandled signal %s", strsignal(sig));
            break;
    }
}

void daemonShutdown()
{
    close(pidFilehandle);
}

void daemonize(char *rundir, char *pidfile)
{
    int pid, sid, i;
    char str[10];
    struct sigaction newSigAction;
    sigset_t newSigSet;

    /* Check if parent process id is set */
    if (getppid() == 1)
    {
        /* PPID exists, therefore we are already a daemon */
        return;
    }

    /* Set signal mask - signals we want to block */
    sigemptyset(&newSigSet);
    sigaddset(&newSigSet, SIGCHLD);  /* ignore child - i.e. we don't need to wait for it */
    sigaddset(&newSigSet, SIGTSTP);  /* ignore Tty stop signals */
    sigaddset(&newSigSet, SIGTTOU);  /* ignore Tty background writes */
    sigaddset(&newSigSet, SIGTTIN);  /* ignore Tty background reads */
    sigprocmask(SIG_BLOCK, &newSigSet, NULL);   /* Block the above specified signals */

    /* Set up a signal handler */
    newSigAction.sa_handler = signal_handler;
    sigemptyset(&newSigAction.sa_mask);
    newSigAction.sa_flags = 0;

    /* Signals to handle */
    sigaction(SIGHUP, &newSigAction, NULL);     /* catch hangup signal */
    sigaction(SIGTERM, &newSigAction, NULL);    /* catch term signal */
    sigaction(SIGINT, &newSigAction, NULL);     /* catch interrupt signal */
    sigaction(SIGSEGV, &newSigAction, NULL);     /* catch interrupt signal */


    /* Fork*/
    pid = fork();

    if (pid < 0)
    {
        /* Could not fork */
        exit(EXIT_FAILURE);
    }

    if (pid > 0)
    {
        /* Child created ok, so exit parent process */
        printf("Child process created: %d\n", pid);
        exit(EXIT_SUCCESS);
    }

    /* Child continues */

    umask(027); /* Set file permissions 750 */

    /* Get a new process group */
    sid = setsid();

    if (sid < 0)
    {
        exit(EXIT_FAILURE);
    }

    /* close all descriptors */
    for (i = getdtablesize(); i >= 0; --i)
    {
        close(i);
    }

    /* Route I/O connections */

    /* Open STDIN */
    i = open("/dev/null", O_RDWR);

    /* STDOUT */
    dup(i);

    /* STDERR */
    dup(i);

    chdir(rundir); /* change running directory */

    /* Ensure only one copy */
    pidFilehandle = open(pidfile, O_RDWR|O_CREAT, 0600);

    if (pidFilehandle == -1 )
    {
        /* Couldn't open lock file */
        syslog(LOG_INFO, "Could not open PID lock file %s, exiting", pidfile);
        exit(EXIT_FAILURE);
    }

    /* Try to lock file */
    if (lockf(pidFilehandle,F_TLOCK,0) == -1)
    {
        /* Couldn't get lock on lock file */
        syslog(LOG_INFO, "Could not lock PID lock file %s, exiting", pidfile);
        exit(EXIT_FAILURE);
    }


    /* Get and format PID */
    sprintf(str,"%d\n",getpid());

    /* write pid to lockfile */
    write(pidFilehandle, str, strlen(str));
}

int main()
{
    /* Debug logging
       setlogmask(LOG_UPTO(LOG_DEBUG));
       openlog(DAEMON_NAME, LOG_CONS, LOG_USER);
     */

    /* Logging */
    setlogmask(LOG_UPTO(LOG_INFO));
    openlog(DAEMON_NAME, LOG_CONS | LOG_PERROR, LOG_USER);

    syslog(LOG_INFO, "Daemon starting up");

    /* Deamonize */
    daemonize("/tmp/", "/tmp/daemon.pid");

    syslog(LOG_INFO, "Daemon running");

    while (1)
    {
        syslog(LOG_INFO, "daemon says hello");

        sleep(1);
    }
}

C program on How to handle SIGSEGV, but also generate a core dump

C program on How to handle SIGSEGV, but also generate a core dump

By default, while signal is being handled it is masked, so it can't be triggered recursively. If masked signal is triggered by program execution (invalid memory access, segfault, division by 0 etc.), the behavior is undefined:

If SIGBUS, SIGFPE, SIGILL, or SIGSEGV are generated while they are blocked, the result is undefined, unless the signal was generated by kill(2), sigqueue(3), or raise(3).

It causes process to crash.

With SA_NODEFER there is no masking, so signal can be handled recursively until stack overflows. And adding SA_RESETHAND would restore default action (crash for SIGSEGV).

#include<signal.h>

#include<stdio.h>

#include<stdlib.h>

#include<unistd.h>

volatile char *ptr;

static void signal_handler(int signal)

{

    printf("signal handler invoked");

    abort(); /* This should give us the expected core dump (if we survive to this point) */

}

struct sigaction sa = {};
 /* initialised to all zero (I vote for GCC style breach of standard here) */

int main()

{

    sa.sa_handler = signal_handler;

    sa.sa_flags = SA_RESETHAND | SA_NODEFER;  /* To have or have not */

    sigaction(SIGSEGV, &sa, NULL);

  
    while(1);
 }

How to write make file for dynamic linked libraries

How to write make file for dynamic linked libraries


NEEL_DIR = $(shell pwd)
LIBNAME = libneel
LIB = $(LIBNAME).so
INCLUDE = -I.

all: compile build_lib
    mkdir -p $(INSTALL_DIR)/lib
    install -m 755 $(LIB) $(INSTALL_DIR)/lib

CFLAGS += -O0 -g -fno-omit-frame-pointer -fno-strict-aliasing
CFLAGS += -fPIC
CFLAGS += $(INCLUDE)

SRCS = neel.c

OBJ_TARGETS = $(SRCS:%.c=$(NEEL_DIR)/%.o)

compile: $(OBJ_TARGETS)

$(NEEL_DIR)/%.o : $(NEEL_DIR)/%.c
    @echo "Compiling file $<"
    $(CC) -c -g -w $(CFLAGS) -o $@ $<

build_lib: compile
    @echo "Linking"
    $(CC) -shared -o $(LIB) $(OBJ_TARGETS)

clean:

    rm -f $(LIB) $(OBJ_TARGETS)

C program to Convert "integer in string" to actual Integer using "strtol" library function

C program to Convert "integer in string" to actual Integer using "strtol" library function

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main(int argc, const char * argv[])
{
    /* Define temporary variables */
    char value[10];
    char *eptr;
    long result;

    /* Copy a value into the variable */
    /* It's okay to have whitespace before the number */
    strcpy(value, " 123");

    /* Convert the provided value to a decimal long */
    result = strtol(value, &eptr, 10);

    /* If a conversion could not be done, display the error
     message and exit */
    if (result == 0)
    {
        printf("Conversion error occurred: %d", errno);

        exit(0);
    }

    /* Display the converted result */
    printf("%ld decimal\n", result);

    /* Copy a hexadecimal value into the variable */
    strcpy(value, "0x19e");

    /* Convert the provided value to a decimal long */
    result = strtol(value, &eptr, 16);

    /* If a conversion could not be done, display the error
     message and exit */
    if (result == 0)
    {
        printf("Conversion error occurred: %d", errno);

        exit(0);
    }

    /* Display the converted result */
    printf("%lx hexadecimal\n", result);

    return 0;
}

Output:

$gcc -o main *.c
$main
123 decimal
19e hexadecimal

C program to print system uptime

C program to print system uptime 


#include <stdio.h>

void print_time (long time)
{
  /* Conversion constants.  */
  const long minute = 60;
  const long hour = minute * 60;
  const long day = hour * 24;
  /* Produce output.  */
  printf ("Uptime: %ld days, %ld:%02ld:%02ld\n", time / day,
   (time % day) / hour, (time % hour) / minute, time % minute);
}

int main ()
{
  FILE* fp;
  double uptime, idle_time;
  /* Read the system uptime and accumulated idle time from /proc/uptime.  */
  fp = fopen ("/proc/uptime", "r");
  fscanf (fp, "%lf\n", &uptime);
  fclose (fp);
  /* Summarize it.  */
  print_time ((long) uptime);
  return 0;
}


c program to extract the seconds from "system uptime" command

C program to extract the seconds from "system uptime" command 


#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int main(void) {
 FILE * uptimefile;
 char uptime_chr[28];
 long uptime = 0;

 if((uptimefile = fopen("/proc/uptime", "r")) == NULL)
  perror("supt"), exit(EXIT_FAILURE);

 fgets(uptime_chr, 12, uptimefile);
 fclose(uptimefile);

 uptime = strtol(uptime_chr, NULL, 10);

 printf("System up for %ld seconds, %ld hours\n", uptime, uptime / 3600);

 exit(EXIT_SUCCESS);

}