/* * Thread wrapper for fork(). */ pid_t rad_fork(void) { pid_t child_pid; if (!pool_initialized) return fork(); reap_children(); /* be nice to non-wait thingies */ if (fr_hash_table_num_elements(thread_pool.waiters) >= 1024) { return -1; } /* * Fork & save the PID for later reaping. */ child_pid = fork(); if (child_pid > 0) { int rcode; thread_fork_t *tf; tf = rad_malloc(sizeof(*tf)); memset(tf, 0, sizeof(*tf)); tf->pid = child_pid; pthread_mutex_lock(&thread_pool.wait_mutex); rcode = fr_hash_table_insert(thread_pool.waiters, tf); pthread_mutex_unlock(&thread_pool.wait_mutex); if (!rcode) { radlog(L_ERR, "Failed to store PID, creating what will be a zombie process %d", (int) child_pid); free(tf); } } /* * Return whatever we were told. */ return child_pid; }
/* * We don't want to catch SIGCHLD for a host of reasons. * * - exec_wait means that someone, somewhere, somewhen, will * call waitpid(), and catch the child. * * - SIGCHLD is delivered to a random thread, not the one that * forked. * * - if another thread catches the child, we have to coordinate * with the thread doing the waiting. * * - if we don't waitpid() for non-wait children, they'll be zombies, * and will hang around forever. * */ static void reap_children(void) { pid_t pid; int status; thread_fork_t mytf, *tf; pthread_mutex_lock(&thread_pool.wait_mutex); do { pid = waitpid(0, &status, WNOHANG); if (pid <= 0) break; mytf.pid = pid; tf = fr_hash_table_finddata(thread_pool.waiters, &mytf); if (!tf) continue; tf->status = status; tf->exited = 1; } while (fr_hash_table_num_elements(thread_pool.waiters) > 0); pthread_mutex_unlock(&thread_pool.wait_mutex); }
/* * (Re-)read radiusd.conf into memory. */ static int mod_instantiate(CONF_SECTION *conf, void *instance) { detail_instance_t *inst = instance; CONF_SECTION *cs; inst->name = cf_section_name2(conf); if (!inst->name) { inst->name = cf_section_name1(conf); } inst->lf= fr_logfile_init(inst); if (!inst->lf) { cf_log_err_cs(conf, "Failed creating log file context"); return -1; } /* * Suppress certain attributes. */ cs = cf_section_sub_find(conf, "suppress"); if (cs) { CONF_ITEM *ci; inst->ht = fr_hash_table_create(detail_hash, detail_cmp, NULL); for (ci = cf_item_find_next(cs, NULL); ci != NULL; ci = cf_item_find_next(cs, ci)) { char const *attr; DICT_ATTR const *da; if (!cf_item_is_pair(ci)) continue; attr = cf_pair_attr(cf_itemtopair(ci)); if (!attr) continue; /* pair-anoia */ da = dict_attrbyname(attr); if (!da) { cf_log_err_cs(conf, "No such attribute '%s'", attr); return -1; } /* * Be kind to minor mistakes. */ if (fr_hash_table_finddata(inst->ht, da)) { WARN("rlm_detail (%s): Ignoring duplicate entry '%s'", inst->name, attr); continue; } if (!fr_hash_table_insert(inst->ht, da)) { ERROR("rlm_detail (%s): Failed inserting '%s' into suppression table", inst->name, attr); return -1; } DEBUG("rlm_detail (%s): '%s' suppressed, will not appear in detail output", inst->name, attr); } /* * If we didn't suppress anything, delete the hash table. */ if (fr_hash_table_num_elements(inst->ht) == 0) { fr_hash_table_free(inst->ht); inst->ht = NULL; } } return 0; }