]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
track "nowait" children we've exec'd.
authorAlan T. DeKok <aland@freeradius.org>
Tue, 30 Jan 2018 16:32:24 +0000 (11:32 -0500)
committerAlan T. DeKok <aland@freeradius.org>
Tue, 30 Jan 2018 16:32:24 +0000 (11:32 -0500)
So that they can be cleaned up appropriately.

src/main/exec.c

index 0f2648478d4c919f9b7f1a8a3aa63953edde2432..c5ce6440202505fbef3a000ccf8107c62b2c6d02 100644 (file)
@@ -53,6 +53,19 @@ static pid_t waitpid_wrapper(pid_t pid, int *status)
 pid_t (*rad_fork)(void) = fork;
 pid_t (*rad_waitpid)(pid_t pid, int *status) = waitpid_wrapper;
 
+typedef struct fr_child_t {
+       fr_dlist_t      entry;
+       pid_t           pid;
+} fr_child_t;
+
+fr_thread_local_setup(fr_dlist_t *, fr_children); /* macro */
+
+static void _fr_children_free(void *arg)
+{
+       talloc_free(arg);
+}
+
+
 /** Start a process
  *
  * @param cmd Command to execute. This is parsed into argv[] parts, then each individual argv
@@ -90,6 +103,7 @@ pid_t radius_start_program(char const *cmd, REQUEST *request, bool exec_wait,
        char            *envp[MAX_ENVP];
        size_t          envlen = 0;
        TALLOC_CTX      *input_ctx = NULL;
+       fr_dlist_t      *list;
 
        if (exec_wait) {
                ERROR("Exec 'wait' is unsupported.");
@@ -113,6 +127,43 @@ pid_t radius_start_program(char const *cmd, REQUEST *request, bool exec_wait,
                for (i = 0; i < argc; i++) DEBUG3("arg[%d] %s", i, argv[i]);
        }
 
+       list = fr_children;
+       if (!list) {
+               list = talloc_zero(NULL, fr_dlist_t);
+               if (!list) {
+                       ERROR("Out of memory");
+                       return -1;
+               }
+
+               list->prev = list->next = list;
+
+               fr_thread_local_set_destructor(fr_children, _fr_children_free, list);
+       } else {
+               fr_dlist_t *entry, *next;
+
+               entry = list->next;
+
+               /*
+                *      Clean up the children.  ALL of them.  This is
+                *      slow as heck, but correct. :(
+                */
+               while (entry != list) {
+                       int status;
+                       fr_child_t *child;
+
+                       next = entry->next;
+
+                       child = fr_ptr_to_type(fr_child_t, entry, entry);
+                       pid = waitpid(child->pid, &status, WNOHANG);
+                       if (pid != 0) {
+                               fr_dlist_remove(entry);
+                               talloc_free(child);
+                       }
+
+                       entry = next;
+               }
+       }
+
 #ifndef __MINGW32__
        /*
         *      Open a pipe for child/parent communication, if necessary.
@@ -306,7 +357,7 @@ pid_t radius_start_program(char const *cmd, REQUEST *request, bool exec_wait,
        }
 
        /*
-        *      We're not waiting, exit, and ignore any child's status.
+        *      We're done.  Do any necessary cleanups.
         */
        if (exec_wait) {
                /*
@@ -322,6 +373,13 @@ pid_t radius_start_program(char const *cmd, REQUEST *request, bool exec_wait,
                        *output_fd = from_child[0];
                        close(from_child[1]);
                }
+
+       } else {
+               fr_child_t *child;
+
+               MEM(child = talloc_zero(fr_children, fr_child_t));
+               fr_dlist_insert_tail(fr_children, &child->entry);
+               child->pid = pid;
        }
 
        return pid;