How to Spawn Child Processes that Don't Die with Parent?

14,475

Solution 1

Try using system with setsid before the process name.

system("setsid processname /path/to/processConfig.xml &");

This will launch the program in a new session.

Solution 2

This one is a bit old but didn't get a complete answer. Here is what I have done on an embedded system to spawn a bash child with no relation to the parent. Note that I execl a bash shell and then run my command in another bash shell. This may not be necessary in your situation. For me it allowed me to do some I/O redirection that didn't work properly without it.

The two important concepts are the setsid() and the double fork(). The combination of these two prevents a zombie from being created when the orphaned child completes, as well as preventing the orphaned child from being killed if the parent completes.

There are many other issues that could come up, like inherited I/O handles, working directory, etc, but this code does the basic job.

int spawn_orphan(char* cmd) {
    char command[1024]; // We could segfault if cmd is longer than 1000 bytes or so
    int pid;
    int Stat;
    pid = fork();
    if (pid < 0) { perror("FORK FAILED\n"); return pid; }
    if (pid == 0) { // CHILD
        setsid(); // Make this process the session leader of a new session
        pid = fork();
        if (pid < 0) { printf("FORK FAILED\n"); exit(1); }
        if (pid == 0) { // GRANDCHILD
            sprintf(command,"bash -c '%s'",cmd);
            execl("/bin/bash", "bash", "-c", command, NULL); // Only returns on error
            perror("execl failed");
            exit(1);
        }
        exit(0); // SUCCESS (This child is reaped below with waitpid())
    }

    // Reap the child, leaving the grandchild to be inherited by init
    waitpid(pid, &Stat, 0);
    if ( WIFEXITED(Stat) && (WEXITSTATUS(Stat) == 0) ) {
        return 0; // Child forked and exited successfully
    }
    else {
        perror("failed to spawn orphan\n");
        return -1;
    }
}

Solution 3

Don't use system(...) it is not multi-threading safe.

int pid = fork();

if(pid==0)
{
  int rc = execv("processname", "/path/to/processConfig.xml &");
  if(rc == -1)
  {
    printf(stderr, "processname failed to start. %d", errno);
  }
  ...
}
else
{
  //continue with the parent
}

Solution 4

You should avoid the use of system.

Do not use system() from a program with set-user-ID or set-group-ID privileges, because strange values for some environment variables might be used to subvert system integrity. Use the exec(3) family of functions instead.

and also if you want to check the return value or anything else

Just go for execl

#include <unistd.h>
#include <stdlib.h>
pid_t pid = fork()
if (pid == -1)
{
   exit(EXIT_FAILURE);
}
else if (pid == 0)
{
  if (execl("processname", "processname", "/path/to/processConfig.xml", NULL) == -1)
    exit(EXIT_FAILURE); 
}
else
...
Share:
14,475
zachd1_618
Author by

zachd1_618

merge me

Updated on August 16, 2022

Comments

  • zachd1_618
    zachd1_618 over 1 year

    I have a C++ program that acts as a watchdog over others. If it detects that a process is no longer running, it restarts it via system. The problem is, if I kill the watchdog process, any processes it has started up also die.

    void* ProcessWatchdog::worker(void* arg)
    {
        //Check if process is running
        if( !processRunning )
            system("processName /path/to/processConfig.xml &");
    }
    

    The new child process gets started correctly, and runs without any problems. But when the parent (now this ProcessWatchdog process) dies, the child dies too. How can I spawn a child process that is fully independent from the parent?

    I've tried using pclose and popen, running shell scripts that start processes, and a few other tactics, but to no avail. I'm ignoring SIGHUP signals in the child processes, but they still die.

    So ideally, I'd like to tell the system to start a process that is wholly independent from the parent. I want the child's trace to end with the child, and for it/the system to have no idea that ProcessWatchdog started it in the first place.

    Is there a way I can do this?

    I'm writing this in C++, on Linux.