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. --- src/pies.c | 535 +++++++++++++++++-------------------------------------------- 1 file changed, 151 insertions(+), 384 deletions(-) (limited to 'src/pies.c') 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) { -- cgit v1.2.1