void child_update(void) { pr_child_t *ch, *chn = NULL; if (!child_list) return; /* Scan the child list, removing those entries marked as 'dead'. */ for (ch = (pr_child_t *) child_list->xas_list; ch; ch = chn) { chn = ch->next; if (ch->ch_dead) { if (ch->ch_pipefd != -1) close(ch->ch_pipefd); xaset_remove(child_list, (xasetmember_t *) ch); destroy_pool(ch->ch_pool); } } /* If the child list is empty, recover the list pool memory. */ if (!child_list->xas_list) { destroy_pool(child_list->pool); child_list = NULL; } return; }
config_rec *pr_parser_config_ctxt_close(int *empty) { config_rec *c = *parser_curr_config; /* Note that if the current config is empty, it should simply be removed. * Such empty configs can happen for <Directory> sections that * contain no directives, for example. */ if (parser_curr_config == (config_rec **) parser_confstack->elts) { if (c != NULL && (!c->subset || !c->subset->xas_list)) { xaset_remove(c->set, (xasetmember_t *) c); destroy_pool(c->pool); if (empty) { *empty = TRUE; } } if (*parser_curr_config) { *parser_curr_config = NULL; } return NULL; } if (c != NULL && (!c->subset || !c->subset->xas_list)) { xaset_remove(c->set, (xasetmember_t *) c); destroy_pool(c->pool); if (empty) { *empty = TRUE; } } parser_curr_config--; parser_confstack->nelts--; return *parser_curr_config; }
/* Sentinel values: * * cmd_type = 0 * cmd_group = NULL * cmd_class = -1 */ int pr_stash_remove_cmd(const char *cmd_name, module *m, unsigned char cmd_type, const char *cmd_group, int cmd_class) { int count = 0, prev_idx, symtab_idx = 0; size_t cmd_namelen = 0; unsigned int hash; cmdtable *tab = NULL; if (cmd_name == NULL) { errno = EINVAL; return -1; } /* Don't forget to include one for the terminating NUL. */ cmd_namelen = strlen(cmd_name) + 1; hash = sym_type_hash(PR_SYM_CMD, cmd_name, cmd_namelen); symtab_idx = hash % PR_TUNABLE_HASH_TABLE_SIZE; prev_idx = -1; tab = pr_stash_get_symbol2(PR_SYM_CMD, cmd_name, NULL, &prev_idx, &hash); while (tab) { cmdtable *cmd_sym; pr_signals_handle(); /* Note: this works because of a hack: the symbol lookup functions set a * static pointer, cmd_curr_sym, to point to the struct stash just looked * up. cmd_curr_sym will not be NULL if pr_stash_get_symbol2() returns * non-NULL. */ cmd_sym = cmd_curr_sym->ptr.sym_cmd; if ((m == NULL || cmd_curr_sym->sym_module == m) && (cmd_type == 0 || cmd_sym->cmd_type == cmd_type) && (cmd_group == NULL || (cmd_group != NULL && cmd_sym->group != NULL && strcmp(cmd_sym->group, cmd_group) == 0)) && (cmd_class == -1 || cmd_sym->cmd_class == cmd_class)) { xaset_remove(cmd_symbol_table[symtab_idx], (xasetmember_t *) cmd_curr_sym); destroy_pool(cmd_curr_sym->sym_pool); cmd_curr_sym = NULL; tab = NULL; count++; } tab = pr_stash_get_symbol2(PR_SYM_CMD, cmd_name, tab, &prev_idx, &hash); } return count; }
int pr_timer_reset(int timerno, module *mod) { struct timer *t = NULL; if (!timers) { errno = EPERM; return -1; } if (_indispatch) { errno = EINTR; return -1; } pr_alarms_block(); if (!recycled) recycled = xaset_create(timer_pool, NULL); for (t = (struct timer *) timers->xas_list; t; t = t->next) { if (t->timerno == timerno && (t->mod == mod || mod == ANY_MODULE)) { t->count = t->interval; xaset_remove(timers, (xasetmember_t *) t); xaset_insert(recycled, (xasetmember_t *) t); nalarms++; /* The handle_alarm() function also readjusts the timers lists * as part of its processing, so it needs to be called when a timer * is reset. */ handle_alarm(); break; } } pr_alarms_unblock(); if (t != NULL) { pr_trace_msg("timer", 7, "reset timer ID %d ('%s', for module '%s')", t->timerno, t->desc, t->mod ? t->mod->name : "[none]"); return t->timerno; } return 0; }
int pr_stash_remove_conf(const char *directive_name, module *m) { int count = 0, prev_idx, symtab_idx = 0; size_t directive_namelen = 0; unsigned int hash; conftable *tab = NULL; if (directive_name == NULL) { errno = EINVAL; return -1; } /* Don't forget to include one for the terminating NUL. */ directive_namelen = strlen(directive_name) + 1; hash = sym_type_hash(PR_SYM_CONF, directive_name, directive_namelen); symtab_idx = hash % PR_TUNABLE_HASH_TABLE_SIZE; prev_idx = -1; tab = pr_stash_get_symbol2(PR_SYM_CONF, directive_name, NULL, &prev_idx, &hash); while (tab) { pr_signals_handle(); /* Note: this works because of a hack: the symbol lookup functions set a * static pointer, conf_curr_sym, to point to the struct stash just looked * up. conf_curr_sym will not be NULL if pr_stash_get_symbol2() returns * non-NULL. */ if (m == NULL || conf_curr_sym->sym_module == m) { xaset_remove(conf_symbol_table[symtab_idx], (xasetmember_t *) conf_curr_sym); destroy_pool(conf_curr_sym->sym_pool); conf_curr_sym = NULL; tab = NULL; count++; } tab = pr_stash_get_symbol2(PR_SYM_CONF, directive_name, tab, &prev_idx, &hash); } return count; }
void run_schedule(void) { sched_t *s, *snext; if (scheds == NULL || scheds->xas_list == NULL) { return; } for (s = (sched_t *) scheds->xas_list; s; s = snext) { snext = s->next; if (s->loops-- <= 0) { s->f(s->a1, s->a2, s->a3, s->a4); xaset_remove(scheds, (xasetmember_t *) s); destroy_pool(s->pool); } } }
void run_schedule(void) { sched_t *s, *snext; if (scheds == NULL || scheds->xas_list == NULL) { return; } for (s = (sched_t *) scheds->xas_list; s; s = snext) { snext = s->next; pr_signals_handle(); if (s->nloops-- <= 0) { s->cb(s->arg1, s->arg2, s->arg3, s->arg4); xaset_remove(scheds, (xasetmember_t *) s); destroy_pool(s->pool); } } }
/* This function does the work of iterating through the list of registered * timers, checking to see if their callbacks should be invoked and whether * they should be removed from the registration list. Its return value is * the amount of time remaining on the first timer in the list. */ static int process_timers(int elapsed) { struct timer *t = NULL, *next = NULL; if (!recycled) recycled = xaset_create(timer_pool, NULL); if (!elapsed && !recycled->xas_list) { if (!timers) return 0; return (timers->xas_list ? ((struct timer *) timers->xas_list)->count : 0); } /* Critical code, no interruptions please */ if (_indispatch) return 0; pr_alarms_block(); _indispatch++; if (elapsed) { for (t = (struct timer *) timers->xas_list; t; t = next) { /* If this timer has already been handled, skip */ next = t->next; if (t->remove) { /* Move the timer onto the free_timers chain, for later reuse. */ xaset_remove(timers, (xasetmember_t *) t); xaset_insert(free_timers, (xasetmember_t *) t); } else if ((t->count -= elapsed) <= 0) { /* This timer's interval has elapsed, so trigger its callback. */ pr_trace_msg("timer", 4, "%ld %s for timer ID %d ('%s', for module '%s') elapsed, invoking " "callback (%p)", t->interval, t->interval != 1 ? "seconds" : "second", t->timerno, t->desc ? t->desc : "<unknown>", t->mod ? t->mod->name : "<none>", t->callback); if (t->callback(t->interval, t->timerno, t->interval - t->count, t->mod) == 0) { /* A return value of zero means this timer is done, and can be * removed. */ xaset_remove(timers, (xasetmember_t *) t); xaset_insert(free_timers, (xasetmember_t *) t); } else { /* A non-zero return value from a timer callback signals that * the timer should be reused/restarted. */ pr_trace_msg("timer", 6, "restarting timer ID %d ('%s'), as per " "callback", t->timerno, t->desc ? t->desc : "<unknown>"); xaset_remove(timers, (xasetmember_t *) t); t->count = t->interval; xaset_insert(recycled, (xasetmember_t *) t); } } } } /* Put the recycled timers back into the main timer list. */ while ((t = (struct timer *) recycled->xas_list) != NULL) { xaset_remove(recycled, (xasetmember_t *) t); xaset_insert_sort(timers, (xasetmember_t *) t, TRUE); } _indispatch--; pr_alarms_unblock(); /* If no active timers remain in the list, there is no reason to set the * SIGALRM handle. */ return (timers->xas_list ? ((struct timer *) timers->xas_list)->count : 0); }
int pr_timer_add(int seconds, int timerno, module *mod, callback_t cb, const char *desc) { struct timer *t = NULL; if (seconds <= 0 || cb == NULL || desc == NULL) { errno = EINVAL; return -1; } if (!timers) timers = xaset_create(timer_pool, (XASET_COMPARE) timer_cmp); /* Check to see that, if specified, the timerno is not already in use. */ if (timerno >= 0) { for (t = (struct timer *) timers->xas_list; t; t = t->next) { if (t->timerno == timerno) { errno = EPERM; return -1; } } } if (!free_timers) free_timers = xaset_create(timer_pool, NULL); /* Try to use an old timer first */ pr_alarms_block(); t = (struct timer *) free_timers->xas_list; if (t != NULL) { xaset_remove(free_timers, (xasetmember_t *) t); } else { if (timer_pool == NULL) { timer_pool = make_sub_pool(permanent_pool); pr_pool_tag(timer_pool, "Timer Pool"); } /* Must allocate a new one */ t = palloc(timer_pool, sizeof(struct timer)); } if (timerno < 0) { /* Dynamic timer */ if (dynamic_timerno < PR_TIMER_DYNAMIC_TIMERNO) { dynamic_timerno = PR_TIMER_DYNAMIC_TIMERNO; } timerno = dynamic_timerno++; } t->timerno = timerno; t->count = t->interval = seconds; t->callback = cb; t->mod = mod; t->remove = 0; t->desc = desc; /* If called while _indispatch, add to the recycled list to prevent * list corruption */ if (_indispatch) { if (!recycled) recycled = xaset_create(timer_pool, NULL); xaset_insert(recycled, (xasetmember_t *) t); } else { xaset_insert_sort(timers, (xasetmember_t *) t, TRUE); nalarms++; set_sig_alarm(); /* The handle_alarm() function also readjusts the timers lists * as part of its processing, so it needs to be called when a timer * is added. */ handle_alarm(); } pr_alarms_unblock(); pr_trace_msg("timer", 7, "added timer ID %d ('%s', for module '%s'), " "triggering in %ld %s", t->timerno, t->desc, t->mod ? t->mod->name : "[none]", t->interval, t->interval != 1 ? "seconds" : "second"); return timerno; }
int pr_timer_remove(int timerno, module *mod) { struct timer *t = NULL, *tnext = NULL; int nremoved = 0; /* If there are no timers currently registered, do nothing. */ if (!timers) return 0; pr_alarms_block(); for (t = (struct timer *) timers->xas_list; t; t = tnext) { tnext = t->next; if ((timerno < 0 || t->timerno == timerno) && (mod == ANY_MODULE || t->mod == mod)) { nremoved++; if (_indispatch) { t->remove++; } else { xaset_remove(timers, (xasetmember_t *) t); xaset_insert(free_timers, (xasetmember_t *) t); nalarms++; /* The handle_alarm() function also readjusts the timers lists * as part of its processing, so it needs to be called when a timer * is removed. */ handle_alarm(); } pr_trace_msg("timer", 7, "removed timer ID %d ('%s', for module '%s')", t->timerno, t->desc, t->mod ? t->mod->name : "[none]"); } /* If we are removing a specific timer, break out of the loop now. * Otherwise, keep removing any matching timers. */ if (nremoved > 0 && timerno >= 0) { break; } } pr_alarms_unblock(); if (nremoved == 0) { errno = ENOENT; return -1; } /* If we removed a specific timer because of the given timerno, return * that timerno value. */ if (timerno >= 0) { return timerno; } return nremoved; }
static int init_standalone_bindings(void) { int res = 0; server_rec *serv = NULL; unsigned char *default_server = NULL, is_default = FALSE; /* If a port is set to zero, the address/port is not bound to a socket * at all. */ if (main_server->ServerPort) { /* If SocketBindTight is off, then pr_inet_create_conn() will * create and bind to a wildcard socket. However, should it be an * IPv4 or an IPv6 wildcard socket? */ if (!SocketBindTight) { #ifdef PR_USE_IPV6 if (pr_netaddr_use_ipv6()) { pr_inet_set_default_family(NULL, AF_INET6); } else { int default_family; default_family = pr_netaddr_get_family(main_server->addr); pr_inet_set_default_family(NULL, default_family); } #else pr_inet_set_default_family(NULL, pr_netaddr_get_family(main_server->addr)); #endif /* PR_USE_IPV6 */ } main_server->listen = pr_ipbind_get_listening_conn(main_server, (SocketBindTight ? main_server->addr : NULL), main_server->ServerPort); if (main_server->listen == NULL) { return -1; } } else { main_server->listen = NULL; } default_server = get_param_ptr(main_server->conf, "DefaultServer", FALSE); if (default_server != NULL && *default_server == TRUE) { is_default = TRUE; } if (main_server->ServerPort || is_default) { PR_CREATE_IPBIND(main_server, main_server->addr, main_server->ServerPort); PR_OPEN_IPBIND(main_server->addr, main_server->ServerPort, main_server->listen, is_default, TRUE, TRUE); PR_ADD_IPBINDS(main_server); } for (serv = main_server->next; serv; serv = serv->next) { config_rec *c; int is_namebind = FALSE; /* See if this server is a namebind, to be part of an existing ipbind. */ c = find_config(serv->conf, CONF_PARAM, "ServerAlias", FALSE); while (c != NULL) { pr_signals_handle(); res = pr_namebind_create(serv, c->argv[0], serv->addr, serv->ServerPort); if (res == 0) { is_namebind = TRUE; res = pr_namebind_open(c->argv[0], serv->addr, serv->ServerPort); if (res < 0) { pr_log_pri(PR_LOG_NOTICE, "%s:%d: notice: unable to open namebind '%s': %s", __FILE__, __LINE__, (char *) c->argv[0], strerror(errno)); } } else { pr_log_pri(PR_LOG_NOTICE, "unable to create namebind for '%s' to %s#%u: %s", (char *) c->argv[0], pr_netaddr_get_ipstr(serv->addr), serv->ServerPort, strerror(errno)); } c = find_config_next(c, c->next, CONF_PARAM, "ServerAlias", FALSE); } if (is_namebind == TRUE) { continue; } if (serv->ServerPort != main_server->ServerPort || SocketBindTight || !main_server->listen) { is_default = FALSE; default_server = get_param_ptr(serv->conf, "DefaultServer", FALSE); if (default_server != NULL && *default_server == TRUE) { is_default = TRUE; } if (serv->ServerPort) { if (!SocketBindTight) { #ifdef PR_USE_IPV6 if (pr_netaddr_use_ipv6()) { pr_inet_set_default_family(NULL, AF_INET6); } else { pr_inet_set_default_family(NULL, pr_netaddr_get_family(serv->addr)); } #else pr_inet_set_default_family(NULL, pr_netaddr_get_family(serv->addr)); #endif /* PR_USE_IPV6 */ } serv->listen = pr_ipbind_get_listening_conn(serv, (SocketBindTight ? serv->addr : NULL), serv->ServerPort); if (serv->listen == NULL) { return -1; } PR_CREATE_IPBIND(serv, serv->addr, serv->ServerPort); PR_OPEN_IPBIND(serv->addr, serv->ServerPort, serv->listen, is_default, FALSE, TRUE); PR_ADD_IPBINDS(serv); } else if (is_default) { serv->listen = NULL; PR_CREATE_IPBIND(serv, serv->addr, serv->ServerPort); PR_OPEN_IPBIND(serv->addr, serv->ServerPort, serv->listen, is_default, FALSE, TRUE); PR_ADD_IPBINDS(serv); } else { serv->listen = NULL; } } else { /* Because this server is sharing the connection with the main server, * we need a cleanup handler to remove the server's reference when the * original connection's pool is destroyed. */ is_default = FALSE; default_server = get_param_ptr(serv->conf, "DefaultServer", FALSE); if (default_server != NULL && *default_server == TRUE) { is_default = TRUE; } serv->listen = main_server->listen; register_cleanup(serv->listen->pool, &serv->listen, server_cleanup_cb, server_cleanup_cb); PR_CREATE_IPBIND(serv, serv->addr, serv->ServerPort); PR_OPEN_IPBIND(serv->addr, serv->ServerPort, NULL, is_default, FALSE, TRUE); PR_ADD_IPBINDS(serv); } } /* Any "unclaimed" listening conns can be removed and closed. */ if (listening_conn_list) { struct listener_rec *lr, *lrn; for (lr = (struct listener_rec *) listening_conn_list->xas_list; lr; lr = lrn) { lrn = lr->next; if (!lr->claimed) { xaset_remove(listening_conn_list, (xasetmember_t *) lr); destroy_pool(lr->pool); } } } return 0; }