Double fork to release child to be reaped by init

If a task forks, it must clean up after its dead children or the system
will have zombie tasks that will ultimately be reparented to init, but
only after the parent dies.

Cleanup can be done in a variety of ways: waitpid, ignoring SIGCHLD, or
forking twice and allowing the grandchild to be reparented to init and
calling waitpid on the child.

Change-Id: Ic48ea583b37e065da34aa4acfd74b6e1b1c2d04f
Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
diff --git a/download_manager.cpp b/download_manager.cpp
index 3affd1d..6bbe604 100644
--- a/download_manager.cpp
+++ b/download_manager.cpp
@@ -67,19 +67,45 @@
 
     if (pid == 0)
     {
-        // child process
-        execl("/usr/bin/tftp", "tftp", "-g", "-r", fileName.c_str(),
-              serverAddress.c_str(), "-l",
-              (std::string{IMG_UPLOAD_DIR} + '/' + fileName).c_str(), (char*)0);
-        // execl only returns on fail
-        log<level::ERR>("Error occurred during the TFTP call");
-        elog<InternalFailure>();
+        pid_t nextPid = fork();
+        if (nextPid == 0)
+        {
+            // child process
+            execl("/usr/bin/tftp", "tftp", "-g", "-r", fileName.c_str(),
+                  serverAddress.c_str(), "-l",
+                  (std::string{IMG_UPLOAD_DIR} + '/' + fileName).c_str(),
+                  (char*)0);
+            // execl only returns on fail
+            log<level::ERR>("Error occurred during the TFTP call");
+            elog<InternalFailure>();
+        }
+        else if (nextPid < 0)
+        {
+            log<level::ERR>("Error occurred during fork");
+            elog<InternalFailure>();
+        }
+        // do nothing as parent if all is going well
+        // when parent exits, child will be reparented under init
+        // and then be reaped properly
+        exit(0);
     }
     else if (pid < 0)
     {
         log<level::ERR>("Error occurred during fork");
         elog<InternalFailure>();
     }
+    else
+    {
+        int status;
+        if (waitpid(pid, &status, 0) < 0)
+        {
+            log<level::ERR>("waitpid error");
+        }
+        else if (WEXITSTATUS(status) != 0)
+        {
+            log<level::ERR>("failed to launch tftp");
+        }
+    }
 
     return;
 }