-rw-r--r-- | src/comp.c | 87 | ||||
-rw-r--r-- | src/pies.c | 115 | ||||
-rw-r--r-- | src/pies.h | 38 | ||||
-rw-r--r-- | src/progman.c | 291 | ||||
-rw-r--r-- | src/socket.c | 54 | ||||
-rw-r--r-- | tests/Makefile.am | 9 | ||||
-rw-r--r-- | tests/atlocal.in | 2 | ||||
-rwxr-xr-x | tests/aux/mailer (renamed from tests/mailer) | 0 | ||||
-rwxr-xr-x | tests/aux/respawn (renamed from tests/respawn) | 0 | ||||
-rwxr-xr-x | tests/aux/retcode (renamed from tests/retcode) | 0 | ||||
-rwxr-xr-x | tests/aux/startup | 7 | ||||
-rw-r--r-- | tests/redirect.at | 2 | ||||
-rw-r--r-- | tests/respawn.at | 2 | ||||
-rw-r--r-- | tests/ret-exec.at | 4 | ||||
-rw-r--r-- | tests/ret-notify.at | 6 | ||||
-rw-r--r-- | tests/startup.at | 84 | ||||
-rw-r--r-- | tests/testsuite.at | 1 |
17 files changed, 442 insertions, 260 deletions
@@ -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); @@ -85,6 +90,22 @@ component_append (struct component *comp) } 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) { struct complist *list = &comp_list[comp->listidx]; @@ -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 @@ -425,17 +451,6 @@ report_cyclic_dependency (pies_depmap_t dp, size_t idx) } 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) { size_t i; @@ -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 @@ -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)); @@ -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); } @@ -1526,14 +1541,34 @@ progman_recompute_alarm (void) } 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 <http://www.gnu.org/licenses/>. -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/mailer b/tests/aux/mailer index f832ff5..f832ff5 100755 --- a/tests/mailer +++ b/tests/aux/mailer diff --git a/tests/respawn b/tests/aux/respawn index 11d59f6..11d59f6 100755 --- a/tests/respawn +++ b/tests/aux/respawn diff --git a/tests/retcode b/tests/aux/retcode index b827ba9..b827ba9 100755 --- a/tests/retcode +++ b/tests/aux/retcode diff --git a/tests/aux/startup b/tests/aux/startup new file mode 100755 index 0000000..b9d92a3 --- a/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/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.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/startup.at b/tests/startup.at new file mode 100644 index 0000000..72017ce --- a/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 <http://www.gnu.org/licenses/>. + +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]) |