From 0c930fc6d3fde82e800c685ec1df92ddfa23fe09 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Thu, 21 Jan 2016 08:31:31 +0200 Subject: Cleanup: redo configuration file handling and dependency tracking. Implement clean configuration reload on SIGHUP. Use SIGUSR1 to restart the program (previously initiated by SIGHUP). * src/Makefile.am (pies_SOURCES): Add comp.c * src/comp.c: New file. * src/acl.c (pies_acl_free): Don't coredump on NULL arg. (_parse_from): Set cmp function for the sockaddr list. (_acl_common_section_parser): Set cmp function for the ACL (pies_acl_cmp): New function. * src/acl.h (pies_acl_cmp): New proto. * src/cmdline.opt: Remove option --dump-prereq. Add options --trace-prereq and --trace-depend. * src/ctl.c: Use prog_tag to access tag of struct prog. * src/depmap.c (depmap_clear) (depmap_clear_all): New functions. * src/inetd.c (inetd_conf_file): Don't register prog right away. This is done later in component_config_commit. (inetd_parse_conf): Rename to inetd_config_parse. * src/limits.c (limits_cmp): New function. * src/pies.c (config_file): Replace with struct config_syntax. (str_to_config_syntax): Return a pointer to struct config_syntax. (add_config): Rename to config_file_add. (config_file_add_type): New function. (return_code_keywords, create_action): Change handling of actions. (return_code_section_parser): Likewise. (component_verify, component_create) (component_free, component_finish): Move to comp.c (config_parse): Remove. (pies_config_parse): New function. (pies_read_config,pies_reload): New function. (pies_reload): Rename to request_reload. (pies_status): Rename to request_status. (pies_stop): Rename to request_stop. (main): Change configuration file handling. SIGHUP reloads configuration, instead of restarting the program. (default_sigv,sig_handler): Handle SIGUSR1. * src/pies.h (component): New members: prev, next, listidx, arridx, ref_count, prog. Remove act_head, act_tail, act_temp. Add new prototypes. * src/prog.h (prog): Remove tag and prereq. * src/progman.c (prog_tag): New function. (destroy_prog): Update component reference count. (register_redir): Likewise. (register_prog0): Take one argument. Update component reference count. (register_prog): Update comp->prog (prog_rebuild_prerequisites): Remove. (component_fixup_depend): Remove. (fixup_prerequisites,rebuild_prerequisites) (print_dep,progman_dump_prereq) (progman_dump_depmap,progman_build_depmap): Remove. (prog_start_prerequisites): Scan depmap to find prerequisites. (prog_stop_dependents): Likewise. (progman_wait): Remove. (progman_wait_until): New function. (progman_stop): Rewrite using progman_wait_until. (react): Rewrite using grecs_list * src/sysvinit.c: Use prog_tag when needed. * src/userprivs.c (pies_privs_cmp, pies_privs_free): New functions. * grecs: Update. * lib/safe_strcmp.c: New file. * lib/Makefile.am: Add safe_strcmp.c * lib/libpies.h (safe_strcmp): New proto. --- grecs | 2 +- lib/Makefile.am | 1 + lib/libpies.h | 1 + lib/safe_strcmp.c | 29 ++ src/Makefile.am | 1 + src/acl.c | 70 ++++- src/acl.h | 3 +- src/cmdline.opt | 22 +- src/comp.c | 817 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/ctl.c | 4 +- src/depmap.c | 28 +- src/inetd.c | 7 +- src/limits.c | 11 +- src/pies.c | 535 ++++++++++------------------------- src/pies.h | 57 +++- src/prog.h | 7 +- src/progman.c | 538 +++++++++++++---------------------- src/sysvinit.c | 43 +-- src/userprivs.c | 23 ++ 19 files changed, 1399 insertions(+), 800 deletions(-) create mode 100644 lib/safe_strcmp.c create mode 100644 src/comp.c diff --git a/grecs b/grecs index ca94270..08070e4 160000 --- a/grecs +++ b/grecs @@ -1 +1 @@ -Subproject commit ca94270a5e30add9b364d32220fb38d457ebd3f2 +Subproject commit 08070e48d83cd34cddb08be33cf4993fc096c9c4 diff --git a/lib/Makefile.am b/lib/Makefile.am index a0d6614..8f07544 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -27,6 +27,7 @@ libpies_a_SOURCES=\ parsetime.c\ proctitle.c\ pp.c\ + safe_strcmp.c\ split3.c\ strtotok.c\ url.c diff --git a/lib/libpies.h b/lib/libpies.h index 1c83b8e..5a7dd73 100644 --- a/lib/libpies.h +++ b/lib/libpies.h @@ -53,6 +53,7 @@ int toktostr (struct tokendef *tab, int tok, const char **pres); int is_array_member (char * const * ar, char const *str); int array_index (char * const *ar, char const *str); int strsplit3 (const char *input, char *result[3], int flag); +int safe_strcmp (char const *a, char const *b); /* url.c */ struct pies_url diff --git a/lib/safe_strcmp.c b/lib/safe_strcmp.c new file mode 100644 index 0000000..e73176d --- /dev/null +++ b/lib/safe_strcmp.c @@ -0,0 +1,29 @@ +/* This file is part of GNU Pies. + Copyright (C) 2015, 2016 Sergey Poznyakoff + + GNU Pies is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GNU Pies is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Pies. If not, see . */ + +#ifdef HAVE_CONFIG_H +# include +#endif +#include "libpies.h" + +int +safe_strcmp (char const *a, char const *b) +{ + if (!a || !b) + return a != b; + return strcmp (a, b); +} + diff --git a/src/Makefile.am b/src/Makefile.am index 3f29b4e..a637077 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -19,6 +19,7 @@ bin_PROGRAMS = piesctl pies_SOURCES = \ acl.c\ + comp.c\ ctl.c\ depmap.c\ diag.c\ diff --git a/src/acl.c b/src/acl.c index a96eb77..e7523f5 100644 --- a/src/acl.c +++ b/src/acl.c @@ -122,10 +122,13 @@ pies_acl_create (const char *name, grecs_locus_t *locus) void pies_acl_free (pies_acl_t acl) { - free (acl->name); - grecs_locus_free (&acl->locus); - grecs_list_free (acl->list); - free (acl); + if (acl) + { + free (acl->name); + grecs_locus_free (&acl->locus); + grecs_list_free (acl->list); + free (acl); + } } static struct pies_sockaddr * @@ -252,6 +255,19 @@ _parse_sockaddr (struct acl_entry *entry, const grecs_value_t *value) return 0; } +static int +sockaddr_cmp (void const *a, void const *b) +{ + struct pies_sockaddr const *ap = a; + struct pies_sockaddr const *bp = b; + + if (ap->netmask != bp->netmask) + return 1; + if (ap->salen != bp->salen) + return 1; + return memcmp (&ap->sa, &bp->sa, ap->salen); +} + static void sockaddr_free (void *p) { @@ -285,6 +301,7 @@ _parse_from (struct acl_entry *entry, size_t argc, grecs_value_t **argv) } entry->sockaddrs = grecs_list_create (); + entry->sockaddrs->cmp = sockaddr_cmp; entry->sockaddrs->free_entry = sockaddr_free; if (argv[0]->type == GRECS_TYPE_STRING) { @@ -433,7 +450,37 @@ parse_acl_line (grecs_locus_t *locus, int allow, pies_acl_t acl, grecs_list_append (acl->list, entry); return 0; } + +static int +acl_entry_cmp (void const *a, void const *b) +{ + struct acl_entry const *ap = a; + struct acl_entry const *bp = b; + size_t i; + + if (ap->allow != bp->allow) + return 1; + if (ap->authenticated != bp->authenticated) + return 1; + if (pies_acl_cmp (ap->acl, bp->acl)) + return 1; + if (ap->name_match != bp->name_match) + return 1; + if (ap->names && bp->names) + { + for (i = 0; ap->names[i]; i++) + if (!bp->names[i] || strcmp (ap->names[i], bp->names[i])) + return 1; + if (bp->names[i]) + return 1; + } + else if (ap->names || bp->names) + return 1; + + return grecs_list_compare (ap->sockaddrs, bp->sockaddrs); +} + #define ACL_TAG_NONE 0 #define ACL_TAG_IGNORE 1 #define ACL_TAG_OPTIONAL 2 @@ -492,6 +539,11 @@ _acl_common_section_parser (enum grecs_callback_command cmd, break; case grecs_callback_section_end: + acl = *pacl; + if (acl->list) + acl->list->cmp = acl_entry_cmp; + break; + case grecs_callback_set_value: break; } @@ -775,3 +827,13 @@ pies_acl_lookup (const char *name) samp.name = (char *) name; return grecs_symtab_lookup_or_install (acl_table, &samp, NULL); } + +int +pies_acl_cmp (struct pies_acl *a, struct pies_acl *b) +{ + if (!a) + return !!b; + else + return 1; + return grecs_list_compare (a->list, b->list); +} diff --git a/src/acl.h b/src/acl.h index 757104d..db65e10 100644 --- a/src/acl.h +++ b/src/acl.h @@ -1,5 +1,5 @@ /* This file is part of GNU Pies - Copyright (C) 2009-2013 Sergey Poznyakoff + Copyright (C) 2009-2016 Sergey Poznyakoff GNU Pies is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -26,6 +26,7 @@ struct acl_input pies_acl_t pies_acl_create (const char *name, grecs_locus_t *locus); void pies_acl_free (pies_acl_t acl); +int pies_acl_cmp (struct pies_acl *a, struct pies_acl *b); int pies_acl_check (pies_acl_t acl, struct acl_input *input, int result); int parse_acl_line (grecs_locus_t *locus, int allow, pies_acl_t acl, grecs_value_t *value); diff --git a/src/cmdline.opt b/src/cmdline.opt index f43d147..389cea7 100644 --- a/src/cmdline.opt +++ b/src/cmdline.opt @@ -26,7 +26,7 @@ GROUP(Operation Mode) OPTION(config-file,c,FILE, []) BEGIN - add_config (current_syntax, optarg); + config_file_add (current_syntax, optarg); END OPTION(config-help,,, @@ -60,7 +60,7 @@ OPTION(inetd,i,, BEGIN if (!instance) instance = "inetd"; - current_syntax = CONF_INETD; + current_syntax = &config_syntax_tab[CONF_INETD]; inetd_mode = 1; END @@ -91,7 +91,8 @@ END OPTION(syntax,,[<{pies|meta1|inetd|inittab}>], []) BEGIN - if (str_to_config_syntax (optarg, ¤t_syntax)) + current_syntax = str_to_config_syntax (optarg); + if (!current_syntax) { logmsg (LOG_ERR, _("unknown syntax type: %s"), optarg); exit (EX_USAGE); @@ -152,7 +153,7 @@ OPTION(restart-component,R,, []) BEGIN log_to_stderr_only = 1; - command = COM_RESTART; + command = COM_RESTART_COMPONENT; END OPTION(status,s,, @@ -178,11 +179,18 @@ BEGIN command = COM_DUMP_DEPMAP; END -OPTION(dump-prereq,,, - []) +OPTION(trace-depend,,, + []) BEGIN log_to_stderr_only = 1; - command = COM_DUMP_PREREQ; + command = COM_TRACE_DEPEND; +END + +OPTION(trace-prereq,,, + []) +BEGIN + log_to_stderr_only = 1; + command = COM_TRACE_PREREQ; END OPTION(source-info,,, diff --git a/src/comp.c b/src/comp.c new file mode 100644 index 0000000..6f8e11f --- /dev/null +++ b/src/comp.c @@ -0,0 +1,817 @@ +/* This file is part of GNU Pies. + Copyright (C) 2016 Sergey Poznyakoff + + GNU Pies is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GNU Pies is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Pies. If not, see . */ + +#include "pies.h" +#include "prog.h" +#include + +struct complist +{ + struct component *head; + struct component *tail; +}; + +static struct complist comp_list[2]; +static int cur; + +static struct component **comp_array; +static size_t comp_count; + +static pies_depmap_t depmap; + +static int +next_index (void) +{ + return (cur + 1) % ARRAY_SIZE (comp_list); +} + +static int +prev_index (void) +{ + return (cur + ARRAY_SIZE (comp_list) - 1) % ARRAY_SIZE (comp_list); +} + +void +component_link (struct component *comp, struct component *ref, int before) +{ + if (!ref) + { + struct complist *list = &comp_list[comp->listidx]; + + comp->next = NULL; + comp->prev = list->tail; + if (list->tail) + list->tail->next = comp; + else + list->head = comp; + list->tail = comp; + } + else if (before) + component_link (comp, ref->prev, 0); + else + { + struct complist *list = &comp_list[comp->listidx]; + struct component *x; + + assert (comp->listidx == ref->listidx); + + comp->prev = ref; + + if ((x = ref->next)) + x->prev = comp; + else + list->tail = comp; + + ref->next = comp; + } +} + +void +component_unlink (struct component *comp) +{ + struct complist *list = &comp_list[comp->listidx]; + struct component *x; + + if ((x = comp->prev)) + x->next = comp->next; + else + list->head = comp->next; + if ((x = comp->next)) + x->prev = comp->prev; + else + list->tail = comp->prev; +} + +struct component * +component_lookup_tag (int idx, const char *tag) +{ + struct complist *list = &comp_list[idx]; + struct component *comp; + + for (comp = list->head; comp; comp = comp->next) + if (strcmp (comp->tag, tag) == 0) + break; + + return comp; +} + +ssize_t +component_lookup_index (const char *tag) +{ + size_t i; + + for (i = 0; i < comp_count; i++) + if (comp_array[i] && strcmp (comp_array[i]->tag, tag) == 0) + return i; + return -1; +} + +struct component * +component_create (const char *name) +{ + struct component *comp = component_lookup_tag (cur, name); + if (!comp) + { + comp = grecs_zalloc (sizeof (*comp)); + comp->listidx = cur; + comp->facility = log_facility; + comp->redir[RETR_OUT].type = comp->redir[RETR_ERR].type = redir_null; + comp->tag = grecs_strdup (name); + comp->socket_type = SOCK_STREAM; + component_link (comp, NULL, 0); + } + return comp; +} + +void +component_free (struct component *comp) +{ + size_t i; + + component_unlink (comp); + free (comp->tag); + free (comp->program); + if (comp->argv) + { + for (i = 0; i < comp->argc; i++) + free (comp->argv[i]); + free (comp->argv); + } + if (comp->env) + { + for (i = 0; comp->env[i]; i++) + free (comp->env[i]); + free (comp->env); + } + free (comp->dir); + grecs_list_free (comp->prereq); + grecs_list_free (comp->depend); + free (comp->rmfile); + pies_privs_free (&comp->privs); + free (comp->runlevels); + free_limits (comp->limits); + free (comp->runlevels); + free (comp->service); + pies_url_destroy (&comp->socket_url); + free (comp->pass_fd_socket); + free (comp->tcpmux); + free (comp->access_denied_message); + free (comp->max_instances_message); + free (comp->max_ip_connections_message); + free_redirector (&comp->redir[0]); + free_redirector (&comp->redir[1]); + grecs_list_free (comp->act_list); + pies_acl_free (comp->list_acl); + pies_acl_free (comp->adm_acl); + free (comp); +} + +void +component_ref_incr (struct component *comp) +{ + ++comp->ref_count; +} + +void +component_ref_decr (struct component *comp) +{ + assert (comp->ref_count > 0); + if (--comp->ref_count == 0) + component_free (comp); +} + +static int +argvcmp (char **a, char **b) +{ + size_t i; + + if (!a != !b) + return 1; + + for (i = 0; a[i]; i++) + if (!b[i] || strcmp (b[i], a[i])) + return 1; + return !!b[i]; +} + +static int +urlcmp (struct pies_url *a, struct pies_url *b) +{ + if (!a) + return !!b; + else if (!b) + return 1; + return safe_strcmp (a->string, b->string); +} + +static int +redirector_cmp (struct redirector const *a, struct redirector const *b) +{ + if (a->type != b->type) + return 1; + switch (a->type) + { + case redir_null: + break; + + case redir_syslog: + if (a->v.prio != b->v.prio) + return 1; + break; + + case redir_file: + if (safe_strcmp (a->v.file, b->v.file)) + return 1; + } + + return 0; +} + +static int +component_match (struct component *comp, struct component *ref) +{ +#define MATCH(cond) do if (cond) return 1; while (0) +#define EQ(memb) MATCH (comp->memb != ref->memb) +#define FN(memb,fun) MATCH (fun (comp->memb, ref->memb)) +#define FNP(memb,fun) MATCH (fun (&comp->memb, &ref->memb)) + + EQ (mode); + FN (tag, safe_strcmp); + FN (program, safe_strcmp); + EQ (argc); + FN (argv, argvcmp); + FN (dir, safe_strcmp); + FN (prereq, grecs_list_compare); + FN (depend, grecs_list_compare); + EQ (flags); + EQ (max_instances); + FN (rmfile, safe_strcmp); + FNP (privs, pies_privs_cmp); + FN (limits, limits_cmp); + FN (runlevels, safe_strcmp); + EQ (max_rate); + EQ (max_ip_connections); + EQ (socket_type); + EQ (builtin); + FN (service, safe_strcmp); + FN (socket_url, urlcmp); + FN (pass_fd_socket, safe_strcmp); + EQ (pass_fd_timeout); + FN (acl, pies_acl_cmp); + FN (tcpmux, safe_strcmp); + EQ (facility); + FNP (redir[0], redirector_cmp); + FNP (redir[1], redirector_cmp); +#undef MATCH +#undef EQ +#undef FN +#undef FNP + + return 0; +} + +static struct component * +complist_find_match (int idx, struct component *ref) +{ + struct complist *list = &comp_list[idx]; + struct component *comp; + + for (comp = list->head; comp && component_match (comp, ref); + comp = comp->next) + ; + return comp; +} + +static void +strasgn (char **dst, char **src) +{ + free (*dst); + *dst = *src; + *src = NULL; +} + +void +component_merge (struct component *comp, struct component *ref) +{ + strasgn (&comp->tag, &ref->tag); + + strasgn (&comp->access_denied_message, &ref->access_denied_message); + strasgn (&comp->max_instances_message, &ref->max_instances_message); + strasgn (&comp->max_ip_connections_message, + &ref->max_ip_connections_message); + + grecs_list_free (comp->act_list); + comp->act_list = ref->act_list; + ref->act_list = NULL; + + pies_acl_free (comp->list_acl); + comp->list_acl = ref->list_acl; + ref->list_acl = NULL; + + pies_acl_free (comp->adm_acl); + comp->adm_acl = ref->adm_acl; + ref->adm_acl = NULL; +} + +int +component_is_active (struct component *comp) +{ + return comp->listidx == cur; +} + +void +component_config_begin (void) +{ + cur = next_index (); +} + +void +component_config_rollback (void) +{ + struct complist *list = &comp_list[cur]; + while (list->head) + component_free (list->head); + cur = prev_index (); +} + +static int +cb_terminate_prog (struct prog *prog, void *data) +{ + if (IS_COMPONENT (prog) && !component_is_active (prog->v.p.comp)) + { + progman_stop_component (prog); + prog->v.p.comp->flags |= CF_DISABLED; + } + return 0; +} + +static int +cb_kill_prog (struct prog *prog, void *data) +{ + if (!(IS_COMPONENT (prog) && component_is_active (prog->v.p.comp))) + prog_stop (prog, SIGKILL); + return 0; +} + +static int +list_is_empty (void *p) +{ + struct complist *list = p; + return list->head == NULL; +} + +static int +list_str_cmp (const void *a, const void *b) +{ + return safe_strcmp (a, b); +} + +static void +component_log_dep (size_t idx) +{ + pies_depmap_pos_t pos; + size_t n; + + logmsg_printf (LOG_NOTICE, "%s -> ", comp_array[idx]->tag); + for (n = depmap_first (depmap, depmap_col, idx, &pos); + n != (size_t)-1; + n = depmap_next (depmap, pos)) + { + logmsg_printf (LOG_NOTICE, "%s -> ", comp_array[n]->tag); + } + depmap_end (pos); + logmsg_printf (LOG_NOTICE, "%s\n", comp_array[idx]->tag); +} + +void +component_build_depmap (void) +{ + size_t i; + pies_depmap_t dp; + + free (depmap); + depmap = depmap_alloc (comp_count); + for (i = 0; i < comp_count; i++) + { + struct component *comp = comp_array[i]; + struct grecs_list_entry *ep; + + if (comp->prereq) + for (ep = comp->prereq->head; ep; ep = ep->next) + { + char const *tag = ep->data; + ssize_t tgt = component_lookup_index (tag); + if (tgt < 0) + { + logmsg (LOG_ERR, + _("component %s depends on %s, " + "which is not declared"), + comp->tag, tag); + component_free (comp); + comp_array[i] = NULL; + depmap_clear_all (depmap, depmap_row, i); + depmap_clear_all (depmap, depmap_col, i); + continue; + } + depmap_set (depmap, i, tgt); + } + + if (comp->depend) + for (ep = comp->depend->head; ep; ep = ep->next) + { + char const *tag = ep->data; + ssize_t tgt = component_lookup_index (tag); + if (tgt < 0) + { + logmsg (LOG_ERR, + _("undefined component %s depends on %s"), + tag, comp->tag); + continue; + } + depmap_set (depmap, tgt, i); + } + } + + dp = depmap_copy (depmap); + depmap_tc (dp); + for (i = 0; i < comp_count; i++) + if (depmap_isset (dp, i, i)) + { + logmsg (LOG_ERR, _("component %s depends on itself"), + comp_array[i]->tag); + component_log_dep (i); + component_free (comp_array[i]); + comp_array[i] = NULL; + depmap_clear_all (depmap, depmap_row, i); + depmap_clear_all (depmap, depmap_col, i); + continue; + } + free (dp); +} + +void +component_config_commit (void) +{ + struct complist *list = &comp_list[cur]; + struct component *comp, *match; + int prev = prev_index (); + size_t i; + + /* Count available components and allocate array for them */ + for (comp = list->head, i = 0; comp; comp = comp->next, i++) + /* FIXME: component_compute_prereq (comp) */; + + comp_array = grecs_realloc (comp_array, i * sizeof (comp_array[0])); + comp_count = i; + + /* Rearrange components, registering prog entries for the new ones */ + for (comp = list->head, i = 0; comp; comp = comp->next, i++) + { + match = complist_find_match (prev, comp); + if (match) + { + component_merge (match, comp); + component_unlink (match); + match->listidx = cur; + component_link (match, comp, 1); + component_free (comp); + comp = match; + } + comp_array[i] = comp; + comp->arridx = i; + } + + /* Terminate orphaned progs */ + list = &comp_list[prev]; + if (list->head) + { + progman_foreach (cb_terminate_prog, NULL); + if (progman_wait_until (list_is_empty, list)) + { + progman_foreach (cb_kill_prog, NULL); + progman_wait_until (list_is_empty, list); + } + } + + /* Build dependency map */ + component_build_depmap (); + + /* Register new progs */ + for (comp = comp_list[cur].head; comp; comp = comp->next) + if (!comp->prog) + register_prog (comp); +} + +static int +component_verify (struct component *comp, grecs_locus_t *locus) +{ + int header = 0; + int i; +#define COMPERR(func, fmt, arg) \ + do \ + { \ + if (!header) \ + { \ + grecs_warning (locus, 0, _("in component %s:"), comp->tag); \ + header = 1; \ + } \ + func (locus, 0, fmt, arg); \ + } \ + while (0) + + if (comp->flags & CF_INTERNAL) + { + comp->mode = pies_comp_inetd; + if (!comp->service) + /* TRANSLATORS: do not translate quoted words, they are keywords. */ + COMPERR (grecs_error, + "%s", _("`internal' used without `service'")); + else + { + comp->builtin = inetd_builtin_lookup (comp->service, + comp->socket_type); + if (!comp->builtin) + COMPERR (grecs_error, + "%s", _("unknown internal service")); + if (comp->argv) + /* TRANSLATORS: do not translate quoted words, they are + keywords. */ + COMPERR (grecs_error, + "%s", _("`internal' used with `command'")); + } + } + else if (!comp->argv) + COMPERR (grecs_error, + "%s", _("missing command line")); + + if (ISCF_TCPMUX (comp->flags)) + { + comp->mode = pies_comp_inetd; + if ((comp->flags & (CF_TCPMUX | CF_TCPMUXPLUS)) + == (CF_TCPMUX | CF_TCPMUXPLUS)) + COMPERR (grecs_error, + "%s", _("both `tcpmux' and `tcpmuxplus' used")); + else if (!comp->service) + /* TRANSLATORS: do not translate quoted words, they are keywords. */ + COMPERR (grecs_error, + "%s", _("`internal' used without `service'")); + } + + if (comp->pass_fd_socket && comp->mode != pies_comp_pass_fd) + COMPERR (grecs_error, + "%s", _("pass-fd-socket ignored: wrong mode")); + switch (comp->mode) + { + case pies_comp_exec: + if (comp->socket_url) + COMPERR (grecs_error, + "%s", _("socket ignored: wrong mode")); + break; + + case pies_comp_pass_fd: + if (!comp->pass_fd_socket) + COMPERR (grecs_error, + "%s", _("must supply pass-fd-socket in this mode")); + else if (comp->pass_fd_socket[0] != '/') + { + if (comp->dir) + { + char *p = mkfilename (comp->dir, comp->pass_fd_socket, NULL); + /*free (comp->pass_fd_socket);*/ + comp->pass_fd_socket = p; + } + else + COMPERR (grecs_error, + "%s", _("pass-fd-socket must be an absolute " + "file name or chdir must be specified")); + } + /* Fall through */ + + case pies_comp_accept: + if (!comp->socket_url) + { + COMPERR (grecs_error, + "%s", _("socket must be specified in this mode")); + return 1; + } + break; + + case pies_comp_inetd: + if (ISCF_TCPMUX (comp->flags)) + { + pies_url_destroy (&comp->socket_url); + if (!comp->tcpmux) + { + COMPERR (grecs_warning, + "%s", + _("TCPMUX master not specified, assuming \"tcpmux\"")); + comp->tcpmux = grecs_strdup ("tcpmux"); + } + } + else if (comp->tcpmux) + { + comp->flags |= CF_TCPMUX; + pies_url_destroy (&comp->socket_url); + } + else if (!comp->socket_url) + { + COMPERR (grecs_error, + "%s", _("socket must be specified in this mode")); + return 1; + } + default: + /* FIXME: more checks perhaps */ + break; + } + + if (comp->mode == pies_comp_inetd) + { + if ((comp->flags & CF_WAIT) && comp->socket_type == SOCK_STREAM) + { + if (comp->max_instances) + COMPERR (grecs_error, "%s", _("max-instances ignored")); + else + comp->max_instances = 1; + } + } + else if (comp->flags & CF_WAIT) + { + /* TRANSLATORS: `wait' is a keywords, do not translate. */ + COMPERR (grecs_error, "%s", _("wait is useless in this mode")); + comp->flags &= ~CF_WAIT; + } + + if (comp->mode != pies_comp_exec + && comp->redir[RETR_OUT].type != redir_null) + { + COMPERR (grecs_error, + "%s", _("stdout translation invalid in this mode")); + comp->redir[RETR_OUT].type = redir_null; + } + + for (i = RETR_OUT; i <= RETR_ERR; i++) + { + if (comp->redir[i].type == redir_file + && comp->redir[i].v.file[0] != '/') + { + if (comp->dir) + { + char *p = mkfilename (comp->dir, comp->redir[i].v.file, NULL); + free (comp->redir[i].v.file); + comp->redir[i].v.file = p; + } + else + COMPERR (grecs_error, + _("%s: must be an absolute " + "file name or chdir must be specified"), + comp->redir[i].v.file); + } + } + + return header; +#undef COMPERR +} + +void +component_finish (struct component *comp, grecs_locus_t *locus) +{ + if (comp->prereq) + comp->prereq->cmp = list_str_cmp; + if (comp->depend) + comp->depend->cmp = list_str_cmp; + if (comp->privs.groups) + comp->privs.groups->cmp = list_str_cmp; + + if (component_verify (comp, locus)) + { + component_free (comp); + } + else + { + size_t n = grecs_list_size (comp->prereq); + if (n == 1) + { + const char *item = grecs_list_index (comp->prereq, 0); + if (strcmp (item, "all") == 0) + { + struct component *p; + + grecs_list_clear (comp->prereq); + for (p = comp->prev; p; p = p->prev) + grecs_list_push (comp->prereq, grecs_strdup (comp->tag)); + } + else if (strcmp (item, "none") == 0) + { + grecs_list_free (comp->prereq); + comp->prereq = NULL; + } + } + } +} + +struct component * +component_get (size_t n) +{ + if (n >= comp_count) + return NULL; + return comp_array[n]; +} + +void +components_dump_depmap (void) +{ + size_t i, j; + + printf ("%s:\n", _("Dependency map")); + printf (" "); + for (i = 0; i < comp_count; i++) + printf (" %2lu", (unsigned long)i); + printf ("\n"); + for (i = 0; i < comp_count; i++) + { + printf ("%2lu ", (unsigned long)i); + for (j = 0; j < comp_count; j++) + printf (" %c ", depmap_isset (depmap, i, j) ? 'X' : ' '); + printf ("\n"); + } + printf ("\n%s:\n", _("Legend")); + for (i = 0; i < comp_count; i++) + printf ("%2lu: %s\n", (unsigned long)i, comp_array[i]->tag); +} + +void +component_trace (size_t idx, enum pies_depmap_direction dir) +{ + pies_depmap_pos_t pos; + size_t n; + int delim = ':'; + + logmsg_printf (LOG_NOTICE, "%s", comp_array[idx]->tag); + for (n = depmap_first (depmap, dir, idx, &pos); + n != (size_t)-1; + n = depmap_next (depmap, pos)) + { + logmsg_printf (LOG_NOTICE, "%c %s", delim, comp_array[n]->tag); + delim = ','; + } + depmap_end (pos); + logmsg_printf (LOG_NOTICE, "\n"); +} + +void +components_trace (char **argv, enum pies_depmap_direction dir) +{ + if (*argv) + for (; *argv; ++argv) + { + ssize_t idx = component_lookup_index (*argv); + if (idx < 0) + logmsg (LOG_ERR, "%s: no such component", *argv); + else + component_trace (idx, dir); + } + else + { + size_t i; + + for (i = 0; i < comp_count; i++) + component_trace (i, dir); + } +} + +struct component * +component_depmap_first (enum pies_depmap_direction dir, size_t idx, + pies_depmap_pos_t *ppos) +{ + size_t n = depmap_first (depmap, dir, idx, ppos); + if (n == (size_t)-1) + return NULL; + return comp_array[n]; +} + +struct component * +component_depmap_next (pies_depmap_pos_t pos) +{ + size_t n = depmap_next (depmap, pos); + if (n == (size_t)-1) + return NULL; + return comp_array[n]; +} + + + + + diff --git a/src/ctl.c b/src/ctl.c index 11ec7b4..d3e6b64 100644 --- a/src/ctl.c +++ b/src/ctl.c @@ -1543,7 +1543,7 @@ pcond_eval (struct pcond_node *node, struct prog *p) return 0; case pcond_component: - return strcmp (p->tag, node->v.tag) == 0; + return strcmp (prog_tag (p), node->v.tag) == 0; case pcond_type: return p->type == node->v.type; @@ -1792,7 +1792,7 @@ selector (struct prog *prog, void *data) if (auth_prog (prog, env->io) & env->allowed_state) { struct json_value *status = json_new_object (); - json_object_set_string (status, "tag", prog->tag); + json_object_set_string (status, "tag", prog_tag (prog)); if (env->fun (status, prog) == 0) env->success_count++; json_array_append (env->result, status); diff --git a/src/depmap.c b/src/depmap.c index e4533e8..3259880 100644 --- a/src/depmap.c +++ b/src/depmap.c @@ -23,7 +23,7 @@ #define WORDSIZE(n) (((n) + BITS_PER_WORD - 1) / BITS_PER_WORD) #define SETBIT(x, i) ((x)[(i)/BITS_PER_WORD] |= (1<<((i) % BITS_PER_WORD))) -#define RESETBIT(x, i) ((x)[(i)/BITS_PER_WORD] &= ~(1<<((i) % BITS_PER_WORD))) +#define CLRBIT(x, i) ((x)[(i)/BITS_PER_WORD] &= ~(1<<((i) % BITS_PER_WORD))) #define BITISSET(x, i) (((x)[(i)/BITS_PER_WORD] & (1<<((i) % BITS_PER_WORD))) != 0) void @@ -118,6 +118,13 @@ depmap_set (pies_depmap_t dmap, size_t row, size_t col) SETBIT (rptr, col); } +void +depmap_clear (pies_depmap_t dmap, size_t row, size_t col) +{ + unsigned *rptr = depmap_rowptr (dmap, row); + CLRBIT (rptr, col); +} + int depmap_isset (pies_depmap_t dmap, size_t row, size_t col) { @@ -166,3 +173,22 @@ depmap_end (pies_depmap_pos_t pos) { grecs_free (pos); } + +void +depmap_clear_all (pies_depmap_t dmap, enum pies_depmap_direction dir, + size_t coord) +{ + size_t i; + + switch (dir) + { + case depmap_row: + for (i = 0; i < dmap->nrows; i++) + depmap_clear (dmap, coord, i); + break; + + case depmap_col: + for (i = 0; i < dmap->nrows; i++) + depmap_clear (dmap, i, coord); + } +} diff --git a/src/inetd.c b/src/inetd.c index 3eb4470..ee16078 100644 --- a/src/inetd.c +++ b/src/inetd.c @@ -281,7 +281,7 @@ inetd_conf_file (const char *file) if (ISCF_TCPMUX (comp->flags)) comp->tcpmux = mktag (address, "tcpmux"); comp->service = grecs_strdup (service); - comp->privs.user = grecs_strdup (user); /* FIXME: memory leak */ + comp->privs.user = grecs_strdup (user); if (group) { comp->privs.groups = grecs_list_create (); @@ -306,9 +306,6 @@ inetd_conf_file (const char *file) comp->argv = grecs_calloc (comp->argc + 1, sizeof (comp->argv[0])); comp->argv[0] = grecs_strdup (comp->program); } - - if (progman_lookup_component (comp->tag) == NULL) - register_prog (comp); } if (wsflags & WRDSF_REUSE) @@ -380,7 +377,7 @@ inetd_conf_dir (const char *name) } int -inetd_parse_conf (const char *file) +inetd_config_parse (const char *file) { struct stat st; diff --git a/src/limits.c b/src/limits.c index a2c8ad9..7387b9d 100644 --- a/src/limits.c +++ b/src/limits.c @@ -304,4 +304,13 @@ free_limits (limits_record_t rec) free (rec); } - +int +limits_cmp (limits_record_t a, limits_record_t b) +{ + if (!a) + return !!b; + else if (!b) + return 1; + return memcmp (a, b, sizeof (*a)); +} + diff --git a/src/pies.c b/src/pies.c index 4a9ac9e..d3a9096 100644 --- a/src/pies.c +++ b/src/pies.c @@ -33,12 +33,13 @@ int init_process; enum pies_command { COM_START, - COM_RESTART, + COM_RESTART_COMPONENT, COM_RELOAD, COM_STATUS, COM_STOP, - COM_DUMP_PREREQ, - COM_DUMP_DEPMAP + COM_DUMP_DEPMAP, + COM_TRACE_PREREQ, + COM_TRACE_DEPEND }; enum pies_command command; @@ -63,43 +64,42 @@ char *default_control_url[2] = { DEFAULT_INIT_CONTROL_URL }; -struct config_file +struct config_syntax { - enum config_syntax syntax; - char *name; + const char *name; + int (*parser) (char const *); }; -struct grecs_list *config_list; +static int pies_config_parse (char const *); -struct config_syntax_descr -{ - const char *name; - enum config_syntax type; +static struct config_syntax config_syntax_tab[] = { + [CONF_PIES] = { "pies" , pies_config_parse }, + [CONF_META1] = { "meta1", meta1_config_parse }, + [CONF_INETD] = { "inetd", inetd_config_parse }, + [CONF_INITTAB] = { "inittab", inittab_parse }, }; -static struct config_syntax_descr config_syntax_tab[] = { - { "pies" , CONF_PIES }, - { "meta1", CONF_META1 }, - { "inetd", CONF_INETD }, - { "inittab", CONF_INITTAB }, - { NULL } +struct config_file +{ + struct config_syntax *syntax; + char *name; }; -int -str_to_config_syntax (const char *str, enum config_syntax *psynt) +struct grecs_list *config_list; + +struct config_syntax * +str_to_config_syntax (const char *str) { - struct config_syntax_descr *p; - for (p = config_syntax_tab; p->name; p++) - if (strcmp (p->name, str) == 0) - { - *psynt = p->type; - return 0; - } - return 1; + int i; + + for (i = 0; i < ARRAY_SIZE (config_syntax_tab); i++) + if (strcmp (config_syntax_tab[i].name, str) == 0) + return &config_syntax_tab[i]; + return NULL; } void -add_config (enum config_syntax syntax, const char *name) +config_file_add (struct config_syntax *syntax, const char *name) { struct config_file *file = grecs_malloc (sizeof (file[0])); file->syntax = syntax; @@ -108,6 +108,12 @@ add_config (enum config_syntax syntax, const char *name) config_list = grecs_list_create (); grecs_list_append (config_list, file); } + +void +config_file_add_type (enum config_syntax_type syntax, const char *name) +{ + config_file_add (&config_syntax_tab[syntax], name); +} /* Logging */ static int @@ -152,26 +158,26 @@ struct grecs_keyword return_code_keywords[] = { N_("Specifies action to take when a component finishes with this " "return code."), grecs_type_string, GRECS_DFLT, - NULL, offsetof (struct component, act_temp.act), + NULL, offsetof (struct action, act), _cb_action, }, {"notify", N_("arg: emails"), N_("Notify this address when a component terminates."), grecs_type_string, GRECS_DFLT, - NULL, offsetof (struct component, act_temp.addr) + NULL, offsetof (struct action, addr) }, {"message", NULL, N_("Notification message text (with headers)."), grecs_type_string, GRECS_DFLT, - NULL, offsetof (struct component, act_temp.message), + NULL, offsetof (struct action, message), NULL}, {"exec", NULL, N_("Execute this command."), grecs_type_string, GRECS_DFLT, - NULL, offsetof (struct component, act_temp.command), + NULL, offsetof (struct action, command), NULL, }, {NULL} @@ -260,7 +266,7 @@ static struct tokendef sig_tokendef[] = { #undef S void -free_action (struct action *act) +action_free (struct action *act) { if (!act) return; @@ -273,11 +279,17 @@ free_action (struct action *act) free (act); } +static void +free_entry_action (void *act) +{ + action_free (act); +} + static struct action * create_action (struct component *comp, - grecs_locus_t *locus, - grecs_value_t *val, int argc, - const char *(*getarg) (grecs_value_t *, int, grecs_locus_t *)) + grecs_locus_t *locus, + grecs_value_t *val, int argc, + const char *(*getarg) (grecs_value_t *, int, grecs_locus_t *)) { int i; unsigned *retv; @@ -348,11 +360,12 @@ create_action (struct component *comp, act->nstat = retc; act->status = retv; } - if (comp->act_tail) - comp->act_tail->next = act; - else - comp->act_head = act; - comp->act_tail = act; + if (!comp->act_list) + { + comp->act_list = grecs_list_create (); + comp->act_list->free_entry = free_entry_action; + } + grecs_list_append (comp->act_list, act); return act; } @@ -423,18 +436,12 @@ return_code_section_parser (enum grecs_callback_command cmd, count = grecs_list_size (value->v.list); act = create_action (comp, locus, value, count, _get_list_arg); } - *(struct component **) cb_data = comp; if (!act) return 1; - memset (&comp->act_temp, 0, sizeof (comp->act_temp)); + *(struct action **) cb_data = act; break; case grecs_callback_section_end: - act = comp->act_tail; - act->act = comp->act_temp.act; - act->addr = comp->act_temp.addr; - act->message = comp->act_temp.message; - act->command = comp->act_temp.command; break; case grecs_callback_set_value: @@ -919,12 +926,12 @@ _cb_runlevels (enum grecs_callback_command cmd, for (p = value->v.string; *p; p++) { if (!is_valid_runlevel (*p)) - { - grecs_error (locus, 0, _("not a valid runlevel: %c"), *p); - return 1; - } + { + grecs_error (locus, 0, _("not a valid runlevel: %c"), *p); + return 1; + } } - *sptr = grecs_strdup(value->v.string); + *sptr = grecs_strdup (value->v.string); for (p = *sptr; *p; p++) *p = toupper (*p); return 0; @@ -1172,265 +1179,6 @@ find_component_keyword (const char *ident) return NULL; } -static char * -make_full_name (const char *dir, const char *file) -{ - char *p; - size_t len = strlen (dir); - - while (len > 0 && dir[len - 1] == '/') - len--; - p = grecs_malloc (len + 1 + strlen (file) + 1); - memcpy (p, dir, len); - p[len++] = '/'; - strcpy (p + len, file); - return p; -} - -static int -component_verify (struct component *comp, grecs_locus_t *locus) -{ - int header = 0; - int i; -#define COMPERR(func, fmt, arg) \ - do \ - { \ - if (!header) \ - { \ - grecs_warning (locus, 0, _("in component %s:"), comp->tag); \ - header = 1; \ - } \ - func (locus, 0, fmt, arg); \ - } \ - while (0) - - if (comp->flags & CF_INTERNAL) - { - comp->mode = pies_comp_inetd; - if (!comp->service) - /* TRANSLATORS: do not translate quoted words, they are keywords. */ - COMPERR (grecs_error, - "%s", _("`internal' used without `service'")); - else - { - comp->builtin = inetd_builtin_lookup (comp->service, - comp->socket_type); - if (!comp->builtin) - COMPERR (grecs_error, - "%s", _("unknown internal service")); - if (comp->argv) - /* TRANSLATORS: do not translate quoted words, they are - keywords. */ - COMPERR (grecs_error, - "%s", _("`internal' used with `command'")); - } - } - else if (!comp->argv) - COMPERR (grecs_error, - "%s", _("missing command line")); - - if (ISCF_TCPMUX (comp->flags)) - { - comp->mode = pies_comp_inetd; - if ((comp->flags & (CF_TCPMUX | CF_TCPMUXPLUS)) - == (CF_TCPMUX | CF_TCPMUXPLUS)) - COMPERR (grecs_error, - "%s", _("both `tcpmux' and `tcpmuxplus' used")); - else if (!comp->service) - /* TRANSLATORS: do not translate quoted words, they are keywords. */ - COMPERR (grecs_error, - "%s", _("`internal' used without `service'")); - } - - if (comp->pass_fd_socket && comp->mode != pies_comp_pass_fd) - COMPERR (grecs_error, - "%s", _("pass-fd-socket ignored: wrong mode")); - switch (comp->mode) - { - case pies_comp_exec: - if (comp->socket_url) - COMPERR (grecs_error, - "%s", _("socket ignored: wrong mode")); - break; - - case pies_comp_pass_fd: - if (!comp->pass_fd_socket) - COMPERR (grecs_error, - "%s", _("must supply pass-fd-socket in this mode")); - else if (comp->pass_fd_socket[0] != '/') - { - if (comp->dir) - { - char *p = make_full_name (comp->dir, comp->pass_fd_socket); - /*free (comp->pass_fd_socket);*/ - comp->pass_fd_socket = p; - } - else - COMPERR (grecs_error, - "%s", _("pass-fd-socket must be an absolute " - "file name or chdir must be specified")); - } - /* Fall through */ - - case pies_comp_accept: - if (!comp->socket_url) - { - COMPERR (grecs_error, - "%s", _("socket must be specified in this mode")); - return 1; - } - break; - - case pies_comp_inetd: - if (ISCF_TCPMUX (comp->flags)) - { - pies_url_destroy (&comp->socket_url); - if (!comp->tcpmux) - { - COMPERR (grecs_warning, - "%s", - _("TCPMUX master not specified, assuming \"tcpmux\"")); - comp->tcpmux = grecs_strdup ("tcpmux"); - } - } - else if (comp->tcpmux) - { - comp->flags |= CF_TCPMUX; - pies_url_destroy (&comp->socket_url); - } - else if (!comp->socket_url) - { - COMPERR (grecs_error, - "%s", _("socket must be specified in this mode")); - return 1; - } - default: - /* FIXME: more checks perhaps */ - break; - } - - if (comp->mode == pies_comp_inetd) - { - if ((comp->flags & CF_WAIT) && comp->socket_type == SOCK_STREAM) - { - if (comp->max_instances) - COMPERR (grecs_error, "%s", _("max-instances ignored")); - else - comp->max_instances = 1; - } - } - else if (comp->flags & CF_WAIT) - { - /* TRANSLATORS: `wait' is a keywords, do not translate. */ - COMPERR (grecs_error, "%s", _("wait is useless in this mode")); - comp->flags &= ~CF_WAIT; - } - - if (comp->mode != pies_comp_exec - && comp->redir[RETR_OUT].type != redir_null) - { - COMPERR (grecs_error, - "%s", _("stdout translation invalid in this mode")); - comp->redir[RETR_OUT].type = redir_null; - } - - for (i = RETR_OUT; i <= RETR_ERR; i++) - { - if (comp->redir[i].type == redir_file - && comp->redir[i].v.file[0] != '/') - { - if (comp->dir) - { - char *p = make_full_name (comp->dir, comp->redir[i].v.file); - free (comp->redir[i].v.file); - comp->redir[i].v.file = p; - } - else - COMPERR (grecs_error, - _("%s: must be an absolute " - "file name or chdir must be specified"), - comp->redir[i].v.file); - } - } - - return header; -#undef COMPERR -} - -struct component * -component_create (const char *name) -{ - struct component *comp = progman_lookup_component (name); - if (!comp) - { - comp = grecs_zalloc (sizeof (*comp)); - comp->facility = log_facility; - comp->redir[RETR_OUT].type = comp->redir[RETR_ERR].type = redir_null; - comp->tag = grecs_strdup (name); - comp->socket_type = SOCK_STREAM; - } - return comp; -} - -void -component_free (struct component *comp) -{ - size_t i; - - free (comp->tag); - free (comp->program); - if (comp->argv) - { - for (i = 0; i < comp->argc; i++) - free (comp->argv[i]); - free (comp->argv); - } - if (comp->env) - { - for (i = 0; comp->env[i]; i++) - free (comp->env[i]); - free (comp->env); - } - free (comp->dir); - grecs_list_free (comp->prereq); - grecs_list_free (comp->depend); - free (comp->rmfile); - free_limits (comp->limits); - free (comp->runlevels); - free (comp->service); - pies_url_destroy (&comp->socket_url); - free (comp->pass_fd_socket); - free (comp->tcpmux); - free (comp->access_denied_message); - free (comp->max_instances_message); - free (comp->max_ip_connections_message); - free_redirector (&comp->redir[0]); - free_redirector (&comp->redir[1]); - if (comp->act_head) - { - struct action *act; - - for (act = comp->act_head; act; act = act->next) - free_action (act); - } - - free (comp); -} - -void -component_finish (struct component *comp, grecs_locus_t *locus) -{ - if (component_verify (comp, locus) == 0) - { - /* FIXME: The prog list is traversed twice for each component - statement, this is suboptimal. */ - if (progman_lookup_component (comp->tag) == NULL) - register_prog (comp); - } - else - component_free (comp); -} - static int component_section_parser (enum grecs_callback_command cmd, grecs_locus_t *locus, @@ -1543,7 +1291,7 @@ _cb_include_inetd (enum grecs_callback_command cmd, { if (assert_grecs_value_type (locus, value, GRECS_TYPE_STRING)) return 1; - return inetd_parse_conf (value->v.string); + return inetd_config_parse (value->v.string); } struct grecs_keyword pies_keywords[] = { @@ -1722,24 +1470,14 @@ config_init () #endif } -static void -config_error () -{ - if (!init_process) - exit (EX_CONFIG); -} - -void -config_parse (char const *name) +int +pies_config_parse (char const *name) { struct grecs_node *node; struct grecs_node *tree = grecs_parse (name); if (!tree) - { - config_error (); - return; - } + return 1; for (node = tree; node; node = node->next) { @@ -1750,9 +1488,11 @@ config_parse (char const *name) } if (grecs_tree_process (tree, pies_keywords)) - config_error (); + return 1; grecs_tree_free (tree); + + return 0; } void @@ -1767,7 +1507,42 @@ config_help () pies_config_identity_mechanisms_help (); } -static enum config_syntax current_syntax = CONF_PIES; +int +pies_read_config (void) +{ + struct grecs_list_entry *ep; + int err = 0; + + component_config_begin (); + + for (ep = config_list->head; ep; ep = ep->next) + { + struct config_file *file = ep->data; + if (file->syntax->parser (file->name)) + ++err; + } + + if (err) + component_config_rollback (); + + return err; +} + +int +pies_reload (void) +{ + int rc = pies_read_config (); + if (rc == 0) + { + component_config_commit (); + progman_create_sockets (); + progman_start (); + } + + return rc; +} + +static struct config_syntax *current_syntax = &config_syntax_tab[CONF_PIES]; #include "cmdline.h" @@ -1796,11 +1571,16 @@ sig_handler (int sig) case SIGINT: case SIGTERM: case SIGQUIT: - action = ACTION_STOP; logmsg (LOG_NOTICE, "received signal %d", sig); + action = ACTION_STOP; break; case SIGHUP: + logmsg (LOG_NOTICE, "received signal %d", sig); + action = ACTION_RELOAD; + break; + + case SIGUSR1: logmsg (LOG_NOTICE, "received signal %d", sig); action = ACTION_RESTART; break; @@ -1836,6 +1616,7 @@ static int default_sigv[] = { SIGQUIT, SIGINT, SIGHUP, + SIGUSR1, SIGALRM, SIGPIPE }; @@ -1934,7 +1715,7 @@ pies_check_status (pid_t *ppid) #define pies_control_url() control.url->string -void +int request_restart_components (size_t cc, char **cv) { char **argv; @@ -1949,7 +1730,7 @@ request_restart_components (size_t cc, char **cv) argv[3 + i] = NULL; execvp (argv[0], argv); logmsg (LOG_ERR, "can't run piesctl: %s", strerror (errno)); - exit (EX_OSFILE); + return EX_OSFILE; } void @@ -1969,7 +1750,7 @@ list_components (void) int -pies_reload () +request_reload () { pid_t pid = pidfile_read (1); @@ -1984,7 +1765,7 @@ pies_reload () } int -pies_status () +request_status () { pid_t pid; @@ -2014,7 +1795,7 @@ pies_status () } int -pies_stop () +request_stop () { pid_t pid = pidfile_read (1); @@ -2119,7 +1900,7 @@ set_conf_file_names (const char *base) if (!config_list) { char *name = mkfilename (SYSCONFDIR, base, ".conf"); - add_config (current_syntax, name); + config_file_add (current_syntax, name); free (name); } } @@ -2196,8 +1977,9 @@ main (int argc, char **argv) { char *inittab = strtok (emu, ":"); char *piesinit = strtok (NULL, ":"); - add_config (CONF_INITTAB, inittab); - add_config (CONF_PIES, piesinit ? piesinit : "/etc/pies.init"); + config_file_add_type (CONF_INITTAB, inittab); + config_file_add_type (CONF_PIES, + piesinit ? piesinit : "/etc/pies.init"); init_fifo = getenv ("INIT_FIFO"); if (!init_fifo) @@ -2205,12 +1987,12 @@ main (int argc, char **argv) } else { - add_config (CONF_INITTAB, "/etc/inittab"); - add_config (CONF_PIES, "/etc/pies.init"); + config_file_add_type (CONF_INITTAB, "/etc/inittab"); + config_file_add_type (CONF_PIES, "/etc/pies.init"); } #else - add_config (CONF_INITTAB, "/etc/inittab"); - add_config (CONF_PIES, "/etc/pies.init"); + config_file_add_type (CONF_INITTAB, "/etc/inittab"); + config_file_add_type (CONF_PIES, "/etc/pies.init"); #endif for (index = 1; index < argc; index++) { @@ -2256,47 +2038,24 @@ main (int argc, char **argv) } exit (0); } - else - for (ep = config_list->head; ep; ep = ep->next) - { - struct config_file *file = ep->data; + else if (pies_read_config ()) + exit (EX_CONFIG); - switch (file->syntax) - { - case CONF_PIES: - config_parse (file->name); - break; - - case CONF_INETD: - if (inetd_parse_conf (file->name)) - config_error (); - break; - - case CONF_META1: - if (meta1_config_parse (file->name)) - config_error (); - break; - - case CONF_INITTAB: - if (inittab_parse (file->name)) - config_error (); - break; - } - } + component_config_commit (); set_state_file_names (instance); set_mailer_argcv (); if (lint_mode) - { - progman_build_depmap (); - exit (0); - } + exit (0); /* Re-setup logging: it might have been reset in the config file */ diag_setup (log_to_stderr_only ? DIAG_TO_STDERR : 0); - if (argc != index && command != COM_RESTART) + if (argc != index + && !(command == COM_RESTART_COMPONENT + || command == COM_TRACE_DEPEND + || command == COM_TRACE_PREREQ)) { logmsg (LOG_ERR, "extra command line arguments"); exit (EX_CONFIG); @@ -2314,32 +2073,35 @@ main (int argc, char **argv) } } - progman_build_depmap (); switch (command) { - case COM_RESTART: + case COM_RESTART_COMPONENT: pies_priv_setup (&pies_privs); if (pies_umask) umask (pies_umask); - request_restart_components (argc - index, argv + index); + exit (request_restart_components (argc - index, argv + index)); case COM_RELOAD: - exit (pies_reload ()); + exit (request_reload ()); case COM_STATUS: - exit (pies_status ()); + exit (request_status ()); case COM_STOP: - exit (pies_stop ()); - - case COM_DUMP_PREREQ: - progman_dump_prereq (); - exit (0); + exit (request_stop ()); case COM_DUMP_DEPMAP: - progman_dump_depmap (); + components_dump_depmap (); exit (0); + case COM_TRACE_DEPEND: + components_trace (argv + index, depmap_row); + exit (0); + + case COM_TRACE_PREREQ: + components_trace (argv + index, depmap_col); + exit (0); + default: pies_priv_setup (&pies_privs); if (pies_umask) @@ -2398,7 +2160,7 @@ main (int argc, char **argv) if (argv[0][0] != '/') logmsg (LOG_NOTICE, _("not started as an absolute pathname; " - "SIGHUP will not work")); + "restart will not work")); signal_setup (sig_handler); @@ -2424,6 +2186,11 @@ main (int argc, char **argv) } break; + case ACTION_RELOAD: + pies_reload (); + action = ACTION_CONT; + break; + case ACTION_STOP: if (init_process) { diff --git a/src/pies.h b/src/pies.h index e0d24d2..ad8e8ee 100644 --- a/src/pies.h +++ b/src/pies.h @@ -98,7 +98,6 @@ enum return_action struct action { - struct action *next; size_t nstat; unsigned *status; enum return_action act; /* Action to take when the component terminates */ @@ -202,8 +201,16 @@ enum pies_comp_mode #define ISCF_TCPMUX(f) ((f) & (CF_TCPMUX | CF_TCPMUXPLUS)) +struct prog; + struct component { + struct component *prev, *next; /* Components form doubly-linked list. */ + int listidx; /* Index of the list. */ + size_t arridx; /* Index of this component. */ + size_t ref_count; /* Reference count. */ + struct prog *prog; /* Prog associated with this component. */ + enum pies_comp_mode mode; char *tag; /* Entry tag (for diagnostics purposes) */ char *program; /* Program name */ @@ -217,7 +224,7 @@ struct component size_t max_instances; /* Maximum number of simultaneously running instances */ char *rmfile; /* Try to remove this file before starting */ - struct pies_privs privs; /* UID/GIDS+groups to run under */ + struct pies_privs privs; /* UID/GIDS+groups to run as */ mode_t umask; /* Umask to install before starting */ limits_record_t limits; /* System limits */ @@ -249,8 +256,7 @@ struct component int facility; /* Syslog facility. */ struct redirector redir[2]; /* Repeaters for stdout and stderr */ /* Actions to execute on various exit codes: */ - struct action *act_head, *act_tail; - struct action act_temp; /* Auxiliary object used during configuration */ + struct grecs_list *act_list; /* ACLs for control interface */ pies_acl_t list_acl; /* List access control list */ pies_acl_t adm_acl; /* Administrative ACL (stop, start, etc.) */ @@ -262,6 +268,7 @@ enum pies_action { ACTION_CONT, ACTION_STOP, ACTION_RESTART, + ACTION_RELOAD, ACTION_CTRLALTDEL, ACTION_KBREQUEST }; @@ -289,7 +296,7 @@ extern size_t pies_master_argc; extern char **pies_master_argv; extern char *default_control_url[2]; -enum config_syntax +enum config_syntax_type { CONF_PIES, CONF_META1, @@ -297,12 +304,16 @@ enum config_syntax CONF_INITTAB }; -int str_to_config_syntax (const char *str, enum config_syntax *psynt); -void add_config (enum config_syntax syntax, const char *name); +struct config_syntax; + +struct config_syntax *str_to_config_syntax (const char *str); +void config_file_add (struct config_syntax *syntax, const char *name); +void config_file_add_type (enum config_syntax_type syntax, const char *name); void free_redirector (struct redirector *rp); void pies_schedule_action (int act); +void free_action (struct action *act); void register_prog (struct component *comp); int progman_running_p (void); @@ -313,11 +324,10 @@ void progman_stop (void); void progman_cleanup (int expect_term); void progman_filter (int (*filter) (struct component *, void *data), void *data); +int progman_wait_until (int (*cond) (void *), void *data); void progman_stop_tag (const char *name); -void progman_dump_prereq (void); -void progman_dump_depmap (void); int progman_accept (int socket, void *data); -int progman_build_depmap (void); + void progman_create_sockets (void); struct component *progman_lookup_component (const char *tag); struct component *progman_lookup_tcpmux (const char *service, @@ -351,6 +361,11 @@ pies_depmap_t depmap_alloc (size_t count); pies_depmap_t depmap_copy (pies_depmap_t dpm); void depmap_set (pies_depmap_t dmap, size_t row, size_t col); int depmap_isset (pies_depmap_t dmap, size_t row, size_t col); +void depmap_clear (pies_depmap_t dmap, size_t row, size_t col); + +void depmap_clear_all (pies_depmap_t dmap, enum pies_depmap_direction dir, + size_t coord); + void depmap_tc (pies_depmap_t dmap); size_t depmap_first (pies_depmap_t dmap, enum pies_depmap_direction dir, size_t coord, pies_depmap_pos_t *ppos); @@ -365,10 +380,25 @@ int socket_type_to_str (int socket_type, const char **pres); struct component *component_create (const char *name); void component_free (struct component *comp); +void component_ref_incr (struct component *comp); +void component_ref_decr (struct component *comp); + +void component_config_begin (void); +void component_config_rollback (void); +void component_config_commit (void); + +int component_is_active (struct component *comp); void component_finish (struct component *comp, grecs_locus_t *locus); struct grecs_keyword *find_component_keyword (const char *ident); +void components_dump_depmap (void); +void components_trace (char **argv, enum pies_depmap_direction dir); + +struct component *component_depmap_first (enum pies_depmap_direction dir, + size_t idx, pies_depmap_pos_t *ppos); +struct component *component_depmap_next (pies_depmap_pos_t pos); + void pies_pause (void); @@ -401,6 +431,7 @@ void enable_socket (int fd); int parse_limits (limits_record_t *plrec, char *str, char **endp); int set_limits (const char *name, limits_record_t lrec); void free_limits (limits_record_t rec); +int limits_cmp (limits_record_t a, limits_record_t b); void meta1_parser_set_debug (void); @@ -451,9 +482,13 @@ int switch_to_privs (uid_t uid, gid_t gid, struct grecs_list *retain_groups); void pies_priv_setup (struct pies_privs *); void pies_epriv_setup (struct pies_privs *); + +int pies_privs_cmp (struct pies_privs const *a, struct pies_privs const *b); +void pies_privs_free (struct pies_privs *p); + /* inetd.c */ -int inetd_parse_conf (const char *file); +int inetd_config_parse (const char *file); /* inetd-bi.c */ struct inetd_builtin diff --git a/src/prog.h b/src/prog.h index 6590d4e..a29de04 100644 --- a/src/prog.h +++ b/src/prog.h @@ -46,8 +46,6 @@ struct prog struct prog *next, *prev; enum prog_type type; pid_t pid; /* PID */ - char *tag; /* Entry tag (for diagnostics purposes) */ - char **prereq; int facility; union { @@ -60,7 +58,6 @@ struct prog time_t timestamp; /* Time of last startup */ size_t failcount; /* Number of failed starts since timestamp */ enum prog_status status; /* Current component status */ - char *runlevels; /* If status == status_listener: */ size_t num_instances; /* Number of running instances */ /* If comp->type == pies_comp_inetd && status == status_enabled */ @@ -72,11 +69,13 @@ struct prog struct { + char *tag; struct prog *master; } r; struct { + char *tag; char *command; } c; } v; @@ -88,3 +87,5 @@ struct prog *progman_locate (const char *name); void progman_foreach (int (*filter) (struct prog *, void *data), void *data); void prog_stop (struct prog *prog, int sig); void progman_stop_component (struct prog *prog); + +char const *prog_tag (struct prog const *prog); diff --git a/src/progman.c b/src/progman.c index 0079149..4f63d9a 100644 --- a/src/progman.c +++ b/src/progman.c @@ -17,9 +17,7 @@ #include "pies.h" #include "prog.h" -static size_t numcomp; static struct prog *proghead, *progtail; -static pies_depmap_t depmap; static int recompute_alarm; static struct grecs_symtab *conn_tab; @@ -29,7 +27,7 @@ progman_locate (const char *name) struct prog *prog; for (prog = proghead; prog; prog = prog->next) - if (strcmp (prog->tag, name) == 0) + if (strcmp (prog_tag (prog), name) == 0) break; return prog; } @@ -73,7 +71,7 @@ prog_lookup_by_tag (const char *tag) { struct prog *prog; for (prog = proghead; prog; prog = prog->next) - if (strcmp (prog->tag, tag) == 0) + if (strcmp (prog_tag (prog), tag) == 0) break; return prog; } @@ -95,7 +93,7 @@ progman_lookup_component (const char *tag) { struct prog *prog; for (prog = proghead; prog; prog = prog->next) - if (IS_COMPONENT (prog) && strcmp (prog->tag, tag) == 0) + if (IS_COMPONENT (prog) && strcmp (prog_tag (prog), tag) == 0) return prog->v.p.comp; return NULL; } @@ -129,6 +127,23 @@ prog_lookup_by_idx (unsigned idx) void prog_stop (struct prog *prog, int sig); static int prog_start_prerequisites (struct prog *prog); +char const * +prog_tag (struct prog const *prog) +{ + switch (prog->type) + { + case TYPE_COMPONENT: + return prog->v.p.comp->tag; + + case TYPE_REDIRECTOR: + return prog->v.r.tag; + + case TYPE_COMMAND: + return prog->v.c.tag; + } + abort (); + } + void link_prog (struct prog *pp, int prepend) { @@ -158,6 +173,7 @@ void unlink_prog (struct prog *pp) { struct prog *x; + if ((x = pp->prev)) x->next = pp->next; else @@ -172,28 +188,35 @@ void destroy_prog (struct prog **pp) { struct prog *p = *pp; + + unlink_prog (p); switch (p->type) { case TYPE_COMPONENT: + component_ref_decr (p->v.p.comp); + if (p->v.p.status == status_listener) + deregister_socket (p->v.p.socket); break; - + case TYPE_REDIRECTOR: { struct prog *master = p->v.r.master; + component_ref_decr (master->v.p.comp); if (p == master->v.p.redir[0]) master->v.p.redir[0] = NULL; else if (p == master->v.p.redir[1]) master->v.p.redir[1] = NULL; /* else logmsg (LOG_NOTICE, _("orphan redirector: %s"), p->tag);*/ + free (p->v.r.tag); } break; - + case TYPE_COMMAND: + free (p->v.c.tag); free (p->v.c.command); } - unlink_prog (*pp); - free (*pp); + free (p); *pp = NULL; } @@ -203,10 +226,11 @@ redir_tag (struct prog *master, int type) static char *redirstr[2] = { "stdout", "stderr" }; char *str = NULL; size_t len = 0; + char const *tag = prog_tag (master); if (type < ARRAY_SIZE(redirstr)) - grecs_asprintf (&str, &len, "%s/%s", master->tag, redirstr[type]); + grecs_asprintf (&str, &len, "%s/%s", tag, redirstr[type]); else - grecs_asprintf (&str, &len, "%s/%d", master->tag, type); + grecs_asprintf (&str, &len, "%s/%d", tag, type); return str; } @@ -214,21 +238,13 @@ static struct prog * register_redir (int type, struct prog *master) { char *tag = redir_tag (master, type); - char *pstr; - struct prog *pp = grecs_zalloc (sizeof (*pp) + strlen (tag) + 1 + - 2 * sizeof (char**)); + struct prog *pp = grecs_zalloc (sizeof (*pp)); pp->type = TYPE_REDIRECTOR; - pstr = (char *) (pp + 1); - pp->tag = pstr; - strcpy (pp->tag, tag); - pstr += strlen (pp->tag) + 1; - free (tag); + pp->v.r.tag = tag; pp->v.r.master = master; - pp->prereq = (char**)pstr; - pp->prereq[0] = master->tag; - pp->prereq[1] = NULL; link_prog (pp, 1); + component_ref_incr (master->v.p.comp); return pp; } @@ -248,17 +264,15 @@ update_redir (int type, struct prog *master, pid_t pid) } static struct prog * -register_prog0 (struct component *comp, unsigned index) +register_prog0 (struct component *comp) { struct prog *newp; newp = grecs_zalloc (sizeof (*newp)); newp->type = TYPE_COMPONENT; - newp->tag = comp->tag; newp->pid = 0; newp->facility = comp->facility; newp->v.p.comp = comp; - newp->v.p.idx = index; newp->v.p.socket = -1; if (comp->flags & CF_DISABLED) newp->v.p.status = status_disabled; @@ -269,13 +283,14 @@ register_prog0 (struct component *comp, unsigned index) comp->redir[RETR_OUT].type = redir_null; link_prog (newp, 0); + component_ref_incr (comp); return newp; } void register_prog (struct component *comp) { - register_prog0