w3hello.com logo
Home PHP C# C++ Android Java Javascript Python IOS SQL HTML videos Categories
A Daemon that kills a child process in a signal handler and forks a new process in c/unix

You've got a problem with your execv() code:

char *mArgv[MAXMOLES] = {"mole",snum};
execv(mArgv[0],mArgv );

The argument list needs to be terminated with a null pointer:

char *mArgv[] = { "mole", snum, 0 };
execv(mArgv[0], mArgv);

Also, in the handler code (and in the main program), you have:

char *snum;
sprintf(snum,"%d",num+1);

This is lethal; you need to allocate space for snum. In this case, the fix is simple:

char snum[16];
sprintf(snum, "%d", num+1);

You could use:

char snum[16];
snprintf(snum, sizeof(snum), "%d", num+1);

but it hardly seems necessary.

Another pair of related problems are:

  1. Because you cd to the root directory, the mole program won't be found to be executed unless you created it in the root directory — which would be an abominable thing to be doing.
  2. Because you cd to the root directory, (if it is run at all) the mole program will try to create its log file in the root directory — but it should not be able to write to files in the root directory.

You should not be running test code as user root or developing as root. It is too dangerous.

I observe that while it might be OK to put a polished, production-ready daemon into the background with no log file and standard output and standard error connected to /dev/null, it makes debugging extremely hard. Since few programs are ever bug free, you should basically always connect your daemons with standard output and standard error going to a log file (opened in append mode, so that if you truncate the log file, the writes will still occur at the end of the now truncated file). For daemons, you should probably record the time of each message, and quite probably the PID too. A standard logging package of functions can be used to automate this. Without the log files, you can't reliably report on problems, so you're running blind, and running blind causes you to trip over and get hurt.

I'm not sure these are the only problems, but they might well be sufficient to account for most of your problems.


Revised mole.c

#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    FILE *fp = fopen("/tmp/mole.log", "a");
    if (fp != 0)
    {
        time_t now = time(0);
        struct tm *utc = gmtime(&now);
        char timestamp[32];
        strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%SZ", utc);
        char *s;
        if (argc > 1 && strcmp(argv[1], "1") == 0)
            s = "Pop mole1";
        else
            s = "Pop mole2";
        fprintf(fp, "%s - %5d: %s
", timestamp, (int)getpid(), s);
        fclose(fp);
    }
    return 0;
}

The main differences between this program and its predecessor is that it uses a fixed log file name and records the time and PID in the log file.

Revised moletrap.c

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>   /* umask() */
#include <signal.h>
#include <unistd.h>
#include "stderr.h"

static pid_t pid_child_mole;
static int num;

// signal handler that kills child and forks a new one OR kills child
// and shuts down daemon
static void handler(int signum)
{
    if (signum == SIGTERM)
    {
        err_remark("Send SIGTERM to %d
", (int)pid_child_mole);
        kill(pid_child_mole, SIGTERM);
        err_remark("Exiting
");
        exit(0);
    }
    else if (signum == SIGUSR1)
    {
        if (num == 0 && pid_child_mole > 0)
        {
            err_remark("Send SIGCHLD to %d
", (int)pid_child_mole);
            kill(pid_child_mole, SIGCHLD);
        }
        num = rand() % 2;
        char snum[16];
        sprintf(snum, "%d", num + 1);
        char *mArgv[] = { "mole", snum, 0 };
        pid_child_mole = fork();
        if (pid_child_mole == 0)
        {
            err_remark("about to execute %s %s
", mArgv[0], mArgv[1]);
            execv(mArgv[0], mArgv);
            err_syserr("failed (1) to execute %s %s
", mArgv[0], mArgv[1]);
        }
        (void) signal(SIGUSR1, handler);
    }
    else if (signum == SIGUSR2)
    {
        if (num == 1)
        {
            err_remark("Send SIGCHLD to %d
", (int)pid_child_mole);
            kill(pid_child_mole, SIGCHLD);
        }
        num = rand() % 2;
        char snum[16];
        sprintf(snum, "%d", num + 1);
        char *mArgv[] = { "mole", snum, 0 };
        pid_child_mole = fork();
        if (pid_child_mole == 0)
        {
            err_remark("about to execute %s %s
", mArgv[0], mArgv[1]);
            execv(mArgv[0], mArgv);
            err_syserr("failed (2) to execute %s %s
", mArgv[0], mArgv[1]);
        }
        (void) signal(SIGUSR2, handler);
    }
    else
        err_remark("received unexpected signal %d
", signum);
}

int main(int argc, char **argv)
{
    const char *logfile = "/tmp/moletrap.log";
    err_setarg0(argv[argc - argc]);
    err_setlogopts(err_getlogopts() | ERR_STAMP | ERR_PID);

    // Create child process
    pid_t process_id = fork();
    if (process_id < 0)  // Indication of fork() failure
        err_syserr("fork() failed
");

    if (process_id > 0)
    {
        // PARENT PROCESS exits successfully
        printf("process ID of child process %d 
", process_id);
        exit(0);
    }

    // unmask the file mode
    umask(0);
    // set new session
    pid_t sid = setsid();
    if (sid < 0)
        err_syserr("setsid() failed
");

    // Change the current working directory to root.
    // if (chdir("/") != 0)
    //     err_syserr("chdir() failed
");

    // Redirect standard input from /dev/null
    close(STDIN_FILENO);
    if (open("/dev/null", O_RDONLY) < 0)
        err_syserr("failed to open /dev/null
");

    // Redirect standard output and standard error to a log file
    int fd1 = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644);
    if (fd1 < 0)
        err_syserr("failed to open %s
", logfile);
    if (dup2(fd1, STDOUT_FILENO) < 0)
        err_syserr("failed to send standard output to log file %s
", logfile);
    if (dup2(fd1, STDERR_FILENO) < 0)
        err_syserr("failed to send standard error to log file %s
", logfile);
    close(fd1);

    err_remark("Started
");

    (void) signal(SIGTERM, handler);
    (void) signal(SIGUSR1, handler);
    (void) signal(SIGUSR2, handler);
    pid_child_mole = fork();
    while (1)
    {
        sleep(1);
        err_remark("Sleepers awake, salute ...
");
        if (pid_child_mole == 0)
        {
            int num = rand() % 2;
            char snum[16];
            sprintf(snum, "%d", num + 1);
            char *mArgv[] = { "mole", snum, 0 };
            err_remark("about to execute %s %s
", mArgv[0], mArgv[1]);
            execv(mArgv[0], mArgv );
            err_syserr("failed (3) to execute %s %s
", mArgv[0], mArgv[1]);
        }
    }

    return(0);
}

This revision uses the original signal handling code, warts and all. In theory, it shouldn't do all the things it does in the signal handler, but it works 'OK'. OTOH, if anything went wrong, there'd be nothing to do except rewrite the code.

The code uses my "stderr.h" header and implicitly the implementation stderr.c. This radically simplifies the error reporting coding here: err_syserr() reports an error and the system error message based on errno and exits, while err_remark() writes a message and returns to the calling code. The err_setarg0() function records the program name (conventionally based on argv[0]); err_getlogopts() reports the current log option settings, and err_setlogopts() sets the same values plus ERR_PID (to record the PID on each line of output) and ERR_STAMP (to timestamp each line of output). The header is 150 lines (93 non-blank, non-comment lines); the source is 608 lines (424 non-blank, non-comment lines) — far too big to be shown here. See my profile if you want the code.

Sample command sequences

$ ./moletrap        # Reported 9424
$ kill -USR2 9424
$ kill -USR2 9424
$ kill -USR1 9424
$

$ ./moletrap        # Reported 9456
$ kill -USR2 9456
$ kill -USR2 9456
$ kill -USR1 9456
$ kill -USR1 9456
$ kill -TERM 9456
$ kill -TERM 9456
$

$ ./moletrap        # Reported 9499
$ kill -USR2 9499
$ kill -USR2 9499
$ kill -USR2 9499
$ kill -USR1 9499
$ kill -USR1 9499
$ kill -USR1 9499
$ kill -TERM 9499
$

Sample mole.log

2014-11-20 05:28:49Z -  9425: Pop mole2
2014-11-20 05:29:12Z -  9428: Pop mole2
2014-11-20 05:33:36Z -  9457: Pop mole2
2014-11-20 05:34:00Z -  9462: Pop mole2
2014-11-20 05:34:02Z -  9463: Pop mole1
2014-11-20 05:36:54Z -  9500: Pop mole2
2014-11-20 05:37:07Z -  9501: Pop mole2
2014-11-20 05:37:08Z -  9504: Pop mole2
2014-11-20 05:37:09Z -  9505: Pop mole2
2014-11-20 05:37:13Z -  9506: Pop mole1
2014-11-20 05:37:14Z -  9507: Pop mole1
2014-11-20 05:37:15Z -  9508: Pop mole1

Sample moletrap.log

moletrap: 2014-11-19 21:28:48 - pid=9424: Started
moletrap: 2014-11-19 21:28:49 - pid=9425: about to execute mole 2
moletrap: 2014-11-19 21:28:59 - pid=9426: about to execute mole 2
moletrap: 2014-11-19 21:28:59 - pid=9426: failed to execute mole 2
error (14) Bad address
moletrap: 2014-11-19 21:29:02 - pid=9424: Send SIGCHLD to 9426
moletrap: 2014-11-19 21:29:02 - pid=9427: about to execute mole 2
moletrap: 2014-11-19 21:29:02 - pid=9427: failed to execute mole 2
error (14) Bad address
moletrap: 2014-11-19 21:29:12 - pid=9428: about to execute mole 2

moletrap: 2014-11-19 21:33:35 - pid=9456: Started
moletrap: moletrap: 2014-11-19 21:33:36 - pid=9456: Sleepers awake, salute
...
2014-11-19 21:33:36 - pid=9457: Sleepers awake, salute ...
moletrap: 2014-11-19 21:33:36 - pid=9457: about to execute mole 2
moletrap: 2014-11-19 21:33:37 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:33:38 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:33:39 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:33:40 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:33:41 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:33:42 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:33:43 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:33:44 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:33:45 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:33:46 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:33:47 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:33:48 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:33:49 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:33:50 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:33:51 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:33:52 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:33:53 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:33:54 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:33:55 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:33:55 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:33:55 - pid=9460: about to execute mole 2
moletrap: 2014-11-19 21:33:55 - pid=9460: failed (2) to execute mole 2
error (14) Bad address
moletrap: 2014-11-19 21:33:56 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:33:57 - pid=9456: Send SIGCHLD to 9460
moletrap: 2014-11-19 21:33:57 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:33:57 - pid=9461: about to execute mole 2
moletrap: 2014-11-19 21:33:57 - pid=9461: failed (2) to execute mole 2
error (14) Bad address
moletrap: 2014-11-19 21:33:58 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:33:59 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:34:00 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:34:00 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:34:00 - pid=9462: about to execute mole 2
moletrap: 2014-11-19 21:34:01 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:34:02 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:34:02 - pid=9463: about to execute mole 1
moletrap: 2014-11-19 21:34:03 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:34:04 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:34:05 - pid=9456: Sleepers awake, salute ...
moletrap: 2014-11-19 21:34:06 - pid=9456: Send SIGTERM to 9463
moletrap: 2014-11-19 21:34:06 - pid=9456: Exiting

moletrap: 2014-11-19 21:36:53 - pid=9499: Started
moletrap: moletrap: 2014-11-19 21:36:54 - pid=9499: Sleepers awake, salute
...
2014-11-19 21:36:54 - pid=9500: Sleepers awake, salute ...
moletrap: 2014-11-19 21:36:54 - pid=9500: about to execute mole 2
moletrap: 2014-11-19 21:36:55 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:36:56 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:36:57 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:36:58 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:36:59 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:00 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:01 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:02 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:03 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:04 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:05 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:06 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:07 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:07 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:07 - pid=9501: about to execute mole 2
moletrap: 2014-11-19 21:37:08 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:08 - pid=9499: Send SIGCHLD to 9501
moletrap: 2014-11-19 21:37:08 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:08 - pid=9504: about to execute mole 2
moletrap: 2014-11-19 21:37:09 - pid=9499: Send SIGCHLD to 9504
moletrap: 2014-11-19 21:37:09 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:09 - pid=9505: about to execute mole 2
moletrap: 2014-11-19 21:37:10 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:11 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:12 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:13 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:13 - pid=9506: about to execute mole 1
moletrap: 2014-11-19 21:37:14 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:14 - pid=9499: Send SIGCHLD to 9506
moletrap: 2014-11-19 21:37:14 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:14 - pid=9507: about to execute mole 1
moletrap: 2014-11-19 21:37:15 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:15 - pid=9499: Send SIGCHLD to 9507
moletrap: 2014-11-19 21:37:15 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:15 - pid=9508: about to execute mole 1
moletrap: 2014-11-19 21:37:16 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:17 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:18 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:19 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:20 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:21 - pid=9499: Sleepers awake, salute ...
moletrap: 2014-11-19 21:37:21 - pid=9499: Send SIGTERM to 9508
moletrap: 2014-11-19 21:37:21 - pid=9499: Exiting

The '(24) Bad address' errors were because I'd only fixed two of the three places where execv() is used; fixing the third one eliminated the errors. You can see the development of the error handling; the first set didn't identify which 'failed to execute' message was giving the trouble; the second set showed that it was 'failed (2) to execute', which made it trivial to see the problem. Watch and learn!

Using "Sleepers awake, salute …" is a (bad) joke and a mixup; it just shows the iterations of the loop with time passing. (See Wachet auf at Wikipedia, and Christians Awake, Salute the Happy Morn.)

This shows your code at work. I'm not convinced the SIGCHLD signals are of any relevance whatsoever, but I left them in. The children die promptly anyway, and not because of being sent SIGCHLD. I've not checked for zombies — beware the sleeping dead.





© Copyright 2018 w3hello.com Publishing Limited. All rights reserved.