From 6dd0ec08db301984b8f8f9082f28006d5915c183 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Fri, 24 May 2019 12:45:25 +0300 Subject: Initial implementation of "startup" components. These are components that are run at program startup. Starting other components is delayed until all startup components terminate. This is similar to SysV "bootwait" components. Upon termination, startup components are removed from the configuration. They are not renewed upon configuratuion reload. * src/comp.c (comp_array_remove): Remove from the depmap as well. (component_ref_decr): Use comp_array_remove for active components and plain component_free for inactive ones. (component_build_depmap): Use comp_array_remove. (component_config_commit): Special handling for pies_comp_startup components. * src/pies.c (modetab): New component modes: "startup" and "shutdown". (main): Run program_init_startup. * src/pies.h (pies_comp_mode): New modes: pies_comp_startup and pies_comp_shutdown. (program_init_startup): New proto. * src/progman.c (progman_waiting_p): Return 1 if a startup component is still running. (program_init_startup): New function. (progman_cleanup): Handle pies_comp_startup termination. * src/socket.c (switch_eids): Avoid unnecessary calls to setegid and seteuid. * tests/atlocal.in (auxdir): New variable. * tests/mailer: Move to tests/aux/ * tests/respawn: Move to tests/aux/ * tests/retcode: Move to tests/aux/ * tests/aux/startup: New auxiliary program. * tests/redirect.at: Start components from $auxdir. * tests/respawn.at: Likewise. * tests/ret-exec.at: Likewise. * tests/ret-notify.at: Likewise. * tests/startup.at: New file. * tests/testsuite.at: Include startup.at * tests/Makefile.am: Add new tests. --- src/comp.c | 87 ++++++++++------ src/pies.c | 115 +++++++++++---------- src/pies.h | 38 ++++--- src/progman.c | 291 ++++++++++++++++++++++++++++++---------------------- src/socket.c | 54 +++++----- tests/Makefile.am | 9 +- tests/atlocal.in | 2 +- tests/aux/mailer | 7 ++ tests/aux/respawn | 63 ++++++++++++ tests/aux/retcode | 9 ++ tests/aux/startup | 7 ++ tests/mailer | 7 -- tests/redirect.at | 2 +- tests/respawn | 63 ------------ tests/respawn.at | 2 +- tests/ret-exec.at | 4 +- tests/ret-notify.at | 6 +- tests/retcode | 9 -- tests/startup.at | 84 +++++++++++++++ tests/testsuite.at | 1 + 20 files changed, 521 insertions(+), 339 deletions(-) create mode 100755 tests/aux/mailer create mode 100755 tests/aux/respawn create mode 100755 tests/aux/retcode create mode 100755 tests/aux/startup delete mode 100755 tests/mailer delete mode 100755 tests/respawn delete mode 100755 tests/retcode create mode 100644 tests/startup.at diff --git a/src/comp.c b/src/comp.c index c3e998a..2346306 100644 --- a/src/comp.c +++ b/src/comp.c @@ -24,6 +24,11 @@ struct complist struct component *tail; }; +/* 0 on the first load, and 1 on all subsequent reloads. Tells the + component_config_commit whether we're starting from scratch or just + updating an already loaded configuration */ +static int loaded; + static struct complist comp_list[2]; static int cur; @@ -32,13 +37,13 @@ static size_t comp_count; static pies_depmap_t depmap; -static int +static inline int next_index (void) { return (cur + 1) % ARRAY_SIZE (comp_list); } -static int +static inline int prev_index (void) { return (cur + ARRAY_SIZE (comp_list) - 1) % ARRAY_SIZE (comp_list); @@ -84,6 +89,22 @@ component_append (struct component *comp) component_link (comp, comp_list[comp->listidx].tail); } +void +comp_array_remove (size_t i) +{ + struct component *comp = comp_array[i]; + + depmap_remove (depmap, i); + while (i < comp_count -1) + { + comp_array[i] = comp_array[i+1]; + comp_array[i]->arridx = i; + i++; + } + component_free (comp); + comp_count--; +} + void component_unlink (struct component *comp) { @@ -201,7 +222,12 @@ component_ref_decr (struct component *comp) { assert (comp->ref_count > 0); if (--comp->ref_count == 0) - component_free (comp); + { + if (component_is_active (comp)) + comp_array_remove (comp->arridx); + else + component_free (comp); + } } static int @@ -424,17 +450,6 @@ report_cyclic_dependency (pies_depmap_t dp, size_t idx) logmsg_printf (LOG_NOTICE, "%s\n", comp_array[idx]->tag); } -void -comp_array_remove (size_t i) -{ - struct component *comp = comp_array[i]; - if (i < comp_count - 1) - memmove (&comp_array[i], &comp_array[i+1], - (comp_count - i - 1) * sizeof comp_array[0]); - component_free (comp); - comp_count--; -} - void component_build_depmap (void) { @@ -460,7 +475,6 @@ component_build_depmap (void) "which is not declared"), comp->tag, tag); comp_array_remove (i); - depmap_remove (depmap, i); continue; } depmap_set (depmap, i, tgt); @@ -497,10 +511,7 @@ component_build_depmap (void) for (i = 0; i < comp_count;) if (comp_array[i]->flags & CF_REMOVE) - { - comp_array_remove (i); - depmap_remove (depmap, i); - } + comp_array_remove (i); else i++; @@ -528,22 +539,36 @@ component_config_commit (void) 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++) + /* Rearrange components, registering entries for the new ones */ + for (comp = list->head, i = 0; comp; ) { - match = complist_find_match (prev, comp); - if (match) + struct component *next = comp->next; + if (loaded && comp->mode == pies_comp_startup) { - component_merge (match, comp); - component_unlink (match); - match->listidx = cur; - component_link (match, comp->prev); + /* Ignore startup components */ + component_unlink (comp); component_free (comp); - comp = match; } - comp_array[i] = comp; - comp->arridx = i; + else + { + match = complist_find_match (prev, comp); + if (match) + { + component_merge (match, comp); + component_unlink (match); + match->listidx = cur; + component_link (match, comp->prev); + component_free (comp); + comp = match; + } + comp_array[i] = comp; + comp->arridx = i; + i++; + } + comp = next; } + /* Adjust comp_count */ + comp_count = i; /* Mark orphaned progs for termination */ list = &comp_list[prev]; @@ -560,6 +585,8 @@ component_config_commit (void) for (comp = comp_list[cur].head; comp; comp = comp->next) if (!comp->prog) register_prog (comp); + + loaded = 1; } static int diff --git a/src/pies.c b/src/pies.c index 89c0b7e..98488a6 100644 --- a/src/pies.c +++ b/src/pies.c @@ -132,7 +132,7 @@ int config_file_remove (const char *name) { struct grecs_list_entry *ep; - + for (ep = config_list->head; ep; ep = ep->next) { struct config_file *file = ep->data; @@ -156,7 +156,7 @@ void config_file_list_serialize (struct json_value *ar) { struct grecs_list_entry *ep; - + for (ep = config_list->head; ep; ep = ep->next) { struct config_file *file = ep->data; @@ -327,7 +327,7 @@ action_free (struct action *act) free (act->addr); free (act->message); free (act->command); - + free (act); } @@ -359,7 +359,7 @@ create_action (struct component *comp, unsigned n; const char *arg = getarg (val, i, locus); size_t len = strlen (arg); - + if (isdigit (arg[0])) { char *p; @@ -394,12 +394,12 @@ create_action (struct component *comp, grecs_error (locus, 0, _("%s: not a return code"), arg); continue; } - + /* Alles in ordnung */ retv[retc++] = n; } } - + if (retc == 0 && !allflag) { free (retv); @@ -472,18 +472,18 @@ return_code_section_parser (enum grecs_callback_command cmd, grecs_error (locus, 0, _("missing tag")); return 1; } - + switch (value->type) { case GRECS_TYPE_STRING: act = create_action (comp, locus, value, 1, _get_string_arg); break; - + case GRECS_TYPE_ARRAY: act = create_action (comp, locus, value, value->v.arg.c, _get_array_arg); break; - + case GRECS_TYPE_LIST: count = grecs_list_size (value->v.list); act = create_action (comp, locus, value, count, _get_list_arg); @@ -492,7 +492,7 @@ return_code_section_parser (enum grecs_callback_command cmd, return 1; *(struct action **) cb_data = act; break; - + case grecs_callback_section_end: break; @@ -542,7 +542,7 @@ _cb_command (enum grecs_callback_command cmd, wordsplit_get_words (&ws, &comp->argc, &comp->argv); wordsplit_free (&ws); break; - + case GRECS_TYPE_ARRAY: comp->argv = config_array_to_argv (value, locus, &comp->argc); break; @@ -702,7 +702,7 @@ _cb_redir (enum grecs_callback_command cmd, {NULL} }; int res; - + switch (value->type) { case GRECS_TYPE_STRING: @@ -719,7 +719,7 @@ _cb_redir (enum grecs_callback_command cmd, return 0; } break; - + case GRECS_TYPE_ARRAY: if (assert_grecs_value_type (locus, value->v.arg.v[0], GRECS_TYPE_STRING)) @@ -739,12 +739,12 @@ _cb_redir (enum grecs_callback_command cmd, if (assert_grecs_value_type (locus, value->v.arg.v[1], GRECS_TYPE_STRING)) return 0; - + switch (res) { case redir_null: break; - + case redir_syslog: if (string_to_syslog_priority (value->v.arg.v[1]->v.string, &rp->v.prio)) @@ -755,7 +755,7 @@ _cb_redir (enum grecs_callback_command cmd, return 0; } break; - + case redir_file: rp->v.file = grecs_strdup (value->v.arg.v[1]->v.string); break; @@ -764,17 +764,17 @@ _cb_redir (enum grecs_callback_command cmd, rp->type = res; } break; - + default: grecs_error (locus, 0, _("unexpected list")); } - + return 0; } static struct tokendef socktype_xtab[] = { - { "stream", SOCK_STREAM }, - { "dgram", SOCK_DGRAM }, + { "stream", SOCK_STREAM }, + { "dgram", SOCK_DGRAM }, { "seqpacket", SOCK_SEQPACKET }, { "raw", SOCK_RAW }, { "rdm", SOCK_RDM }, @@ -820,12 +820,14 @@ static struct tokendef modetab[] = { {"nostartaccept", pies_comp_inetd}, {"pass-fd", pies_comp_pass_fd}, {"pass", pies_comp_pass_fd}, + {"startup", pies_comp_startup}, + {"shutdown", pies_comp_shutdown}, {"boot", pies_comp_boot}, {"bootwait", pies_comp_boot}, {"powerfail", pies_comp_powerfail}, {"powerwait", pies_comp_powerwait}, {"powerokwait", pies_comp_powerokwait}, - {"ctrlaltdel", pies_comp_ctrlaltdel}, + {"ctrlaltdel", pies_comp_ctrlaltdel}, {"ondemand", pies_comp_ondemand}, {"sysinit", pies_comp_sysinit}, {"powerfailnow", pies_comp_powerfailnow}, @@ -920,11 +922,11 @@ _cb_flags (enum grecs_callback_command cmd, return 1; } break; - + case GRECS_TYPE_LIST: { struct grecs_list_entry *ep; - + for (ep = value->v.list->head; ep; ep = ep->next) { const grecs_value_t *vp = ep->data; @@ -939,7 +941,7 @@ _cb_flags (enum grecs_callback_command cmd, } } break; - + case GRECS_TYPE_ARRAY: grecs_error (locus, 0, _("too many arguments")); return 1; @@ -1228,7 +1230,7 @@ struct grecs_keyword * find_component_keyword (const char *ident) { struct grecs_keyword *kwp; - + for (kwp = component_keywords; kwp->ident; kwp++) if (strcmp (kwp->ident, ident) == 0) return kwp; @@ -1256,7 +1258,7 @@ component_section_parser (enum grecs_callback_command cmd, comp = *(struct component **) section_data; component_finish (comp, locus); break; - + case grecs_callback_set_value: grecs_error (locus, 0, _("expected block statement")); } @@ -1534,7 +1536,7 @@ pies_config_parse (char const *name) if (!tree) return 1; - + for (node = tree; node; node = node->next) { node = grecs_find_node (node, "identity-provider"); @@ -1550,7 +1552,7 @@ pies_config_parse (char const *name) if (grecs_error_count) return 1; - + return 0; } @@ -1573,7 +1575,7 @@ pies_read_config (void) int err = 0; component_config_begin (); - + for (ep = config_list->head; ep; ep = ep->next) { struct config_file *file = ep->data; @@ -1583,10 +1585,10 @@ pies_read_config (void) if (init_process) err = 0; - + if (err) component_config_rollback (); - + return err; } @@ -1656,7 +1658,7 @@ setsigvhan (RETSIGTYPE (*handler) (int signo), int *sigv, int sigc) { int i; struct sigaction act; - + act.sa_flags = 0; sigemptyset (&act.sa_mask); for (i = 0; i < sigc; i++) @@ -1779,7 +1781,7 @@ request_restart_components (size_t cc, char **cv) { char **argv; size_t i, j; - + argv = grecs_calloc (5 + 3 * cc - 1, sizeof (*argv)); argv[0] = "piesctl"; argv[1] = "--url"; @@ -1803,7 +1805,7 @@ void list_components (void) { char *argv[5]; - + argv[0] = "piesctl"; argv[1] = "--url"; argv[2] = (char*) pies_control_url (); @@ -1942,7 +1944,7 @@ set_mailer_argcv (void) { int i; struct wordsplit ws; - + if (wordsplit (mailer_command_line, &ws, WRDSF_DEFFLAGS)) { logmsg (LOG_CRIT, _("cannot parse mailer command line: %s"), @@ -2033,7 +2035,7 @@ main (int argc, char **argv) struct grecs_list_entry *ep; int diag_flags; int i; - + set_program_name (argv[0]); #ifdef ENABLE_NLS setlocale (LC_ALL, ""); @@ -2043,10 +2045,10 @@ main (int argc, char **argv) mf_proctitle_init (argc, argv, environ); grecs_print_diag_fun = pies_diag_printer; - + pies_master_argc = argc; pies_master_argv = argv; - + set_quoting_style (NULL, shell_quoting_style); init_process = getpid () == 1; @@ -2058,7 +2060,7 @@ main (int argc, char **argv) break; } } - + /* Set default logging */ if (init_process) { @@ -2067,13 +2069,13 @@ main (int argc, char **argv) } else diag_flags = DIAG_TO_SYSLOG | (stderr_closed_p () ? 0 : DIAG_TO_STDERR); - + diag_setup (diag_flags); - + config_init (); parse_options (&argc, &argv); - + if (argc && !(command == COM_RESTART_COMPONENT || command == COM_TRACE_DEPEND || command == COM_TRACE_PREREQ)) @@ -2081,7 +2083,7 @@ main (int argc, char **argv) logmsg (LOG_ERR, "extra command line arguments"); exit (EX_USAGE); } - + if (!instance) { instance = strrchr (program_name, '/'); @@ -2119,13 +2121,13 @@ main (int argc, char **argv) set_state_file_names (instance); set_mailer_argcv (); - + if (lint_mode) 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 (!control.url) { char const *str = default_control_url[init_process]; @@ -2137,7 +2139,7 @@ main (int argc, char **argv) exit (EX_OSERR); } } - + switch (command) { case COM_RESTART_COMPONENT: @@ -2145,7 +2147,7 @@ main (int argc, char **argv) if (pies_umask) umask (pies_umask); exit (request_restart_components (argc, argv)); - + case COM_RELOAD: exit (request_reload ()); @@ -2162,11 +2164,11 @@ main (int argc, char **argv) case COM_TRACE_DEPEND: components_trace (argv, depmap_row); exit (0); - - case COM_TRACE_PREREQ: + + case COM_TRACE_PREREQ: components_trace (argv, depmap_col); exit (0); - + default: pies_priv_setup (&pies_privs); if (pies_umask) @@ -2193,13 +2195,13 @@ main (int argc, char **argv) exit (EX_USAGE); } break; - + case pies_status_running: logmsg (LOG_ERR, _("another pies instance already running (pid %lu)"), (unsigned long) pid); exit (EX_USAGE); } - + if (!foreground) { check_pidfile (pidfile); @@ -2212,14 +2214,14 @@ main (int argc, char **argv) } logmsg (LOG_INFO, _("%s %s starting"), proginfo.package, proginfo.version); - + if (!init_process) { if (ctl_open ()) exit (EX_UNAVAILABLE); create_pidfile (pidfile); } - + if (pies_master_argv[0][0] != '/') logmsg (LOG_NOTICE, _("not started as an absolute pathname; " @@ -2228,6 +2230,7 @@ main (int argc, char **argv) signal_setup (sig_handler); progman_create_sockets (); + program_init_startup (); progman_start (); do @@ -2261,7 +2264,7 @@ main (int argc, char **argv) pies_schedule_children (PIES_CHLD_WAKEUP); action = ACTION_CONT; break; - + case ACTION_STOP: if (init_process) { @@ -2276,7 +2279,7 @@ main (int argc, char **argv) pies_schedule_children (PIES_CHLD_WAKEUP); action = ACTION_CONT; break; - + case ACTION_KBREQUEST: debug (1, ("kbrequest")); sysvinit_runlevel_setup (PIES_COMP_MASK (pies_comp_kbrequest)); diff --git a/src/pies.h b/src/pies.h index a7f6567..bdc406b 100644 --- a/src/pies.h +++ b/src/pies.h @@ -104,7 +104,7 @@ struct action enum return_action act; /* Action to take when the component terminates */ char *addr; /* Addresses to notify about it. */ char *message; /* Notification mail. */ - char *command; /* Execute this command */ + char *command; /* Execute this command */ }; @@ -137,14 +137,21 @@ enum pies_comp_mode component via the UNIX domain socket. Corresponds to `start_action = pass' in MeTA1. */ pies_comp_pass_fd, - + + /* Components of this type runs once on program startup. Running other + components is delayed until the last startup component finishes. */ + pies_comp_startup, + + /* FIXME: Runs before program termination */ + pies_comp_shutdown, + /* ** Init-style components */ pies_mark_sysvinit, /* Start the process when the specified runlevel is entered and wait for its termination */ - pies_comp_wait = pies_mark_sysvinit, + pies_comp_wait = pies_mark_sysvinit, /* Execute the component once, when the specified runlevel is entered */ pies_comp_once, /* Execute the component during system boot. Ignore runlevel settings. */ @@ -162,7 +169,7 @@ enum pies_comp_mode pies_comp_powerokwait, /* Execute the process when SIGINT is delivered, i.e. someone has pressed the Ctrl+Alt+Del combination. */ - pies_comp_ctrlaltdel, + pies_comp_ctrlaltdel, /* Execute the component when a specified ondemand runlevel is called */ pies_comp_ondemand, /* Execute the component on the system boot. */ @@ -184,16 +191,16 @@ enum pies_comp_mode #define CF_DISABLED 0x001 /* The componenet is disabled */ #define CF_PRECIOUS 0x002 /* The component is precious (should not - be disabled) */ + be disabled) */ #define CF_WAIT 0x004 /* Wait for the component instance to - terminate. */ + terminate. */ #define CF_TCPMUX 0x008 /* A plain TCPMUX service */ #define CF_TCPMUXPLUS 0x010 /* A TCPMUX-plus service, i.e. pies - must emit a '+' response before starting - it */ + must emit a '+' response before starting + it */ #define CF_INTERNAL 0x020 /* An internal inetd service */ #define CF_SOCKENV 0x040 /* Component wants socket information in - the environment */ + the environment */ #define CF_RESOLVE 0x080 /* Resolve IP addresses */ #define CF_SIGGROUP 0x100 /* Send signals to the process group */ @@ -210,9 +217,9 @@ 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. */ + 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 */ @@ -232,7 +239,7 @@ struct component /* For exec (init) components */ char *runlevels; - + /* For inetd components */ size_t max_rate; /* Maximum number of invocations per minute */ size_t max_ip_connections; /* Max. number of connections per IP address */ @@ -253,9 +260,9 @@ struct component char *access_denied_message; char *max_instances_message; char *max_ip_connections_message; - + /* Redirectors: */ - int facility; /* Syslog facility. */ + int facility; /* Syslog facility. */ struct redirector redir[2]; /* Repeaters for stdout and stderr */ /* Actions to execute on various exit codes: */ struct grecs_list *act_list; @@ -334,6 +341,7 @@ int pies_read_config (void); int pies_reread_config (void); void register_prog (struct component *comp); +void program_init_startup (void); int progman_waiting_p (void); void progman_start (void); void progman_gc (void); @@ -594,7 +602,7 @@ struct sysvinit_request #define SYSV_ACCT_BOOT 0 #define SYSV_ACCT_RUNLEVEL 1 #define SYSV_ACCT_PROC_START 2 -#define SYSV_ACCT_PROC_STOP 3 +#define SYSV_ACCT_PROC_STOP 3 void sysvinit_acct (int what, const char *user, const char *id, pid_t pid, const char *line); diff --git a/src/progman.c b/src/progman.c index 1b09cd5..5bc4eb3 100644 --- a/src/progman.c +++ b/src/progman.c @@ -65,7 +65,7 @@ progman_lookup_component (const char *tag) if (IS_COMPONENT (prog) && strcmp (prog_tag (prog), tag) == 0) return prog->v.p.comp; return NULL; -} +} struct component * progman_lookup_tcpmux (const char *service, const char *master) @@ -122,7 +122,7 @@ link_prog (struct prog *prog, struct prog *ref) prog->prev = ref; prog->next = ref->next; - + if ((x = ref->next)) x->prev = prog; else @@ -151,21 +151,21 @@ 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 && p->v.p.socket != -1) - deregister_socket (p->v.p.socket); - /* FIXME: Remove also all dependent progs (esp. tcpmux) */ + deregister_socket (p->v.p.socket); + /* FIXME: Remove also all dependent progs (esp. tcpmux) */ if (p->v.p.redir[RETR_OUT]) p->v.p.redir[RETR_OUT]->v.r.master = NULL; if (p->v.p.redir[RETR_ERR]) p->v.p.redir[RETR_ERR]->v.r.master = NULL; break; - + case TYPE_REDIRECTOR: { struct prog *master = p->v.r.master; @@ -182,7 +182,7 @@ destroy_prog (struct prog **pp) free (p->v.r.tag); } break; - + case TYPE_COMMAND: free (p->v.c.tag); free (p->v.c.command); @@ -256,7 +256,7 @@ find_prog_ref (struct component *comp) if (!comp) return NULL; /* FIXME: Skip redirectors? */ } - + if (comp->prog) { for (prog = comp->prog; @@ -270,12 +270,12 @@ find_prog_ref (struct component *comp) prog = NULL; return prog; } - + static struct prog * register_prog0 (struct component *comp) { struct prog *newp; - + newp = grecs_zalloc (sizeof (*newp)); newp->type = TYPE_COMPONENT; newp->pid = 0; @@ -291,7 +291,7 @@ register_prog0 (struct component *comp) newp->active = 0; else newp->active = 1; - + if (comp->mode != pies_comp_exec) comp->redir[RETR_OUT].type = redir_null; @@ -317,14 +317,29 @@ register_command (char *tag, char *command, pid_t pid) link_prog (newp, progtail); } +static inline int +progman_startup_phase (void) +{ + struct prog *prog; + + for (prog = proghead; prog; prog = prog->next) + { + if (IS_COMPONENT (prog) && prog->v.p.comp->mode == pies_comp_startup) + return 1; + } + return 0; +} + int progman_waiting_p (void) { struct prog *prog; - + for (prog = proghead; prog; prog = prog->next) { - if (IS_COMPONENT (prog) && prog->wait && prog->pid > 0) + if (IS_COMPONENT (prog) + && prog->pid > 0 + && (prog->wait || prog->v.p.comp->mode == pies_comp_startup)) { debug (3, ("%s: waiting for %s (%lu)", __FUNCTION__, prog_tag (prog), @@ -406,17 +421,17 @@ open_redirector (struct prog *master, int stream) case redir_file: return redirect_to_file (master, stream); - + case redir_syslog: break; } - + if (pipe (p)) { logmsg (LOG_CRIT, "pipe: %s", strerror (errno)); return -1; } - + switch (pid = fork ()) { case 0: @@ -428,10 +443,10 @@ open_redirector (struct prog *master, int stream) FD_ZERO (&fdset); FD_SET (p[0], &fdset); close_fds (&fdset); - + diag_setup (0); signal_setup (redir_exit); - + close (p[1]); fp = fdopen (p[0], "r"); if (fp == NULL) @@ -441,7 +456,7 @@ open_redirector (struct prog *master, int stream) while (getline (&buf, &size, fp) > 0) syslog (prio, "%s", buf); _exit (0); - + case -1: logmsg (LOG_CRIT, _("cannot run redirector `%s': fork failed: %s"), @@ -466,7 +481,7 @@ conn_class_hasher (void *data, unsigned long n_buckets) size_t value = 0; unsigned char ch; size_t len; - + while ((ch = *tag++)) value = (value * 31 + ch) % n_buckets; @@ -530,7 +545,7 @@ conn_class_lookup (const char *tag, probe->sa_storage.s.sa_family); break; } - + probe->count = 0; if (!conn_tab) { @@ -725,7 +740,7 @@ env_concat (const char *name, size_t namelen, const char *a, const char *b) { char *res; size_t len; - + if (a && b) { res = grecs_malloc (namelen + 1 + strlen (a) + strlen (b) + 1); @@ -753,14 +768,14 @@ env_concat (const char *name, size_t namelen, const char *a, const char *b) res[namelen] = '='; return res; } - + static void environ_setup (char **hint) { char **old_env = environ; char **new_env; size_t count, i, j, n; - + if (!hint) return; @@ -769,22 +784,22 @@ environ_setup (char **hint) old_env = NULL; hint++; } - + /* Count new environment size */ count = 0; if (old_env) for (i = 0; old_env[i]; i++) count++; - + for (i = 0; hint[i]; i++) count++; /* Allocate new environment. */ new_env = grecs_calloc (count + 1, sizeof new_env[0]); - + /* Populate the environment. */ n = 0; - + if (old_env) for (i = 0; old_env[i]; i++) { @@ -795,7 +810,7 @@ environ_setup (char **hint) for (i = 0; hint[i]; i++) { char *p; - + if (hint[i][0] == '-') { /* Skip unset directives. */ @@ -806,12 +821,12 @@ environ_setup (char **hint) slot if there's no such variable in new_env */ if (find_env_pos (new_env, hint[i], &j, NULL)) j = n; - + if ((p = strchr (hint[i], '='))) { if (p == hint[i]) continue; /* Ignore erroneous entry */ - if (p[-1] == '+') + if (p[-1] == '+') new_env[j] = env_concat (hint[i], p - hint[i] - 1, find_env_ptr (environ, hint[i], 1), p + 1); @@ -835,7 +850,7 @@ environ_setup (char **hint) if (envsize) free (environ); - + environ = new_env; envsize = count + 1; } @@ -852,14 +867,14 @@ prog_sockenv (struct prog *prog) union pies_sockaddr_storage *sa_client = &prog->v.p.sa_storage; socklen_t cltlen = prog->v.p.sa_len; const char *proto = NULL; - + if (!(prog->v.p.comp->flags & CF_SOCKENV)) return; if (socket_type_to_str (prog->v.p.comp->socket_type, &proto)) proto = umaxtostr (prog->v.p.comp->socket_type, buf); add_env (ENV_SOCKTYPE, proto); - + if (prog->v.p.comp->socket_url) proto = prog->v.p.comp->socket_url->proto_s; else if (prog->v.p.listener) @@ -868,7 +883,7 @@ prog_sockenv (struct prog *prog) proto = "TCP"; add_env (ENV_PROTO, proto); - + if (getsockname (prog->v.p.socket, (struct sockaddr *) &sa_server, &len) < 0) logmsg (LOG_WARNING, "getsockname(): %s", strerror (errno)); @@ -920,7 +935,7 @@ static int check_rate (struct prog *prog, unsigned testtime, size_t max_count) { time_t now; - + time (&now); if (prog->v.p.timestamp + testtime > now) @@ -930,7 +945,7 @@ check_rate (struct prog *prog, unsigned testtime, size_t max_count) prog->v.p.failcount = 0; prog->v.p.timestamp = now; } - + if (prog->v.p.failcount > max_count) { prog->v.p.timestamp = now; @@ -938,7 +953,7 @@ check_rate (struct prog *prog, unsigned testtime, size_t max_count) pies_schedule_children (PIES_CHLD_RESCHEDULE_ALARM); return 1; } - + return 0; } @@ -961,7 +976,7 @@ static int check_connection_rate (struct prog *prog) { size_t max_rate = prog->v.p.comp->max_rate - ? prog->v.p.comp->max_rate : default_max_rate; + ? prog->v.p.comp->max_rate : default_max_rate; if (max_rate && check_rate (prog, 60, max_rate)) { logmsg (LOG_NOTICE, @@ -1009,7 +1024,7 @@ prog_start_prologue (struct prog *prog) logmsg (LOG_ERR, _("%s: cannot change to directory %s: %s"), prog_tag (prog), prog->v.p.comp->dir, strerror (errno)); } - + environ_setup (prog->v.p.comp->env ? prog->v.p.comp->env : ((prog->v.p.comp->flags & CF_SOCKENV) ? sockenv_hint : NULL)); @@ -1020,16 +1035,16 @@ prog_start_prologue (struct prog *prog) pies_priv_setup (&prog->v.p.comp->privs); if (prog->v.p.comp->umask) umask (prog->v.p.comp->umask); - + set_limits (prog_tag (prog), prog->v.p.comp->limits ? prog->v.p.comp->limits : pies_limits); - + if (debug_level >= 1) { int i; struct component *comp = prog->v.p.comp; - + logmsg_printf (LOG_DEBUG, "executing"); for (i = 0; i < comp->argc; i++) logmsg_printf (LOG_DEBUG, " %s", quotearg (comp->argv[i])); @@ -1047,7 +1062,7 @@ prog_execute (struct prog *prog) prog->v.p.comp->builtin->fun (0, prog->v.p.comp); _exit (0); } - + execvp (prog->v.p.comp->program ? prog->v.p.comp->program : prog->v.p.comp->argv[0], prog->v.p.comp->argv); @@ -1077,7 +1092,7 @@ prog_start (struct prog *prog) pid_t pid; int redir[2]; fd_set fdset; - + if (prog->pid > 0 || !IS_COMPONENT (prog)) return; @@ -1123,7 +1138,7 @@ prog_start (struct prog *prog) if (prog_open_socket (prog)) return; break; - + case pies_comp_accept: if (check_spawn_rate (prog)) return; @@ -1139,9 +1154,9 @@ prog_start (struct prog *prog) default: break; } - + debug (1, (_("starting %s"), prog_tag (prog))); - + if (prog->v.p.comp->rmfile) { debug (1, (_("unlinking %s"), prog->v.p.comp->rmfile)); @@ -1158,7 +1173,7 @@ prog_start (struct prog *prog) redir[RETR_OUT] = open_redirector (prog, RETR_OUT); redir[RETR_ERR] = open_redirector (prog, RETR_ERR); - + switch (pid = fork ()) { /* The child branch. */ @@ -1167,22 +1182,22 @@ prog_start (struct prog *prog) setsid (); prog_start_prologue (prog); switch (prog->v.p.comp->mode) - { - case pies_comp_accept: - case pies_comp_inetd: + { + case pies_comp_accept: + case pies_comp_inetd: prog_sockenv (prog); - dup2 (prog->v.p.socket, 0); - dup2 (prog->v.p.socket, 1); - close (prog->v.p.socket); + dup2 (prog->v.p.socket, 0); + dup2 (prog->v.p.socket, 1); + close (prog->v.p.socket); prog->v.p.socket = -1; - break; + break; default: if (init_process) { int fd = console_open (O_RDWR|O_NOCTTY); - if (fd < 0) + if (fd < 0) { logmsg (LOG_CRIT, "open(%s): %s", console_device, strerror (errno)); @@ -1218,8 +1233,8 @@ prog_start (struct prog *prog) dup2 (redir[RETR_OUT], 1); } } - break; - } + break; + } if (!init_process) { @@ -1236,7 +1251,7 @@ prog_start (struct prog *prog) dup2 (redir[RETR_ERR], 2); } } - + /* Close unneeded descripitors */ FD_ZERO (&fdset); FD_SET (0, &fdset); @@ -1247,8 +1262,8 @@ prog_start (struct prog *prog) close_fds (&fdset); prog_execute (prog); - - + + case -1: logmsg (LOG_CRIT, _("cannot run `%s': fork failed: %s"), @@ -1291,14 +1306,14 @@ check_acl (pies_acl_t acl, struct sockaddr *s, socklen_t salen, { struct acl_input input; int rc; - + if (!acl) return 0; input.addr = s; input.addrlen = salen; input.identity = identity; - + rc = pies_acl_check (acl, &input, 1); if (rc == 0) { @@ -1315,7 +1330,7 @@ void fd_report (int fd, const char *msg) { size_t len; - + if (!msg) return; @@ -1334,7 +1349,7 @@ fd_report (int fd, const char *msg) len -= rc; msg += rc; } -} +} static int _prog_accept (struct prog *p) @@ -1344,14 +1359,14 @@ _prog_accept (struct prog *p) union pies_sockaddr_storage addr; socklen_t addrlen = sizeof addr; struct conn_class *pcclass; - + fd = accept (p->v.p.socket, (struct sockaddr*) &addr, &addrlen); if (fd == -1) { logfuncall ("accept", NULL, errno); return 1; } - + if (debug_level >= 1) { char *s = sockaddr_to_astr ((struct sockaddr *)&addr, addrlen); @@ -1394,7 +1409,7 @@ _prog_accept (struct prog *p) close (fd); return 1; } - + if (check_connection_rate (p)) { disable_socket (p->v.p.socket); @@ -1447,7 +1462,7 @@ _prog_wait (struct prog *p) p->v.p.num_instances++; return 0; } - + int progman_accept (int socket, void *data) { @@ -1456,7 +1471,7 @@ progman_accept (int socket, void *data) if (p->v.p.comp->socket_type == SOCK_STREAM && !(p->v.p.comp->flags & CF_WAIT)) return _prog_accept (p); - + return _prog_wait (p); } @@ -1525,15 +1540,35 @@ progman_recompute_alarm (void) alarm (alarm_time); } +void +program_init_startup (void) +{ + struct prog *prog; + + for (prog = proghead; prog; prog = prog->next) + if (IS_COMPONENT (prog) && prog->v.p.comp->mode == pies_comp_startup) + { + debug (1, ("running startup components")); + break; + } + + for (; prog; prog = prog->next) + if (IS_COMPONENT (prog) && prog->v.p.comp->mode == pies_comp_startup) + { + prog_start (prog); + } +} + void progman_start (void) { struct prog *prog; if (progman_waiting_p ()) - /* Noting to do if there are processes left in the previous runlevel */ + /* Noting to do if there are processes left in the previous runlevel + (in sysv-init mode) or startup components running. */ return; - + debug (1, ("starting components")); for (prog = proghead; prog; prog = prog->next) if (IS_COMPONENT (prog)) @@ -1565,8 +1600,8 @@ check_stopping (struct prog *prog, time_t now) if (now - prog->v.p.timestamp >= shutdown_timeout) { if (prog->pid == 0) - logmsg (LOG_EMERG, - _("INTERNAL ERROR: attempting to kill unexisting process %s"), + logmsg (LOG_EMERG, + _("INTERNAL ERROR: attempting to kill unexisting process %s"), prog_tag (prog)); else if (prog->v.p.comp->flags & CF_SIGGROUP) kill (-prog->pid, SIGKILL); @@ -1625,7 +1660,7 @@ progman_wake_sleeping (int onalrm) pies_schedule_children (PIES_CHLD_RESCHEDULE_ALARM); } break; - + case status_stopping: check_stopping (prog, now); break; @@ -1634,7 +1669,7 @@ progman_wake_sleeping (int onalrm) if (IS_ACTIVE_COMPONENT (prog)) prog_start (prog); break; - + default: break; } @@ -1647,7 +1682,7 @@ prog_start_prerequisites (struct prog *prog) pies_depmap_pos_t pos; struct component *comp; int warned = 0; - + if (!prog->active) return 1; for (comp = component_depmap_first (depmap_col, prog->v.p.comp->arridx, &pos); @@ -1655,7 +1690,7 @@ prog_start_prerequisites (struct prog *prog) comp = component_depmap_next (pos)) { struct prog *p; - + if (!comp->prog || comp->flags & CF_PRECIOUS) continue; if (!warned) @@ -1669,16 +1704,16 @@ prog_start_prerequisites (struct prog *prog) prog->active = 0; return 1; } - + p = comp->prog; switch (p->v.p.status) { case status_running: continue; - + case status_stopped: break; - + case status_listener: continue; @@ -1700,7 +1735,7 @@ prog_start_prerequisites (struct prog *prog) ret = 1; } depmap_end (pos); - + return ret; } @@ -1757,7 +1792,7 @@ prog_stop (struct prog *prog, int sig) kill (-prog->pid, sig); else kill (prog->pid, sig); -} +} static int mark_for_stopping (struct prog *prog, void *data) @@ -1787,7 +1822,7 @@ print_status (const char *tag, pid_t pid, int status, int expect_term) } else prio = LOG_ERR; - + if (WIFEXITED (status)) { if (WEXITSTATUS (status) == 0) @@ -1801,7 +1836,7 @@ print_status (const char *tag, pid_t pid, int status, int expect_term) else if (WIFSIGNALED (status)) { char const *coremsg = ""; - + if (expect_term && WTERMSIG (status) == SIGTERM) prio = LOG_DEBUG; @@ -1823,7 +1858,7 @@ print_status (const char *tag, pid_t pid, int status, int expect_term) } static void propagate_child_exit (pid_t) ATTRIBUTE_NORETURN; - + static void propagate_child_exit (pid_t pid) { @@ -1855,7 +1890,7 @@ wordsplit_string (struct wordsplit const *ws) char **argv = grecs_calloc (count, sizeof (argv[0])); size_t i; size_t len = 0; - + for (i = 0; i < count; i++) { argv[i] = quotearg_n (i, ws->ws_wordv[i]); @@ -1883,7 +1918,7 @@ send_msg (char *rcpts, const char *msg_text) struct wordsplit ws; int p[2]; size_t size; - + ws.ws_offs = mailer_argc; ws.ws_delim = ","; if (wordsplit (rcpts, &ws, @@ -1896,7 +1931,7 @@ send_msg (char *rcpts, const char *msg_text) } debug (1, (_("sending notification to %s"), rcpts)); - + /* Copy mailer arguments */ for (i = 0; i < mailer_argc; i++) ws.ws_wordv[i] = mailer_argv[i]; @@ -1911,7 +1946,7 @@ send_msg (char *rcpts, const char *msg_text) { char *arg = ws.ws_wordv[i]; size_t len; - + while (*arg && c_isblank (*arg)) arg++; len = strlen (arg); @@ -1934,10 +1969,10 @@ send_msg (char *rcpts, const char *msg_text) k++; } ws.ws_wordv[k] = NULL; - + /* Fork a child: */ child_pid = fork (); - + if (child_pid < 0) { wordsplit_free (&ws); @@ -1955,7 +1990,7 @@ send_msg (char *rcpts, const char *msg_text) register_command (mailer_program, cmd, child_pid); return; } - + /* Child process */ /* ============= */ signal_setup (SIG_DFL); @@ -1967,7 +2002,7 @@ send_msg (char *rcpts, const char *msg_text) wordsplit_free (&ws); exit (EX_OSERR); } - + grand_child_pid = fork (); if (grand_child_pid < 0) { @@ -2030,7 +2065,7 @@ notify_get_tag (char **ret, void *data) if (!s) return WRDSE_NOSPACE; *ret = s; - return WRDSE_OK; + return WRDSE_OK; } static int @@ -2039,7 +2074,7 @@ notify_get_termination (char **ret, void *data) struct notify_closure const *clos = data; char const *msg; char *s; - + if (WIFEXITED (clos->status)) /* TRANSLATORS: The subject of this statement is 'component' */ msg = _("exited with code"); @@ -2053,16 +2088,16 @@ notify_get_termination (char **ret, void *data) if (!s) return WRDSE_NOSPACE; *ret = s; - return WRDSE_OK; + return WRDSE_OK; } - + static int notify_get_retcode (char **ret, void *data) { struct notify_closure const *clos = data; char *s = NULL; size_t l = 0; - + if (WIFEXITED (clos->status)) grecs_asprintf (&s, &l, "%d", WEXITSTATUS (clos->status)); else if (WIFSIGNALED (clos->status)) @@ -2072,9 +2107,9 @@ notify_get_retcode (char **ret, void *data) if (!s) return WRDSE_NOSPACE; *ret = s; - return WRDSE_OK; -} - + return WRDSE_OK; +} + struct notify_variable { char *name; @@ -2090,7 +2125,7 @@ static struct notify_variable notify_vartab[] = { #undef S { NULL } }; - + static int notify_getvar (char **ret, const char *vptr, size_t vlen, void *data) { @@ -2100,7 +2135,7 @@ notify_getvar (char **ret, const char *vptr, size_t vlen, void *data) return var->get (ret, data); return WRDSE_UNDEF; } - + static void notify (const char *tag, int status, struct action *act) { @@ -2120,7 +2155,7 @@ notify (const char *tag, int status, struct action *act) closure.tag = tag; closure.status = status; closure.act = act; - + env[PROGRAM_NAME_IDX] = program_name; env[INSTANCE_IDX] = instance; @@ -2144,7 +2179,7 @@ static int status_matches_p (struct action *act, unsigned status) { int i; - + if (act->nstat == 0) return 1; for (i = 0; i < act->nstat; i++) @@ -2184,7 +2219,7 @@ run_command (struct action *act, struct prog *prog, unsigned retcode, setenv ("PIES_STATUS", umaxtostr (STATUS_CODE (retcode), buf), 1); close_fds (NULL); - + argv[0] = "/bin/sh"; argv[1] = "-c"; argv[2] = act->command; @@ -2208,7 +2243,7 @@ react (struct prog *prog, int status, pid_t pid) if (!list) list = default_component.act_list; - + if (WIFEXITED (status)) { retcode = WEXITSTATUS (status); @@ -2233,21 +2268,21 @@ react (struct prog *prog, int status, pid_t pid) for (ep = list->head; ep; ep = ep->next) { struct action *act = ep->data; - + if (status_matches_p (act, retcode)) { if (act->command) { run_command (act, prog, retcode, pid); } - + switch (act->act) { case action_restart: if (prog->v.p.comp->mode != pies_comp_inetd) prog_start (prog); break; - + case action_disable: logmsg (LOG_NOTICE, _("disabling component %s"), prog_tag (prog)); @@ -2263,7 +2298,7 @@ react (struct prog *prog, int status, pid_t pid) } } } - + if (!list && prog->v.p.comp->mode != pies_comp_inetd) /* Default action: */ prog_start (prog); @@ -2294,7 +2329,7 @@ progman_cleanup (int expect_term) if (prog->v.p.comp->mode == pies_comp_inetd) { struct prog *listener = prog->v.p.listener; - + listener->v.p.num_instances--; if (prog->v.p.cclass) { @@ -2307,7 +2342,7 @@ progman_cleanup (int expect_term) prog->v.p.cclass = NULL; } } - + prog_stop_redirectors (prog); if (listener->v.p.num_instances == 0 && !component_is_active (prog->v.p.comp)) @@ -2321,6 +2356,14 @@ progman_cleanup (int expect_term) } destroy_prog (&prog); } + else if (prog->v.p.comp->mode == pies_comp_startup) + { + debug (1, (_("removing startup component %s, pid=%lu"), + prog_tag (prog), (unsigned long)pid)); + destroy_prog (&prog); + if (!progman_startup_phase ()) + pies_schedule_children (PIES_CHLD_WAKEUP); + } else { if (prog->v.p.comp->mode >= pies_mark_sysvinit @@ -2329,7 +2372,7 @@ progman_cleanup (int expect_term) sysvinit_acct (SYSV_ACCT_PROC_STOP, "", prog_tag (prog), pid, ""); prog->v.p.status = status_finished; - + if (prog->wait) { pies_schedule_children (PIES_CHLD_WAKEUP); @@ -2351,7 +2394,7 @@ progman_cleanup (int expect_term) if (!component_is_active (prog->v.p.comp)) destroy_prog (&prog); } - + break; case TYPE_REDIRECTOR: @@ -2371,7 +2414,7 @@ progman_cleanup (int expect_term) break; } } - + if (!expect_term) /* This will also recompute alarm settings, if necessary */ progman_wake_sleeping (0); @@ -2389,7 +2432,7 @@ progman_stop_component (struct prog **progptr) logmsg (LOG_INFO, _("stopping component %s"), prog_tag (prog)); prog_stop (prog, SIGTERM); break; - + case status_listener: prog_deactivate_listener (prog); /* fall through */ @@ -2413,7 +2456,7 @@ progman_stop_component (struct prog **progptr) case status_stopping: break; - + case status_finished: prog->stop = 0; if (!component_is_active (prog->v.p.comp)) @@ -2441,7 +2484,7 @@ int prog_activate_listener (struct prog *prog) { struct component *comp = prog->v.p.comp; - + logmsg (LOG_INFO, _("activating listener %s"), prog_tag (prog)); if (comp->mode == pies_comp_inetd && !ISCF_TCPMUX (comp->flags) && prog->v.p.socket == -1) @@ -2535,9 +2578,9 @@ progman_gc (void) else break; } - + /* FIXME: Report remaining programs */ - + } - + /* EOF */ diff --git a/src/socket.c b/src/socket.c index aa01543..40c7aa7 100644 --- a/src/socket.c +++ b/src/socket.c @@ -23,13 +23,16 @@ switch_eids (uid_t *puid, gid_t *pgid, mode_t *pumask) uid_t ouid = geteuid (); gid_t ogid = getegid (); mode_t omask = umask (*pumask); - - if (setegid (*pgid)) - logmsg (LOG_ERR, _("cannot switch to EGID %lu: %s"), - (unsigned long) *pgid, strerror (errno)); - if (seteuid (*puid)) - logmsg (LOG_ERR, _("cannot switch to EUID %lu: %s"), - (unsigned long) *puid, strerror (errno)); + + if ((*puid && *puid != ouid) || (*pgid && *pgid != ogid)) + { + if (setegid (*pgid)) + logmsg (LOG_ERR, _("cannot switch to EGID %lu: %s"), + (unsigned long) *pgid, strerror (errno)); + if (seteuid (*puid)) + logmsg (LOG_ERR, _("cannot switch to EUID %lu: %s"), + (unsigned long) *puid, strerror (errno)); + } *puid = ouid; *pgid = ogid; *pumask = omask; @@ -51,14 +54,14 @@ create_socket (struct pies_url *url, int socket_type, uid_t uid = 0; gid_t gid = 0; int switch_back; - + if (strcmp (url->scheme, "unix") == 0 || strcmp (url->scheme, "file") == 0 || strcmp (url->scheme, "socket") == 0) { struct stat st; const char *group = NULL; - + user = url->user; if (url->argc) { @@ -99,7 +102,7 @@ create_socket (struct pies_url *url, int socket_type, } } } - + if (user) { struct passwd *pw = getpwnam (user); @@ -111,7 +114,7 @@ create_socket (struct pies_url *url, int socket_type, uid = pw->pw_uid; gid = pw->pw_gid; } - + if (group) { struct group *grp = getgrnam (group); @@ -122,7 +125,7 @@ create_socket (struct pies_url *url, int socket_type, } gid = grp->gr_gid; } - + if (strlen (url->path) > sizeof addr.s_un.sun_path) { errno = EINVAL; @@ -159,14 +162,14 @@ create_socket (struct pies_url *url, int socket_type, { const char *host = url->host; short port = url->port; - + uid = 0; gid = 0; umaskval = 0; addr.sa.sa_family = PF_INET; socklen = sizeof (addr.s_in); - + if (!host) addr.s_in.sin_addr.s_addr = INADDR_ANY; else @@ -185,7 +188,7 @@ create_socket (struct pies_url *url, int socket_type, memmove (&addr.s_in.sin_addr, hp->h_addr, 4); addr.s_in.sin_port = htons (port); break; - + default: logmsg (LOG_ERR, _("%s: unsupported address family"), url->string); @@ -198,7 +201,7 @@ create_socket (struct pies_url *url, int socket_type, logmsg (LOG_ERR, "%s: unknown scheme", url->string); return -1; } - + fd = socket (addr.sa.sa_family, socket_type, url->proto); if (fd == -1) { @@ -250,7 +253,7 @@ pass_fd0 (int fd, int payload) # ifndef CMSG_SPACE # define CMSG_SPACE(size) (sizeof(struct cmsghdr) + (size)) # endif /* ! CMSG_SPACE */ - + char control[CMSG_SPACE (sizeof (int))]; struct cmsghdr *cmptr; @@ -290,7 +293,7 @@ pass_fd (const char *socket_name, int fd, unsigned maxtime) int sockfd = -1; int res = -1; struct sockaddr_un addr; - + if (strlen (socket_name) > sizeof addr.sun_path) { logmsg (LOG_ERR, _("%s: UNIX socket name too long"), socket_name); @@ -298,7 +301,7 @@ pass_fd (const char *socket_name, int fd, unsigned maxtime) } addr.sun_family = AF_UNIX; strcpy (addr.sun_path, socket_name); - + for (;;) { time_t now = time (NULL); @@ -362,7 +365,7 @@ pass_fd (const char *socket_name, int fd, unsigned maxtime) int rc; fd_set fds; struct timeval tv; - + FD_ZERO (&fds); FD_SET (sockfd, &fds); tv.tv_usec = 0; @@ -430,7 +433,7 @@ calc_fd_max (void) } void * -register_socket (int fd, +register_socket (int fd, socket_handler_t rd, socket_handler_t wr, socket_handler_t ex, @@ -454,7 +457,7 @@ register_socket (int fd, FD_ZERO (&fdset[PIES_EVT_EX]); si_head = sip; } - + si_tail = sip; if (rd) FD_SET (fd, &fdset[PIES_EVT_RD]); @@ -493,7 +496,7 @@ delete_sockinst (struct sockinst *sp) if (sp->handler[PIES_EVT_EX]) FD_CLR (sp->fd, &fdset[PIES_EVT_EX]); fd_max = -1; - + if (sp->prev) sp->prev->next = sp->next; else @@ -572,7 +575,7 @@ pies_pause (void) { if (pies_pause_hook && pies_pause_hook ()) return; - + if (fd_max == -1) calc_fd_max (); @@ -581,7 +584,7 @@ pies_pause (void) fd_set rdset = fdset[PIES_EVT_RD]; fd_set wrset = fdset[PIES_EVT_WR]; fd_set exset = fdset[PIES_EVT_EX]; - + int rc = select (fd_max + 1, &rdset, &wrset, &exset, NULL); if (rc > 0) { @@ -637,4 +640,3 @@ pies_pause (void) } } } - diff --git a/tests/Makefile.am b/tests/Makefile.am index 447104b..b2f2719 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -14,7 +14,13 @@ # You should have received a copy of the GNU General Public License # along with GNU Pies. If not, see . -EXTRA_DIST = $(TESTSUITE_AT) testsuite package.m4 respawn retcode mailer +AUXTOOLS = \ + aux/respawn\ + aux/retcode\ + aux/mailer\ + aux/startup + +EXTRA_DIST = $(TESTSUITE_AT) testsuite package.m4 $(AUXTOOLS) DISTCLEANFILES = atconfig $(check_SCRIPTS) MAINTAINERCLEANFILES = Makefile.in $(TESTSUITE) @@ -46,6 +52,7 @@ TESTSUITE_AT = \ redirect.at\ ret-exec.at\ ret-notify.at\ + startup.at\ version.at TESTSUITE = $(srcdir)/testsuite diff --git a/tests/atlocal.in b/tests/atlocal.in index 9069bbd..1992b80 100644 --- a/tests/atlocal.in +++ b/tests/atlocal.in @@ -4,7 +4,7 @@ PATH=@abs_builddir@:@abs_top_builddir@/src:$srcdir:$PATH XFAILFILE=$abs_builddir/.badversion - +auxdir="$abs_srcdir/aux" trimws() { sed 's/[ ][ ]*$//' } diff --git a/tests/aux/mailer b/tests/aux/mailer new file mode 100755 index 0000000..f832ff5 --- /dev/null +++ b/tests/aux/mailer @@ -0,0 +1,7 @@ +#! /bin/sh + +exec >${1:?} +shift +echo $* +cat - + diff --git a/tests/aux/respawn b/tests/aux/respawn new file mode 100755 index 0000000..11d59f6 --- /dev/null +++ b/tests/aux/respawn @@ -0,0 +1,63 @@ +#! /bin/sh + +# usage: respawn [-append] [-stderr FILE] [-stdout FILE] [-sleep TIME] +# [-pid FILE] [-tag STRING] [-exit CODE] + +append=0 +unset name +time=10 +tag=$0 +code=0 + +while [ $# -ne 0 ] +do + arg=$1 + shift + case $arg in + -append) + append=1;; + -stderr) + name=${1:?missing argument for -stderr} + shift + if [ $append -eq 1 ]; then + exec 2>>$name + append=0 + else + exec 2>$name + fi;; + -stdout) + name=${1:?missing argument for -stdout} + shift + if [ $append -eq 1 ]; then + exec >>$name + append=0 + else + exec >$name + fi;; + -sleep) + time=${1:?missing argument for -sleep} + shift;; + -pid) + name=${1:?missing argument for -pid} + shift + if [ $append -eq 1 ]; then + echo $$ >>$name + append=0 + else + echo $$ >$name + fi;; + -tag) + tag=${1:?missing argument for -tag} + shift;; + -exit) + code=${1:?missing argument for -exit} + shift;; + *) echo >&2 "$tag: invalid argument: $arg" + exit 1 + esac +done + +echo "$tag: start" +sleep $time +echo "$tag: stop" +exit $code diff --git a/tests/aux/retcode b/tests/aux/retcode new file mode 100755 index 0000000..b827ba9 --- /dev/null +++ b/tests/aux/retcode @@ -0,0 +1,9 @@ +#! /bin/sh + +exec >${1:?} + +echo $PIES_VERSION +echo $PIES_COMPONENT +echo $PIES_PID +echo $PIES_STATUS +echo ${PIES_SIGNAL:-No signal} diff --git a/tests/aux/startup b/tests/aux/startup new file mode 100755 index 0000000..b9d92a3 --- /dev/null +++ b/tests/aux/startup @@ -0,0 +1,7 @@ +#!/bin/sh +dir=${1:?} +time=${2:?} +tag=${3:?} + +touch $dir/$tag +sleep $time diff --git a/tests/mailer b/tests/mailer deleted file mode 100755 index f832ff5..0000000 --- a/tests/mailer +++ /dev/null @@ -1,7 +0,0 @@ -#! /bin/sh - -exec >${1:?} -shift -echo $* -cat - - diff --git a/tests/redirect.at b/tests/redirect.at index 9e53ba2..3a8cca7 100644 --- a/tests/redirect.at +++ b/tests/redirect.at @@ -24,7 +24,7 @@ outfile=$PWD/out cat > pies.conf <<_EOT component test { mode respawn; - command "$abs_srcdir/respawn -tag respawn -append -pid $comp_pid_file"; + command "$auxdir/respawn -tag respawn -append -pid $comp_pid_file"; stdout file "$outfile"; } _EOT diff --git a/tests/respawn b/tests/respawn deleted file mode 100755 index 11d59f6..0000000 --- a/tests/respawn +++ /dev/null @@ -1,63 +0,0 @@ -#! /bin/sh - -# usage: respawn [-append] [-stderr FILE] [-stdout FILE] [-sleep TIME] -# [-pid FILE] [-tag STRING] [-exit CODE] - -append=0 -unset name -time=10 -tag=$0 -code=0 - -while [ $# -ne 0 ] -do - arg=$1 - shift - case $arg in - -append) - append=1;; - -stderr) - name=${1:?missing argument for -stderr} - shift - if [ $append -eq 1 ]; then - exec 2>>$name - append=0 - else - exec 2>$name - fi;; - -stdout) - name=${1:?missing argument for -stdout} - shift - if [ $append -eq 1 ]; then - exec >>$name - append=0 - else - exec >$name - fi;; - -sleep) - time=${1:?missing argument for -sleep} - shift;; - -pid) - name=${1:?missing argument for -pid} - shift - if [ $append -eq 1 ]; then - echo $$ >>$name - append=0 - else - echo $$ >$name - fi;; - -tag) - tag=${1:?missing argument for -tag} - shift;; - -exit) - code=${1:?missing argument for -exit} - shift;; - *) echo >&2 "$tag: invalid argument: $arg" - exit 1 - esac -done - -echo "$tag: start" -sleep $time -echo "$tag: stop" -exit $code diff --git a/tests/respawn.at b/tests/respawn.at index 8d72c40..4a8e3a7 100644 --- a/tests/respawn.at +++ b/tests/respawn.at @@ -23,7 +23,7 @@ comp_pid_file=$PWD/comp.pid cat > pies.conf <<_EOT component test { mode respawn; - command "$abs_srcdir/respawn -append -pid $comp_pid_file"; + command "$auxdir/respawn -append -pid $comp_pid_file"; } _EOT diff --git a/tests/ret-exec.at b/tests/ret-exec.at index bf2c1a4..0b3d716 100644 --- a/tests/ret-exec.at +++ b/tests/ret-exec.at @@ -26,10 +26,10 @@ cat > pies.conf <<_EOT component test { mode respawn; return-code 10 { - exec "$abs_srcdir/retcode $report_file"; + exec "$auxdir/retcode $report_file"; action disable; } - command "$abs_srcdir/respawn -sleep 2 -pid $comp_pid_file -exit 10"; + command "$auxdir/respawn -sleep 2 -pid $comp_pid_file -exit 10"; } _EOT diff --git a/tests/ret-notify.at b/tests/ret-notify.at index d1a7f39..a7768aa 100644 --- a/tests/ret-notify.at +++ b/tests/ret-notify.at @@ -22,15 +22,15 @@ PIES_XFAIL_CHECK PIES_CONTROL_INIT report_file=$PWD/report cat > pies.conf <<_EOT -mailer-program "$abs_srcdir/mailer"; -mailer-command-line "$abs_srcdir/mailer $report_file"; +mailer-program "$auxdir/mailer"; +mailer-command-line "$auxdir/mailer $report_file"; component test { mode respawn; return-code 10 { notify root; action disable; } - command "$abs_srcdir/respawn -sleep 2 -exit 10"; + command "$auxdir/respawn -sleep 2 -exit 10"; } _EOT diff --git a/tests/retcode b/tests/retcode deleted file mode 100755 index b827ba9..0000000 --- a/tests/retcode +++ /dev/null @@ -1,9 +0,0 @@ -#! /bin/sh - -exec >${1:?} - -echo $PIES_VERSION -echo $PIES_COMPONENT -echo $PIES_PID -echo $PIES_STATUS -echo ${PIES_SIGNAL:-No signal} diff --git a/tests/startup.at b/tests/startup.at new file mode 100644 index 0000000..72017ce --- /dev/null +++ b/tests/startup.at @@ -0,0 +1,84 @@ +# This file is part of GNU pies testsuite. -*- Autotest -*- +# Copyright (C) 2019 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 . + +AT_SETUP([Startup components]) + +AT_CHECK([ +PIES_XFAIL_CHECK +PIES_CONTROL_INIT +comp_pid_file=$PWD/comp.pid + +cat > pies.conf <<_EOT +component b1 { + mode startup; + command "$auxdir/startup $PWD 1 b1"; +} + +component b2 { + mode startup; + command "$auxdir/startup $PWD 2 b2"; +} + +component test { + mode respawn; + command "$auxdir/respawn -append -pid $comp_pid_file"; +} +_EOT + +pies --config-file control.conf --config-file pies.conf + +n=0 +res= +b1= +b2= +while : +do + echo "n=$n" >> tracefile + if test -z "$b1" && test -f b1; then + res="${res}b1" + b1=1 + echo "got b1" >> tracefile + fi + if test -z "$b2" && test -f b2; then + res="${res}b2" + b2=1 + echo "got b2" >> tracefile + fi + if test -f $comp_pid_file; then + echo "got pidfile" >> tracefile + res="${res}pid" + break + fi + sleep 1 + n=$(($n + 1)) + if test $n -gt 10; then + echo >&2 "timed out" + break + fi +done + +PIES_STOP +case $res in +b1b2pid|b2b1pid) echo b1b2pid;; +*) echo $res +esac +], +[0], +[b1b2pid +]) + +AT_CLEANUP + diff --git a/tests/testsuite.at b/tests/testsuite.at index 03ddd50..2a1167d 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at @@ -65,3 +65,4 @@ m4_include([respawn.at]) m4_include([redirect.at]) m4_include([ret-exec.at]) m4_include([ret-notify.at]) +m4_include([startup.at]) -- cgit v1.2.1