aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
m---------grecs0
-rw-r--r--lib/Makefile.am1
-rw-r--r--lib/libpies.h1
-rw-r--r--lib/safe_strcmp.c29
-rw-r--r--src/Makefile.am1
-rw-r--r--src/acl.c70
-rw-r--r--src/acl.h3
-rw-r--r--src/cmdline.opt22
-rw-r--r--src/comp.c817
-rw-r--r--src/ctl.c4
-rw-r--r--src/depmap.c28
-rw-r--r--src/inetd.c7
-rw-r--r--src/limits.c11
-rw-r--r--src/pies.c535
-rw-r--r--src/pies.h57
-rw-r--r--src/prog.h7
-rw-r--r--src/progman.c538
-rw-r--r--src/sysvinit.c43
-rw-r--r--src/userprivs.c23
19 files changed, 1398 insertions, 799 deletions
diff --git a/grecs b/grecs
-Subproject ca94270a5e30add9b364d32220fb38d457ebd3f
+Subproject 08070e48d83cd34cddb08be33cf4993fc096c9c
diff --git a/lib/Makefile.am b/lib/Makefile.am
index a0d6614..8f07544 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -24,12 +24,13 @@ libpies_a_SOURCES=\
grecsasrt.c\
mkfilename.c\
netrc.c\
parsetime.c\
proctitle.c\
pp.c\
+ safe_strcmp.c\
split3.c\
strtotok.c\
url.c
libpies_a_LIBADD=\
$(LIBOBJS)\
diff --git a/lib/libpies.h b/lib/libpies.h
index 1c83b8e..5a7dd73 100644
--- a/lib/libpies.h
+++ b/lib/libpies.h
@@ -50,12 +50,13 @@ int strtotok (struct tokendef *tab, const char *str, int *pres);
int strtotok_ci (struct tokendef *tab, const char *str, int *pres);
int toktostr (struct tokendef *tab, int tok, const char **pres);
int is_array_member (char * const * ar, char const *str);
int array_index (char * const *ar, char const *str);
int strsplit3 (const char *input, char *result[3], int flag);
+int safe_strcmp (char const *a, char const *b);
/* url.c */
struct pies_url
{
char *string;
char *scheme;
diff --git a/lib/safe_strcmp.c b/lib/safe_strcmp.c
new file mode 100644
index 0000000..e73176d
--- /dev/null
+++ b/lib/safe_strcmp.c
@@ -0,0 +1,29 @@
+/* This file is part of GNU Pies.
+ Copyright (C) 2015, 2016 Sergey Poznyakoff
+
+ GNU Pies is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GNU Pies is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Pies. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include "libpies.h"
+
+int
+safe_strcmp (char const *a, char const *b)
+{
+ if (!a || !b)
+ return a != b;
+ return strcmp (a, b);
+}
+
diff --git a/src/Makefile.am b/src/Makefile.am
index 3f29b4e..a637077 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -16,12 +16,13 @@
sbin_PROGRAMS = pies
bin_PROGRAMS = piesctl
pies_SOURCES = \
acl.c\
+ comp.c\
ctl.c\
depmap.c\
diag.c\
inetd.c\
inetd-bi.c\
limits.c\
diff --git a/src/acl.c b/src/acl.c
index a96eb77..e7523f5 100644
--- a/src/acl.c
+++ b/src/acl.c
@@ -119,16 +119,19 @@ pies_acl_create (const char *name, grecs_locus_t *locus)
return acl;
}
void
pies_acl_free (pies_acl_t acl)
{
- free (acl->name);
- grecs_locus_free (&acl->locus);
- grecs_list_free (acl->list);
- free (acl);
+ if (acl)
+ {
+ free (acl->name);
+ grecs_locus_free (&acl->locus);
+ grecs_list_free (acl->list);
+ free (acl);
+ }
}
static struct pies_sockaddr *
create_acl_sockaddr (int family, int len)
{
struct pies_sockaddr *p = grecs_zalloc (sizeof (*p));
@@ -249,12 +252,25 @@ _parse_sockaddr (struct acl_entry *entry, const grecs_value_t *value)
sptr->netmask = 0xfffffffful;
}
grecs_list_append (entry->sockaddrs, sptr);
return 0;
}
+static int
+sockaddr_cmp (void const *a, void const *b)
+{
+ struct pies_sockaddr const *ap = a;
+ struct pies_sockaddr const *bp = b;
+
+ if (ap->netmask != bp->netmask)
+ return 1;
+ if (ap->salen != bp->salen)
+ return 1;
+ return memcmp (&ap->sa, &bp->sa, ap->salen);
+}
+
static void
sockaddr_free (void *p)
{
free (p);
}
@@ -282,12 +298,13 @@ _parse_from (struct acl_entry *entry, size_t argc, grecs_value_t **argv)
grecs_error (&entry->locus, 0,
_("unexpected end of statement after `from'"));
return 1;
}
entry->sockaddrs = grecs_list_create ();
+ entry->sockaddrs->cmp = sockaddr_cmp;
entry->sockaddrs->free_entry = sockaddr_free;
if (argv[0]->type == GRECS_TYPE_STRING)
{
if (_parse_sockaddr (entry, argv[0]))
return 1;
}
@@ -430,13 +447,43 @@ parse_acl_line (grecs_locus_t *locus, int allow, pies_acl_t acl,
grecs_error (locus, 0, _("unexpected list"));
return 1;
}
grecs_list_append (acl->list, entry);
return 0;
}
+
+static int
+acl_entry_cmp (void const *a, void const *b)
+{
+ struct acl_entry const *ap = a;
+ struct acl_entry const *bp = b;
+ size_t i;
+
+ if (ap->allow != bp->allow)
+ return 1;
+ if (ap->authenticated != bp->authenticated)
+ return 1;
+ if (pies_acl_cmp (ap->acl, bp->acl))
+ return 1;
+ if (ap->name_match != bp->name_match)
+ return 1;
+ if (ap->names && bp->names)
+ {
+ for (i = 0; ap->names[i]; i++)
+ if (!bp->names[i] || strcmp (ap->names[i], bp->names[i]))
+ return 1;
+ if (bp->names[i])
+ return 1;
+ }
+ else if (ap->names || bp->names)
+ return 1;
+
+ return grecs_list_compare (ap->sockaddrs, bp->sockaddrs);
+}
+
#define ACL_TAG_NONE 0
#define ACL_TAG_IGNORE 1
#define ACL_TAG_OPTIONAL 2
#define ACL_TAG_REQUIRED 3
int
@@ -489,12 +536,17 @@ _acl_common_section_parser (enum grecs_callback_command cmd,
return 1;
if (pacl)
*pacl = acl;
break;
case grecs_callback_section_end:
+ acl = *pacl;
+ if (acl->list)
+ acl->list->cmp = acl_entry_cmp;
+ break;
+
case grecs_callback_set_value:
break;
}
return 0;
}
@@ -772,6 +824,16 @@ pies_acl_lookup (const char *name)
struct pies_acl samp;
if (!acl_table)
return NULL;
samp.name = (char *) name;
return grecs_symtab_lookup_or_install (acl_table, &samp, NULL);
}
+
+int
+pies_acl_cmp (struct pies_acl *a, struct pies_acl *b)
+{
+ if (!a)
+ return !!b;
+ else
+ return 1;
+ return grecs_list_compare (a->list, b->list);
+}
diff --git a/src/acl.h b/src/acl.h
index 757104d..db65e10 100644
--- a/src/acl.h
+++ b/src/acl.h
@@ -1,8 +1,8 @@
/* This file is part of GNU Pies
- Copyright (C) 2009-2013 Sergey Poznyakoff
+ Copyright (C) 2009-2016 Sergey Poznyakoff
GNU Pies is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
@@ -23,12 +23,13 @@ struct acl_input
socklen_t addrlen;
pies_identity_t identity;
};
pies_acl_t pies_acl_create (const char *name, grecs_locus_t *locus);
void pies_acl_free (pies_acl_t acl);
+int pies_acl_cmp (struct pies_acl *a, struct pies_acl *b);
int pies_acl_check (pies_acl_t acl, struct acl_input *input, int result);
int parse_acl_line (grecs_locus_t *locus, int allow, pies_acl_t acl,
grecs_value_t *value);
pies_acl_t pies_acl_lookup (const char *name);
pies_acl_t pies_acl_install (pies_acl_t acl);
diff --git a/src/cmdline.opt b/src/cmdline.opt
index f43d147..389cea7 100644
--- a/src/cmdline.opt
+++ b/src/cmdline.opt
@@ -23,13 +23,13 @@ OPTIONS_BEGIN("pies",
GROUP(Operation Mode)
OPTION(config-file,c,FILE,
[<use FILE instead of the default configuration>])
BEGIN
- add_config (current_syntax, optarg);
+ config_file_add (current_syntax, optarg);
END
OPTION(config-help,,,
[<show configuration file summary>])
BEGIN
config_help ();
@@ -57,13 +57,13 @@ END
OPTION(inetd,i,,
[<run in inetd mode>])
BEGIN
if (!instance)
instance = "inetd";
- current_syntax = CONF_INETD;
+ current_syntax = &config_syntax_tab[CONF_INETD];
inetd_mode = 1;
END
OPTION(instance,,NAME,
[<set instance name>])
BEGIN
@@ -88,13 +88,14 @@ BEGIN
log_to_stderr_only = 1;
END
OPTION(syntax,,[<{pies|meta1|inetd|inittab}>],
[<expect configuration files in the given syntax>])
BEGIN
- if (str_to_config_syntax (optarg, &current_syntax))
+ current_syntax = str_to_config_syntax (optarg);
+ if (!current_syntax)
{
logmsg (LOG_ERR, _("unknown syntax type: %s"), optarg);
exit (EX_USAGE);
}
END
@@ -149,13 +150,13 @@ BEGIN
END
OPTION(restart-component,R,,
[<restart components named in the command line>])
BEGIN
log_to_stderr_only = 1;
- command = COM_RESTART;
+ command = COM_RESTART_COMPONENT;
END
OPTION(status,s,,
[<display info about the running instance>])
BEGIN
log_to_stderr_only = 1;
@@ -175,17 +176,24 @@ OPTION(dump-depmap,,,
[<dump dependency map>])
BEGIN
log_to_stderr_only = 1;
command = COM_DUMP_DEPMAP;
END
-OPTION(dump-prereq,,,
- [<dump prerequisite charts>])
+OPTION(trace-depend,,,
+ [<trace dependencies>])
BEGIN
log_to_stderr_only = 1;
- command = COM_DUMP_PREREQ;
+ command = COM_TRACE_DEPEND;
+END
+
+OPTION(trace-prereq,,,
+ [<trace prerequisites>])
+BEGIN
+ log_to_stderr_only = 1;
+ command = COM_TRACE_PREREQ;
END
OPTION(source-info,,,
[<show source info with debugging messages>])
BEGIN
source_info_option = 1;
diff --git a/src/comp.c b/src/comp.c
new file mode 100644
index 0000000..6f8e11f
--- /dev/null
+++ b/src/comp.c
@@ -0,0 +1,817 @@
+/* This file is part of GNU Pies.
+ Copyright (C) 2016 Sergey Poznyakoff
+
+ GNU Pies is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GNU Pies is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Pies. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "pies.h"
+#include "prog.h"
+#include <assert.h>
+
+struct complist
+{
+ struct component *head;
+ struct component *tail;
+};
+
+static struct complist comp_list[2];
+static int cur;
+
+static struct component **comp_array;
+static size_t comp_count;
+
+static pies_depmap_t depmap;
+
+static int
+next_index (void)
+{
+ return (cur + 1) % ARRAY_SIZE (comp_list);
+}
+
+static int
+prev_index (void)
+{
+ return (cur + ARRAY_SIZE (comp_list) - 1) % ARRAY_SIZE (comp_list);
+}
+
+void
+component_link (struct component *comp, struct component *ref, int before)
+{
+ if (!ref)
+ {
+ struct complist *list = &comp_list[comp->listidx];
+
+ comp->next = NULL;
+ comp->prev = list->tail;
+ if (list->tail)
+ list->tail->next = comp;
+ else
+ list->head = comp;
+ list->tail = comp;
+ }
+ else if (before)
+ component_link (comp, ref->prev, 0);
+ else
+ {
+ struct complist *list = &comp_list[comp->listidx];
+ struct component *x;
+
+ assert (comp->listidx == ref->listidx);
+
+ comp->prev = ref;
+
+ if ((x = ref->next))
+ x->prev = comp;
+ else
+ list->tail = comp;
+
+ ref->next = comp;
+ }
+}
+
+void
+component_unlink (struct component *comp)
+{
+ struct complist *list = &comp_list[comp->listidx];
+ struct component *x;
+
+ if ((x = comp->prev))
+ x->next = comp->next;
+ else
+ list->head = comp->next;
+ if ((x = comp->next))
+ x->prev = comp->prev;
+ else
+ list->tail = comp->prev;
+}
+
+struct component *
+component_lookup_tag (int idx, const char *tag)
+{
+ struct complist *list = &comp_list[idx];
+ struct component *comp;
+
+ for (comp = list->head; comp; comp = comp->next)
+ if (strcmp (comp->tag, tag) == 0)
+ break;
+
+ return comp;
+}
+
+ssize_t
+component_lookup_index (const char *tag)
+{
+ size_t i;
+
+ for (i = 0; i < comp_count; i++)
+ if (comp_array[i] && strcmp (comp_array[i]->tag, tag) == 0)
+ return i;
+ return -1;
+}
+
+struct component *
+component_create (const char *name)
+{
+ struct component *comp = component_lookup_tag (cur, name);
+ if (!comp)
+ {
+ comp = grecs_zalloc (sizeof (*comp));
+ comp->listidx = cur;
+ comp->facility = log_facility;
+ comp->redir[RETR_OUT].type = comp->redir[RETR_ERR].type = redir_null;
+ comp->tag = grecs_strdup (name);
+ comp->socket_type = SOCK_STREAM;
+ component_link (comp, NULL, 0);
+ }
+ return comp;
+}
+
+void
+component_free (struct component *comp)
+{
+ size_t i;
+
+ component_unlink (comp);
+ free (comp->tag);
+ free (comp->program);
+ if (comp->argv)
+ {
+ for (i = 0; i < comp->argc; i++)
+ free (comp->argv[i]);
+ free (comp->argv);
+ }
+ if (comp->env)
+ {
+ for (i = 0; comp->env[i]; i++)
+ free (comp->env[i]);
+ free (comp->env);
+ }
+ free (comp->dir);
+ grecs_list_free (comp->prereq);
+ grecs_list_free (comp->depend);
+ free (comp->rmfile);
+ pies_privs_free (&comp->privs);
+ free (comp->runlevels);
+ free_limits (comp->limits);
+ free (comp->runlevels);
+ free (comp->service);
+ pies_url_destroy (&comp->socket_url);
+ free (comp->pass_fd_socket);
+ free (comp->tcpmux);
+ free (comp->access_denied_message);
+ free (comp->max_instances_message);
+ free (comp->max_ip_connections_message);
+ free_redirector (&comp->redir[0]);
+ free_redirector (&comp->redir[1]);
+ grecs_list_free (comp->act_list);
+ pies_acl_free (comp->list_acl);
+ pies_acl_free (comp->adm_acl);
+ free (comp);
+}
+
+void
+component_ref_incr (struct component *comp)
+{
+ ++comp->ref_count;
+}
+
+void
+component_ref_decr (struct component *comp)
+{
+ assert (comp->ref_count > 0);
+ if (--comp->ref_count == 0)
+ component_free (comp);
+}
+
+static int
+argvcmp (char **a, char **b)
+{
+ size_t i;
+
+ if (!a != !b)
+ return 1;
+
+ for (i = 0; a[i]; i++)
+ if (!b[i] || strcmp (b[i], a[i]))
+ return 1;
+ return !!b[i];
+}
+
+static int
+urlcmp (struct pies_url *a, struct pies_url *b)
+{
+ if (!a)
+ return !!b;
+ else if (!b)
+ return 1;
+ return safe_strcmp (a->string, b->string);
+}
+
+static int
+redirector_cmp (struct redirector const *a, struct redirector const *b)
+{
+ if (a->type != b->type)
+ return 1;
+ switch (a->type)
+ {
+ case redir_null:
+ break;
+
+ case redir_syslog:
+ if (a->v.prio != b->v.prio)
+ return 1;
+ break;
+
+ case redir_file:
+ if (safe_strcmp (a->v.file, b->v.file))
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+component_match (struct component *comp, struct component *ref)
+{
+#define MATCH(cond) do if (cond) return 1; while (0)
+#define EQ(memb) MATCH (comp->memb != ref->memb)
+#define FN(memb,fun) MATCH (fun (comp->memb, ref->memb))
+#define FNP(memb,fun) MATCH (fun (&comp->memb, &ref->memb))
+
+ EQ (mode);
+ FN (tag, safe_strcmp);
+ FN (program, safe_strcmp);
+ EQ (argc);
+ FN (argv, argvcmp);
+ FN (dir, safe_strcmp);
+ FN (prereq, grecs_list_compare);
+ FN (depend, grecs_list_compare);
+ EQ (flags);
+ EQ (max_instances);
+ FN (rmfile, safe_strcmp);
+ FNP (privs, pies_privs_cmp);
+ FN (limits, limits_cmp);
+ FN (runlevels, safe_strcmp);
+ EQ (max_rate);
+ EQ (max_ip_connections);
+ EQ (socket_type);
+ EQ (builtin);
+ FN (service, safe_strcmp);
+ FN (socket_url, urlcmp);
+ FN (pass_fd_socket, safe_strcmp);
+ EQ (pass_fd_timeout);
+ FN (acl, pies_acl_cmp);
+ FN (tcpmux, safe_strcmp);
+ EQ (facility);
+ FNP (redir[0], redirector_cmp);
+ FNP (redir[1], redirector_cmp);
+#undef MATCH
+#undef EQ
+#undef FN
+#undef FNP
+
+ return 0;
+}
+
+static struct component *
+complist_find_match (int idx, struct component *ref)
+{
+ struct complist *list = &comp_list[idx];
+ struct component *comp;
+
+ for (comp = list->head; comp && component_match (comp, ref);
+ comp = comp->next)
+ ;
+ return comp;
+}
+
+static void
+strasgn (char **dst, char **src)
+{
+ free (*dst);
+ *dst = *src;
+ *src = NULL;
+}
+
+void
+component_merge (struct component *comp, struct component *ref)
+{
+ strasgn (&comp->tag, &ref->tag);
+
+ strasgn (&comp->access_denied_message, &ref->access_denied_message);
+ strasgn (&comp->max_instances_message, &ref->max_instances_message);
+ strasgn (&comp->max_ip_connections_message,
+ &ref->max_ip_connections_message);
+
+ grecs_list_free (comp->act_list);
+ comp->act_list = ref->act_list;
+ ref->act_list = NULL;
+
+ pies_acl_free (comp->list_acl);
+ comp->list_acl = ref->list_acl;
+ ref->list_acl = NULL;
+
+ pies_acl_free (comp->adm_acl);
+ comp->adm_acl = ref->adm_acl;
+ ref->adm_acl = NULL;
+}
+
+int
+component_is_active (struct component *comp)
+{
+ return comp->listidx == cur;
+}
+
+void
+component_config_begin (void)
+{
+ cur = next_index ();
+}
+
+void
+component_config_rollback (void)
+{
+ struct complist *list = &comp_list[cur];
+ while (list->head)
+ component_free (list->head);
+ cur = prev_index ();
+}
+
+static int
+cb_terminate_prog (struct prog *prog, void *data)
+{
+ if (IS_COMPONENT (prog) && !component_is_active (prog->v.p.comp))
+ {
+ progman_stop_component (prog);
+ prog->v.p.comp->flags |= CF_DISABLED;
+ }
+ return 0;
+}
+
+static int
+cb_kill_prog (struct prog *prog, void *data)
+{
+ if (!(IS_COMPONENT (prog) && component_is_active (prog->v.p.comp)))
+ prog_stop (prog, SIGKILL);
+ return 0;
+}
+
+static int
+list_is_empty (void *p)
+{
+ struct complist *list = p;
+ return list->head == NULL;
+}
+
+static int
+list_str_cmp (const void *a, const void *b)
+{
+ return safe_strcmp (a, b);
+}
+
+static void
+component_log_dep (size_t idx)
+{
+ pies_depmap_pos_t pos;
+ size_t n;
+
+ logmsg_printf (LOG_NOTICE, "%s -> ", comp_array[idx]->tag);
+ for (n = depmap_first (depmap, depmap_col, idx, &pos);
+ n != (size_t)-1;
+ n = depmap_next (depmap, pos))
+ {
+ logmsg_printf (LOG_NOTICE, "%s -> ", comp_array[n]->tag);
+ }
+ depmap_end (pos);
+ logmsg_printf (LOG_NOTICE, "%s\n", comp_array[idx]->tag);
+}
+
+void
+component_build_depmap (void)
+{
+ size_t i;
+ pies_depmap_t dp;
+
+ free (depmap);
+ depmap = depmap_alloc (comp_count);
+ for (i = 0; i < comp_count; i++)
+ {
+ struct component *comp = comp_array[i];
+ struct grecs_list_entry *ep;
+
+ if (comp->prereq)
+ for (ep = comp->prereq->head; ep; ep = ep->next)
+ {
+ char const *tag = ep->data;
+ ssize_t tgt = component_lookup_index (tag);
+ if (tgt < 0)
+ {
+ logmsg (LOG_ERR,
+ _("component %s depends on %s, "
+ "which is not declared"),
+ comp->tag, tag);
+ component_free (comp);
+ comp_array[i] = NULL;
+ depmap_clear_all (depmap, depmap_row, i);
+ depmap_clear_all (depmap, depmap_col, i);
+ continue;
+ }
+ depmap_set (depmap, i, tgt);
+ }
+
+ if (comp->depend)
+ for (ep = comp->depend->head; ep; ep = ep->next)
+ {
+ char const *tag = ep->data;
+ ssize_t tgt = component_lookup_index (tag);
+ if (tgt < 0)
+ {
+ logmsg (LOG_ERR,
+ _("undefined component %s depends on %s"),
+ tag, comp->tag);
+ continue;
+ }
+ depmap_set (depmap, tgt, i);
+ }
+ }
+
+ dp = depmap_copy (depmap);
+ depmap_tc (dp);
+ for (i = 0; i < comp_count; i++)
+ if (depmap_isset (dp, i, i))
+ {
+ logmsg (LOG_ERR, _("component %s depends on itself"),
+ comp_array[i]->tag);
+ component_log_dep (i);
+ component_free (comp_array[i]);
+ comp_array[i] = NULL;
+ depmap_clear_all (depmap, depmap_row, i);
+ depmap_clear_all (depmap, depmap_col, i);
+ continue;
+ }
+ free (dp);
+}
+
+void
+component_config_commit (void)
+{
+ struct complist *list = &comp_list[cur];
+ struct component *comp, *match;
+ int prev = prev_index ();
+ size_t i;
+
+ /* Count available components and allocate array for them */
+ for (comp = list->head, i = 0; comp; comp = comp->next, i++)
+ /* FIXME: component_compute_prereq (comp) */;
+
+ comp_array = grecs_realloc (comp_array, i * sizeof (comp_array[0]));
+ comp_count = i;
+
+ /* Rearrange components, registering prog entries for the new ones */
+ for (comp = list->head, i = 0; comp; comp = comp->next, i++)
+ {
+ match = complist_find_match (prev, comp);
+ if (match)
+ {
+ component_merge (match, comp);
+ component_unlink (match);
+ match->listidx = cur;
+ component_link (match, comp, 1);
+ component_free (comp);
+ comp = match;
+ }
+ comp_array[i] = comp;
+ comp->arridx = i;
+ }
+
+ /* Terminate orphaned progs */
+ list = &comp_list[prev];
+ if (list->head)
+ {
+ progman_foreach (cb_terminate_prog, NULL);
+ if (progman_wait_until (list_is_empty, list))
+ {
+ progman_foreach (cb_kill_prog, NULL);
+ progman_wait_until (list_is_empty, list);
+ }
+ }
+
+ /* Build dependency map */
+ component_build_depmap ();
+
+ /* Register new progs */
+ for (comp = comp_list[cur].head; comp; comp = comp->next)
+ if (!comp->prog)
+ register_prog (comp);
+}
+
+static int
+component_verify (struct component *comp, grecs_locus_t *locus)
+{
+ int header = 0;
+ int i;
+#define COMPERR(func, fmt, arg) \
+ do \
+ { \
+ if (!header) \
+ { \
+ grecs_warning (locus, 0, _("in component %s:"), comp->tag); \
+ header = 1; \
+ } \
+ func (locus, 0, fmt, arg); \
+ } \
+ while (0)
+
+ if (comp->flags & CF_INTERNAL)
+ {
+ comp->mode = pies_comp_inetd;
+ if (!comp->service)
+ /* TRANSLATORS: do not translate quoted words, they are keywords. */
+ COMPERR (grecs_error,
+ "%s", _("`internal' used without `service'"));
+ else
+ {
+ comp->builtin = inetd_builtin_lookup (comp->service,
+ comp->socket_type);
+ if (!comp->builtin)
+ COMPERR (grecs_error,
+ "%s", _("unknown internal service"));
+ if (comp->argv)
+ /* TRANSLATORS: do not translate quoted words, they are
+ keywords. */
+ COMPERR (grecs_error,
+ "%s", _("`internal' used with `command'"));
+ }
+ }
+ else if (!comp->argv)
+ COMPERR (grecs_error,
+ "%s", _("missing command line"));
+
+ if (ISCF_TCPMUX (comp->flags))
+ {
+ comp->mode = pies_comp_inetd;
+ if ((comp->flags & (CF_TCPMUX | CF_TCPMUXPLUS))
+ == (CF_TCPMUX | CF_TCPMUXPLUS))
+ COMPERR (grecs_error,
+ "%s", _("both `tcpmux' and `tcpmuxplus' used"));
+ else if (!comp->service)
+ /* TRANSLATORS: do not translate quoted words, they are keywords. */
+ COMPERR (grecs_error,
+ "%s", _("`internal' used without `service'"));
+ }
+
+ if (comp->pass_fd_socket && comp->mode != pies_comp_pass_fd)
+ COMPERR (grecs_error,
+ "%s", _("pass-fd-socket ignored: wrong mode"));
+ switch (comp->mode)
+ {
+ case pies_comp_exec:
+ if (comp->socket_url)
+ COMPERR (grecs_error,
+ "%s", _("socket ignored: wrong mode"));
+ break;
+
+ case pies_comp_pass_fd:
+ if (!comp->pass_fd_socket)
+ COMPERR (grecs_error,
+ "%s", _("must supply pass-fd-socket in this mode"));
+ else if (comp->pass_fd_socket[0] != '/')
+ {
+ if (comp->dir)
+ {
+ char *p = mkfilename (comp->dir, comp->pass_fd_socket, NULL);
+ /*free (comp->pass_fd_socket);*/
+ comp->pass_fd_socket = p;
+ }
+ else
+ COMPERR (grecs_error,
+ "%s", _("pass-fd-socket must be an absolute "
+ "file name or chdir must be specified"));
+ }
+ /* Fall through */
+
+ case pies_comp_accept:
+ if (!comp->socket_url)
+ {
+ COMPERR (grecs_error,
+ "%s", _("socket must be specified in this mode"));
+ return 1;
+ }
+ break;
+
+ case pies_comp_inetd:
+ if (ISCF_TCPMUX (comp->flags))
+ {
+ pies_url_destroy (&comp->socket_url);
+ if (!comp->tcpmux)
+ {
+ COMPERR (grecs_warning,
+ "%s",
+ _("TCPMUX master not specified, assuming \"tcpmux\""));
+ comp->tcpmux = grecs_strdup ("tcpmux");
+ }
+ }
+ else if (comp->tcpmux)
+ {
+ comp->flags |= CF_TCPMUX;
+ pies_url_destroy (&comp->socket_url);
+ }
+ else if (!comp->socket_url)
+ {
+ COMPERR (grecs_error,
+ "%s", _("socket must be specified in this mode"));
+ return 1;
+ }
+ default:
+ /* FIXME: more checks perhaps */
+ break;
+ }
+
+ if (comp->mode == pies_comp_inetd)
+ {
+ if ((comp->flags & CF_WAIT) && comp->socket_type == SOCK_STREAM)
+ {
+ if (comp->max_instances)
+ COMPERR (grecs_error, "%s", _("max-instances ignored"));
+ else
+ comp->max_instances = 1;
+ }
+ }
+ else if (comp->flags & CF_WAIT)
+ {
+ /* TRANSLATORS: `wait' is a keywords, do not translate. */
+ COMPERR (grecs_error, "%s", _("wait is useless in this mode"));
+ comp->flags &= ~CF_WAIT;
+ }
+
+ if (comp->mode != pies_comp_exec
+ && comp->redir[RETR_OUT].type != redir_null)
+ {
+ COMPERR (grecs_error,
+ "%s", _("stdout translation invalid in this mode"));
+ comp->redir[RETR_OUT].type = redir_null;
+ }
+
+ for (i = RETR_OUT; i <= RETR_ERR; i++)
+ {
+ if (comp->redir[i].type == redir_file
+ && comp->redir[i].v.file[0] != '/')
+ {
+ if (comp->dir)
+ {
+ char *p = mkfilename (comp->dir, comp->redir[i].v.file, NULL);
+ free (comp->redir[i].v.file);
+ comp->redir[i].v.file = p;
+ }
+ else
+ COMPERR (grecs_error,
+ _("%s: must be an absolute "
+ "file name or chdir must be specified"),
+ comp->redir[i].v.file);
+ }
+ }
+
+ return header;
+#undef COMPERR
+}
+
+void
+component_finish (struct component *comp, grecs_locus_t *locus)
+{
+ if (comp->prereq)
+ comp->prereq->cmp = list_str_cmp;
+ if (comp->depend)
+ comp->depend->cmp = list_str_cmp;
+ if (comp->privs.groups)
+ comp->privs.groups->cmp = list_str_cmp;
+
+ if (component_verify (comp, locus))
+ {
+ component_free (comp);
+ }
+ else
+ {
+ size_t n = grecs_list_size (comp->prereq);
+ if (n == 1)
+ {
+ const char *item = grecs_list_index (comp->prereq, 0);
+ if (strcmp (item, "all") == 0)
+ {
+ struct component *p;
+
+ grecs_list_clear (comp->prereq);
+ for (p = comp->prev; p; p = p->prev)
+ grecs_list_push (comp->prereq, grecs_strdup (comp->tag));
+ }
+ else if (strcmp (item, "none") == 0)
+ {
+ grecs_list_free (comp->prereq);
+ comp->prereq = NULL;
+ }
+ }
+ }
+}
+
+struct component *
+component_get (size_t n)
+{
+ if (n >= comp_count)
+ return NULL;
+ return comp_array[n];
+}
+
+void
+components_dump_depmap (void)
+{
+ size_t i, j;
+
+ printf ("%s:\n", _("Dependency map"));
+ printf (" ");
+ for (i = 0; i < comp_count; i++)
+ printf (" %2lu", (unsigned long)i);
+ printf ("\n");
+ for (i = 0; i < comp_count; i++)
+ {
+ printf ("%2lu ", (unsigned long)i);
+ for (j = 0; j < comp_count; j++)
+ printf (" %c ", depmap_isset (depmap, i, j) ? 'X' : ' ');
+ printf ("\n");
+ }
+ printf ("\n%s:\n", _("Legend"));
+ for (i = 0; i < comp_count; i++)
+ printf ("%2lu: %s\n", (unsigned long)i, comp_array[i]->tag);
+}
+
+void
+component_trace (size_t idx, enum pies_depmap_direction dir)
+{
+ pies_depmap_pos_t pos;
+ size_t n;
+ int delim = ':';
+
+ logmsg_printf (LOG_NOTICE, "%s", comp_array[idx]->tag);
+ for (n = depmap_first (depmap, dir, idx, &pos);
+ n != (size_t)-1;
+ n = depmap_next (depmap, pos))
+ {
+ logmsg_printf (LOG_NOTICE, "%c %s", delim, comp_array[n]->tag);
+ delim = ',';
+ }
+ depmap_end (pos);
+ logmsg_printf (LOG_NOTICE, "\n");
+}
+
+void
+components_trace (char **argv, enum pies_depmap_direction dir)
+{
+ if (*argv)
+ for (; *argv; ++argv)
+ {
+ ssize_t idx = component_lookup_index (*argv);
+ if (idx < 0)
+ logmsg (LOG_ERR, "%s: no such component", *argv);
+ else
+ component_trace (idx, dir);
+ }
+ else
+ {
+ size_t i;
+
+ for (i = 0; i < comp_count; i++)
+ component_trace (i, dir);
+ }
+}
+
+struct component *
+component_depmap_first (enum pies_depmap_direction dir, size_t idx,
+ pies_depmap_pos_t *ppos)
+{
+ size_t n = depmap_first (depmap, dir, idx, ppos);
+ if (n == (size_t)-1)
+ return NULL;
+ return comp_array[n];
+}
+
+struct component *
+component_depmap_next (pies_depmap_pos_t pos)
+{
+ size_t n = depmap_next (depmap, pos);
+ if (n == (size_t)-1)
+ return NULL;
+ return comp_array[n];
+}
+
+
+
+
+
diff --git a/src/ctl.c b/src/ctl.c
index 11ec7b4..d3e6b64 100644
--- a/src/ctl.c
+++ b/src/ctl.c
@@ -1540,13 +1540,13 @@ pcond_eval (struct pcond_node *node, struct prog *p)
return 1;
case pcond_false:
return 0;
case pcond_component:
- return strcmp (p->tag, node->v.tag) == 0;
+ return strcmp (prog_tag (p), node->v.tag) == 0;
case pcond_type:
return p->type == node->v.type;
case pcond_mode:
return IS_COMPONENT (p) && p->v.p.comp->mode == node->v.mode;
@@ -1789,13 +1789,13 @@ selector (struct prog *prog, void *data)
if (pcond_eval (env->cond, prog))
{
if (auth_prog (prog, env->io) & env->allowed_state)
{
struct json_value *status = json_new_object ();
- json_object_set_string (status, "tag", prog->tag);
+ json_object_set_string (status, "tag", prog_tag (prog));
if (env->fun (status, prog) == 0)
env->success_count++;
json_array_append (env->result, status);
env->total_count++;
}
else
diff --git a/src/depmap.c b/src/depmap.c
index e4533e8..3259880 100644
--- a/src/depmap.c
+++ b/src/depmap.c
@@ -20,13 +20,13 @@
# define CHAR_BIT 8
#endif
#define BITS_PER_WORD (sizeof(unsigned)*CHAR_BIT)
#define WORDSIZE(n) (((n) + BITS_PER_WORD - 1) / BITS_PER_WORD)
#define SETBIT(x, i) ((x)[(i)/BITS_PER_WORD] |= (1<<((i) % BITS_PER_WORD)))
-#define RESETBIT(x, i) ((x)[(i)/BITS_PER_WORD] &= ~(1<<((i) % BITS_PER_WORD)))
+#define CLRBIT(x, i) ((x)[(i)/BITS_PER_WORD] &= ~(1<<((i) % BITS_PER_WORD)))
#define BITISSET(x, i) (((x)[(i)/BITS_PER_WORD] & (1<<((i) % BITS_PER_WORD))) != 0)
void
TC (unsigned *R, int n)
{
register int rowsize;
@@ -115,12 +115,19 @@ void
depmap_set (pies_depmap_t dmap, size_t row, size_t col)
{
unsigned *rptr = depmap_rowptr (dmap, row);
SETBIT (rptr, col);
}
+void
+depmap_clear (pies_depmap_t dmap, size_t row, size_t col)
+{
+ unsigned *rptr = depmap_rowptr (dmap, row);
+ CLRBIT (rptr, col);
+}
+
int
depmap_isset (pies_depmap_t dmap, size_t row, size_t col)
{
unsigned *rptr = depmap_rowptr (dmap, row);
return BITISSET (rptr, col);
}
@@ -163,6 +170,25 @@ depmap_first (pies_depmap_t dmap, enum pies_depmap_direction dir,
void
depmap_end (pies_depmap_pos_t pos)
{
grecs_free (pos);
}
+
+void
+depmap_clear_all (pies_depmap_t dmap, enum pies_depmap_direction dir,
+ size_t coord)
+{
+ size_t i;
+
+ switch (dir)
+ {
+ case depmap_row:
+ for (i = 0; i < dmap->nrows; i++)
+ depmap_clear (dmap, coord, i);
+ break;
+
+ case depmap_col:
+ for (i = 0; i < dmap->nrows; i++)
+ depmap_clear (dmap, i, coord);
+ }
+}
diff --git a/src/inetd.c b/src/inetd.c
index 3eb4470..ee16078 100644
--- a/src/inetd.c
+++ b/src/inetd.c
@@ -278,13 +278,13 @@ inetd_conf_file (const char *file)
}
else
comp->flags = flags;
if (ISCF_TCPMUX (comp->flags))
comp->tcpmux = mktag (address, "tcpmux");
comp->service = grecs_strdup (service);
- comp->privs.user = grecs_strdup (user); /* FIXME: memory leak */
+ comp->privs.user = grecs_strdup (user);
if (group)
{
comp->privs.groups = grecs_list_create ();
comp->privs.groups->free_entry = listel_dispose;
grecs_list_append (comp->privs.groups, grecs_strdup (group));
}
@@ -303,15 +303,12 @@ inetd_conf_file (const char *file)
else
{
comp->argc = 1;
comp->argv = grecs_calloc (comp->argc + 1, sizeof (comp->argv[0]));
comp->argv[0] = grecs_strdup (comp->program);
}
-
- if (progman_lookup_component (comp->tag) == NULL)
- register_prog (comp);
}
if (wsflags & WRDSF_REUSE)
wordsplit_free (&ws);
free (dfl_address);
free (buf);
@@ -377,13 +374,13 @@ inetd_conf_dir (const char *name)
free (namebuf);
closedir (dir);
return errs;
}
int
-inetd_parse_conf (const char *file)
+inetd_config_parse (const char *file)
{
struct stat st;
if (stat (file, &st))
{
logmsg (LOG_ERR, _("cannot stat %s: %s"), file, strerror (errno));
diff --git a/src/limits.c b/src/limits.c
index a2c8ad9..7387b9d 100644
--- a/src/limits.c
+++ b/src/limits.c
@@ -301,7 +301,16 @@ void
free_limits (limits_record_t rec)
{
if (rec)
free (rec);
}
-
+int
+limits_cmp (limits_record_t a, limits_record_t b)
+{
+ if (!a)
+ return !!b;
+ else if (!b)
+ return 1;
+ return memcmp (a, b, sizeof (*a));
+}
+
diff --git a/src/pies.c b/src/pies.c
index 4a9ac9e..d3a9096 100644
--- a/src/pies.c
+++ b/src/pies.c
@@ -30,18 +30,19 @@ struct pies_privs pies_privs;
int foreground;
int init_process;
enum pies_command
{
COM_START,
- COM_RESTART,
+ COM_RESTART_COMPONENT,
COM_RELOAD,
COM_STATUS,
COM_STOP,
- COM_DUMP_PREREQ,
- COM_DUMP_DEPMAP
+ COM_DUMP_DEPMAP,
+ COM_TRACE_PREREQ,
+ COM_TRACE_DEPEND
};
enum pies_command command;
char *statedir = DEFAULT_STATE_DIR;
char *instance;
char *pidfile;
@@ -60,57 +61,62 @@ char **mailer_argv;
char *default_control_url[2] = {
DEFAULT_PIES_CONTROL_URL,
DEFAULT_INIT_CONTROL_URL
};
-struct config_file
+struct config_syntax
{
- enum config_syntax syntax;
- char *name;
+ const char *name;
+ int (*parser) (char const *);
};
-struct grecs_list *config_list;
+static int pies_config_parse (char const *);
-struct config_syntax_descr
-{
- const char *name;
- enum config_syntax type;
+static struct config_syntax config_syntax_tab[] = {
+ [CONF_PIES] = { "pies" , pies_config_parse },
+ [CONF_META1] = { "meta1", meta1_config_parse },
+ [CONF_INETD] = { "inetd", inetd_config_parse },
+ [CONF_INITTAB] = { "inittab", inittab_parse },
};
-static struct config_syntax_descr config_syntax_tab[] = {
- { "pies" , CONF_PIES },
- { "meta1", CONF_META1 },
- { "inetd", CONF_INETD },
- { "inittab", CONF_INITTAB },
- { NULL }
+struct config_file
+{
+ struct config_syntax *syntax;
+ char *name;
};
-int
-str_to_config_syntax (const char *str, enum config_syntax *psynt)
+struct grecs_list *config_list;
+
+struct config_syntax *
+str_to_config_syntax (const char *str)
{
- struct config_syntax_descr *p;
- for (p = config_syntax_tab; p->name; p++)
- if (strcmp (p->name, str) == 0)
- {
- *psynt = p->type;
- return 0;
- }
- return 1;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE (config_syntax_tab); i++)
+ if (strcmp (config_syntax_tab[i].name, str) == 0)
+ return &config_syntax_tab[i];
+ return NULL;
}
void
-add_config (enum config_syntax syntax, const char *name)
+config_file_add (struct config_syntax *syntax, const char *name)
{
struct config_file *file = grecs_malloc (sizeof (file[0]));
file->syntax = syntax;
file->name = grecs_strdup (name);
if (!config_list)
config_list = grecs_list_create ();
grecs_list_append (config_list, file);
}
+
+void
+config_file_add_type (enum config_syntax_type syntax, const char *name)
+{
+ config_file_add (&config_syntax_tab[syntax], name);
+}
/* Logging */
static int
stderr_closed_p ()
{
int fd = dup (0);
@@ -149,32 +155,32 @@ struct grecs_keyword return_code_keywords[] = {
{"action",
/* TRANSLATORS: disable and restart are keywords, do not translate them. */
N_("arg: {disable | restart}"),
N_("Specifies action to take when a component finishes with this "
"return code."),
grecs_type_string, GRECS_DFLT,
- NULL, offsetof (struct component, act_temp.act),
+ NULL, offsetof (struct action, act),
_cb_action,
},
{"notify",
N_("arg: emails"),
N_("Notify this address when a component terminates."),
grecs_type_string, GRECS_DFLT,
- NULL, offsetof (struct component, act_temp.addr)
+ NULL, offsetof (struct action, addr)
},
{"message",
NULL,
N_("Notification message text (with headers)."),
grecs_type_string, GRECS_DFLT,
- NULL, offsetof (struct component, act_temp.message),
+ NULL, offsetof (struct action, message),
NULL},
{"exec",
NULL,
N_("Execute this command."),
grecs_type_string, GRECS_DFLT,
- NULL, offsetof (struct component, act_temp.command),
+ NULL, offsetof (struct action, command),
NULL,
},
{NULL}
};
#define S(s) { #s, s }
@@ -257,30 +263,36 @@ static struct tokendef sig_tokendef[] = {
{NULL}
};
#undef S
void
-free_action (struct action *act)
+action_free (struct action *act)
{
if (!act)
return;
if (act->nstat > 0)
free (act->status);
free (act->addr);
free (act->message);
free (act->command);
free (act);
}
+static void
+free_entry_action (void *act)
+{
+ action_free (act);
+}
+
static struct action *
create_action (struct component *comp,
- grecs_locus_t *locus,
- grecs_value_t *val, int argc,
- const char *(*getarg) (grecs_value_t *, int, grecs_locus_t *))
+ grecs_locus_t *locus,
+ grecs_value_t *val, int argc,
+ const char *(*getarg) (grecs_value_t *, int, grecs_locus_t *))
{
int i;
unsigned *retv;
int retc = 0;
int allflag = 0;
struct action *act;
@@ -345,17 +357,18 @@ create_action (struct component *comp,
act = grecs_zalloc (sizeof *act);
if (!allflag)
{
act->nstat = retc;
act->status = retv;
}
- if (comp->act_tail)
- comp->act_tail->next = act;
- else
- comp->act_head = act;
- comp->act_tail = act;
+ if (!comp->act_list)
+ {
+ comp->act_list = grecs_list_create ();
+ comp->act_list->free_entry = free_entry_action;
+ }
+ grecs_list_append (comp->act_list, act);
return act;
}
const char *
_get_string_arg (grecs_value_t *val, int num, grecs_locus_t *locus)
{
@@ -420,24 +433,18 @@ return_code_section_parser (enum grecs_callback_command cmd,
break;
case GRECS_TYPE_LIST:
count = grecs_list_size (value->v.list);
act = create_action (comp, locus, value, count, _get_list_arg);
}
- *(struct component **) cb_data = comp;
if (!act)
return 1;
- memset (&comp->act_temp, 0, sizeof (comp->act_temp));
+ *(struct action **) cb_data = act;
break;
case grecs_callback_section_end:
- act = comp->act_tail;
- act->act = comp->act_temp.act;
- act->addr = comp->act_temp.addr;
- act->message = comp->act_temp.message;
- act->command = comp->act_temp.command;
break;
case grecs_callback_set_value:
grecs_error (locus, 0, _("invalid use of block statement"));
}
return 0;
@@ -916,18 +923,18 @@ _cb_runlevels (enum grecs_callback_command cmd,
if (assert_grecs_value_type (locus, value, GRECS_TYPE_STRING))
return 1;
for (p = value->v.string; *p; p++)
{
if (!is_valid_runlevel (*p))
- {
- grecs_error (locus, 0, _("not a valid runlevel: %c"), *p);
- return 1;
- }
+ {
+ grecs_error (locus, 0, _("not a valid runlevel: %c"), *p);
+ return 1;
+ }
}
- *sptr = grecs_strdup(value->v.string);
+ *sptr = grecs_strdup (value->v.string);
for (p = *sptr; *p; p++)
*p = toupper (*p);
return 0;
}
struct grecs_keyword component_keywords[] = {
@@ -1169,271 +1176,12 @@ find_component_keyword (const char *ident)
for (kwp = component_keywords; kwp->ident; kwp++)
if (strcmp (kwp->ident, ident) == 0)
return kwp;
return NULL;
}
-static char *
-make_full_name (const char *dir, const char *file)
-{
- char *p;
- size_t len = strlen (dir);
-
- while (len > 0 && dir[len - 1] == '/')
- len--;
- p = grecs_malloc (len + 1 + strlen (file) + 1);
- memcpy (p, dir, len);
- p[len++] = '/';
- strcpy (p + len, file);
- return p;
-}
-
-static int
-component_verify (struct component *comp, grecs_locus_t *locus)
-{
- int header = 0;
- int i;
-#define COMPERR(func, fmt, arg) \
- do \
- { \
- if (!header) \
- { \
- grecs_warning (locus, 0, _("in component %s:"), comp->tag); \
- header = 1; \
- } \
- func (locus, 0, fmt, arg); \
- } \
- while (0)
-
- if (comp->flags & CF_INTERNAL)
- {
- comp->mode = pies_comp_inetd;
- if (!comp->service)
- /* TRANSLATORS: do not translate quoted words, they are keywords. */
- COMPERR (grecs_error,
- "%s", _("`internal' used without `service'"));
- else
- {
- comp->builtin = inetd_builtin_lookup (comp->service,
- comp->socket_type);
- if (!comp->builtin)
- COMPERR (grecs_error,
- "%s", _("unknown internal service"));
- if (comp->argv)
- /* TRANSLATORS: do not translate quoted words, they are
- keywords. */
- COMPERR (grecs_error,
- "%s", _("`internal' used with `command'"));
- }
- }
- else if (!comp->argv)
- COMPERR (grecs_error,
- "%s", _("missing command line"));
-
- if (ISCF_TCPMUX (comp->flags))
- {
- comp->mode = pies_comp_inetd;
- if ((comp->flags & (CF_TCPMUX | CF_TCPMUXPLUS))
- == (CF_TCPMUX | CF_TCPMUXPLUS))
- COMPERR (grecs_error,
- "%s", _("both `tcpmux' and `tcpmuxplus' used"));
- else if (!comp->service)
- /* TRANSLATORS: do not translate quoted words, they are keywords. */
- COMPERR (grecs_error,
- "%s", _("`internal' used without `service'"));
- }
-
- if (comp->pass_fd_socket && comp->mode != pies_comp_pass_fd)
- COMPERR (grecs_error,
- "%s", _("pass-fd-socket ignored: wrong mode"));
- switch (comp->mode)
- {
- case pies_comp_exec:
- if (comp->socket_url)
- COMPERR (grecs_error,
- "%s", _("socket ignored: wrong mode"));
- break;
-
- case pies_comp_pass_fd:
- if (!comp->pass_fd_socket)
- COMPERR (grecs_error,
- "%s", _("must supply pass-fd-socket in this mode"));
- else if (comp->pass_fd_socket[0] != '/')
- {
- if (comp->dir)
- {
- char *p = make_full_name (comp->dir, comp->pass_fd_socket);
- /*free (comp->pass_fd_socket);*/
- comp->pass_fd_socket = p;
- }
- else
- COMPERR (grecs_error,
- "%s", _("pass-fd-socket must be an absolute "
- "file name or chdir must be specified"));
- }
- /* Fall through */
-
- case pies_comp_accept:
- if (!comp->socket_url)
- {
- COMPERR (grecs_error,
- "%s", _("socket must be specified in this mode"));
- return 1;
- }
- break;
-
- case pies_comp_inetd:
- if (ISCF_TCPMUX (comp->flags))
- {
- pies_url_destroy (&comp->socket_url);
- if (!comp->tcpmux)
- {
- COMPERR (grecs_warning,
- "%s",
- _("TCPMUX master not specified, assuming \"tcpmux\""));
- comp->tcpmux = grecs_strdup ("tcpmux");
- }
- }
- else if (comp->tcpmux)
- {
- comp->flags |= CF_TCPMUX;
- pies_url_destroy (&comp->socket_url);
- }
- else if (!comp->socket_url)
- {
- COMPERR (grecs_error,
- "%s", _("socket must be specified in this mode"));
- return 1;
- }
- default:
- /* FIXME: more checks perhaps */
- break;
- }
-
- if (comp->mode == pies_comp_inetd)
- {
- if ((comp->flags & CF_WAIT) && comp->socket_type == SOCK_STREAM)
- {
- if (comp->max_instances)
- COMPERR (grecs_error, "%s", _("max-instances ignored"));
- else
- comp->max_instances = 1;
- }
- }
- else if (comp->flags & CF_WAIT)
- {
- /* TRANSLATORS: `wait' is a keywords, do not translate. */
- COMPERR (grecs_error, "%s", _("wait is useless in this mode"));
- comp->flags &= ~CF_WAIT;
- }
-
- if (comp->mode != pies_comp_exec
- && comp->redir[RETR_OUT].type != redir_null)
- {
- COMPERR (grecs_error,
- "%s", _("stdout translation invalid in this mode"));
- comp->redir[RETR_OUT].type = redir_null;
- }
-
- for (i = RETR_OUT; i <= RETR_ERR; i++)
- {
- if (comp->redir[i].type == redir_file
- && comp->redir[i].v.file[0] != '/')
- {
- if (comp->dir)
- {
- char *p = make_full_name (comp->dir, comp->redir[i].v.file);
- free (comp->redir[i].v.file);
- comp->redir[i].v.file = p;
- }
- else
- COMPERR (grecs_error,
- _("%s: must be an absolute "
- "file name or chdir must be specified"),
- comp->redir[i].v.file);
- }
- }
-
- return header;
-#undef COMPERR
-}
-
-struct component *
-component_create (const char *name)
-{
- struct component *comp = progman_lookup_component (name);
- if (!comp)
- {
- comp = grecs_zalloc (sizeof (*comp));
- comp->facility = log_facility;
- comp->redir[RETR_OUT].type = comp->redir[RETR_ERR].type = redir_null;
- comp->tag = grecs_strdup (name);
- comp->socket_type = SOCK_STREAM;
- }
- return comp;
-}
-
-void
-component_free (struct component *comp)
-{
- size_t i;
-
- free (comp->tag);
- free (comp->program);
- if (comp->argv)
- {
- for (i = 0; i < comp->argc; i++)
- free (comp->argv[i]);
- free (comp->argv);
- }
- if (comp->env)
- {
- for (i = 0; comp->env[i]; i++)
- free (comp->env[i]);
- free (comp->env);
- }
- free (comp->dir);
- grecs_list_free (comp->prereq);
- grecs_list_free (comp->depend);
- free (comp->rmfile);
- free_limits (comp->limits);
- free (comp->runlevels);
- free (comp->service);
- pies_url_destroy (&comp->socket_url);
- free (comp->pass_fd_socket);
- free (comp->tcpmux);
- free (comp->access_denied_message);
- free (comp->max_instances_message);
- free (comp->max_ip_connections_message);
- free_redirector (&comp->redir[0]);
- free_redirector (&comp->redir[1]);
- if (comp->act_head)
- {
- struct action *act;
-
- for (act = comp->act_head; act; act = act->next)
- free_action (act);
- }
-
- free (comp);
-}
-
-void
-component_finish (struct component *comp, grecs_locus_t *locus)
-{
- if (component_verify (comp, locus) == 0)
- {
- /* FIXME: The prog list is traversed twice for each component
- statement, this is suboptimal. */
- if (progman_lookup_component (comp->tag) == NULL)
- register_prog (comp);
- }
- else
- component_free (comp);
-}
-
static int
component_section_parser (enum grecs_callback_command cmd,
grecs_locus_t *locus,
void *varptr, grecs_value_t *value, void *cb_data)
{
struct component *comp;
@@ -1540,13 +1288,13 @@ static int
_cb_include_inetd (enum grecs_callback_command cmd,
grecs_locus_t *locus,
void *varptr, grecs_value_t *value, void *cb_data)
{
if (assert_grecs_value_type (locus, value, GRECS_TYPE_STRING))
return 1;
- return inetd_parse_conf (value->v.string);
+ return inetd_config_parse (value->v.string);
}
struct grecs_keyword pies_keywords[] = {
{"component",
N_("tag: string"),
N_("Define a component"),
@@ -1719,43 +1467,35 @@ config_init ()
pies_identity_mechanism_register (&system_identity_mechanism);
#ifdef WITH_PAM
pies_identity_mechanism_register (&pam_identity_mechanism);
#endif
}
-static void
-config_error ()
-{
- if (!init_process)
- exit (EX_CONFIG);
-}
-
-void
-config_parse (char const *name)
+int
+pies_config_parse (char const *name)
{
struct grecs_node *node;
struct grecs_node *tree = grecs_parse (name);
if (!tree)
- {
- config_error ();
- return;
- }
+ return 1;
for (node = tree; node; node = node->next)
{
node = grecs_find_node (node, "identity-provider");
if (!node)
break;
pies_config_provider (node);
}
if (grecs_tree_process (tree, pies_keywords))
- config_error ();
+ return 1;
grecs_tree_free (tree);
+
+ return 0;
}
void
config_help ()
{
static char docstring[] =
@@ -1764,13 +1504,48 @@ config_help ()
"For more information, use `info pies configuration'.");
grecs_print_docstring (docstring, 0, stdout);
grecs_print_statement_array (pies_keywords, 1, 0, stdout);
pies_config_identity_mechanisms_help ();
}
-static enum config_syntax current_syntax = CONF_PIES;
+int
+pies_read_config (void)
+{
+ struct grecs_list_entry *ep;
+ int err = 0;
+
+ component_config_begin ();
+
+ for (ep = config_list->head; ep; ep = ep->next)
+ {
+ struct config_file *file = ep->data;
+ if (file->syntax->parser (file->name))
+ ++err;
+ }
+
+ if (err)
+ component_config_rollback ();
+
+ return err;
+}
+
+int
+pies_reload (void)
+{
+ int rc = pies_read_config ();
+ if (rc == 0)
+ {
+ component_config_commit ();
+ progman_create_sockets ();
+ progman_start ();
+ }
+
+ return rc;
+}
+
+static struct config_syntax *current_syntax = &config_syntax_tab[CONF_PIES];
#include "cmdline.h"
int action = ACTION_CONT;
int children_cleanup = 0;
@@ -1793,18 +1568,23 @@ sig_handler (int sig)
children_cleanup = 1;
break;
case SIGINT:
case SIGTERM:
case SIGQUIT:
- action = ACTION_STOP;
logmsg (LOG_NOTICE, "received signal %d", sig);
+ action = ACTION_STOP;
break;
case SIGHUP:
logmsg (LOG_NOTICE, "received signal %d", sig);
+ action = ACTION_RELOAD;
+ break;
+
+ case SIGUSR1:
+ logmsg (LOG_NOTICE, "received signal %d", sig);
action = ACTION_RESTART;
break;
case SIGALRM:
got_alarm = 1;
break;
@@ -1833,12 +1613,13 @@ setsigvhan (RETSIGTYPE (*handler) (int signo), int *sigv, int sigc)
static int default_sigv[] = {
SIGCHLD,
SIGTERM,
SIGQUIT,
SIGINT,
SIGHUP,
+ SIGUSR1,
SIGALRM,
SIGPIPE
};
static int extra_sigv[PIES_MAXSIG];
static int extra_sigc;
@@ -1931,13 +1712,13 @@ pies_check_status (pid_t *ppid)
return pies_status_running;
}
#define pies_control_url() control.url->string
-void
+int
request_restart_components (size_t cc, char **cv)
{
char **argv;
size_t i;
argv = grecs_calloc (cc + 4, sizeof (*argv));
@@ -1946,13 +1727,13 @@ request_restart_components (size_t cc, char **cv)
argv[2] = (char*) pies_control_url ();
for (i = 0; i < cc; i++)
argv[3 + i] = cv[i];
argv[3 + i] = NULL;
execvp (argv[0], argv);
logmsg (LOG_ERR, "can't run piesctl: %s", strerror (errno));
- exit (EX_OSFILE);
+ return EX_OSFILE;
}
void
list_components (void)
{
char *argv[5];
@@ -1966,13 +1747,13 @@ list_components (void)
logmsg (LOG_ERR, "can't run piesctl: %s", strerror (errno));
exit (EX_OSFILE);
}
int
-pies_reload ()
+request_reload ()
{
pid_t pid = pidfile_read (1);
if (pid == -1)
{
logmsg (LOG_CRIT, _("pies is not running"));
@@ -1981,13 +1762,13 @@ pies_reload ()
logmsg (LOG_INFO, _("reloading pies at PID %lu"), (unsigned long) pid);
return kill (pid, SIGHUP) ? EX_SOFTWARE : 0;
}
int
-pies_status ()
+request_status ()
{
pid_t pid;
switch (pies_check_status (&pid))
{
case pies_status_ctr:
@@ -2011,13 +1792,13 @@ pies_status ()
break;
}
return 0;
}
int
-pies_stop ()
+request_stop ()
{
pid_t pid = pidfile_read (1);
if (pid == -1)
{
logmsg (LOG_CRIT, _("pies is not running"));
@@ -2116,13 +1897,13 @@ set_mailer_argcv ()
static void
set_conf_file_names (const char *base)
{
if (!config_list)
{
char *name = mkfilename (SYSCONFDIR, base, ".conf");
- add_config (current_syntax, name);
+ config_file_add (current_syntax, name);
free (name);
}
}
static void
set_state_file_names (const char *base)
@@ -2193,27 +1974,28 @@ main (int argc, char **argv)
#ifdef INIT_EMU
char *emu = getenv ("INIT_EMU");
if (emu)
{
char *inittab = strtok (emu, ":");
char *piesinit = strtok (NULL, ":");
- add_config (CONF_INITTAB, inittab);
- add_config (CONF_PIES, piesinit ? piesinit : "/etc/pies.init");
+ config_file_add_type (CONF_INITTAB, inittab);
+ config_file_add_type (CONF_PIES,
+ piesinit ? piesinit : "/etc/pies.init");
init_fifo = getenv ("INIT_FIFO");
if (!init_fifo)
init_fifo = "/tmp/initctl";
}
else
{
- add_config (CONF_INITTAB, "/etc/inittab");
- add_config (CONF_PIES, "/etc/pies.init");
+ config_file_add_type (CONF_INITTAB, "/etc/inittab");
+ config_file_add_type (CONF_PIES, "/etc/pies.init");
}
#else
- add_config (CONF_INITTAB, "/etc/inittab");
- add_config (CONF_PIES, "/etc/pies.init");
+ config_file_add_type (CONF_INITTAB, "/etc/inittab");
+ config_file_add_type (CONF_PIES, "/etc/pies.init");
#endif
for (index = 1; index < argc; index++)
{
if (!strcmp (argv[index], "single") || !strcmp (argv[index], "-s"))
dfl_level = 'S';
else if (strchr("0123456789sS", argv[index][0]) && !argv[index][1])
@@ -2253,53 +2035,30 @@ main (int argc, char **argv)
if (file->syntax == CONF_PIES
&& grecs_preproc_run (file->name, grecs_preprocessor))
exit (EX_CONFIG);
}
exit (0);
}
- else
- for (ep = config_list->head; ep; ep = ep->next)
- {
- struct config_file *file = ep->data;
+ else if (pies_read_config ())
+ exit (EX_CONFIG);
- switch (file->syntax)
- {
- case CONF_PIES:
- config_parse (file->name);
- break;
-
- case CONF_INETD:
- if (inetd_parse_conf (file->name))
- config_error ();
- break;
-
- case CONF_META1:
- if (meta1_config_parse (file->name))
- config_error ();
- break;
-
- case CONF_INITTAB:
- if (inittab_parse (file->name))
- config_error ();
- break;
- }
- }
+ component_config_commit ();
set_state_file_names (instance);
set_mailer_argcv ();
if (lint_mode)
- {
- progman_build_depmap ();
- exit (0);
- }
+ exit (0);
/* Re-setup logging: it might have been reset in the config file */
diag_setup (log_to_stderr_only ? DIAG_TO_STDERR : 0);
- if (argc != index && command != COM_RESTART)
+ if (argc != index
+ && !(command == COM_RESTART_COMPONENT
+ || command == COM_TRACE_DEPEND
+ || command == COM_TRACE_PREREQ))
{
logmsg (LOG_ERR, "extra command line arguments");
exit (EX_CONFIG);
}
if (!control.url)
@@ -2311,38 +2070,41 @@ main (int argc, char **argv)
str, strerror (errno));
if (!init_process)
exit (EX_OSERR);
}
}
- progman_build_depmap ();
switch (command)
{
- case COM_RESTART:
+ case COM_RESTART_COMPONENT:
pies_priv_setup (&pies_privs);
if (pies_umask)
umask (pies_umask);
- request_restart_components (argc - index, argv + index);
+ exit (request_restart_components (argc - index, argv + index));
case COM_RELOAD:
- exit (pies_reload ());
+ exit (request_reload ());
case COM_STATUS:
- exit (pies_status ());
+ exit (request_status ());
case COM_STOP:
- exit (pies_stop ());
-
- case COM_DUMP_PREREQ:
- progman_dump_prereq ();
- exit (0);
+ exit (request_stop ());
case COM_DUMP_DEPMAP:
- progman_dump_depmap ();
+ components_dump_depmap ();
exit (0);
+ case COM_TRACE_DEPEND:
+ components_trace (argv + index, depmap_row);
+ exit (0);
+
+ case COM_TRACE_PREREQ:
+ components_trace (argv + index, depmap_col);
+ exit (0);
+
default:
pies_priv_setup (&pies_privs);
if (pies_umask)
umask (pies_umask);
}
@@ -2395,13 +2157,13 @@ main (int argc, char **argv)
create_pidfile (pidfile);
}
if (argv[0][0] != '/')
logmsg (LOG_NOTICE,
_("not started as an absolute pathname; "
- "SIGHUP will not work"));
+ "restart will not work"));
signal_setup (sig_handler);
progman_create_sockets ();
progman_start ();
@@ -2421,12 +2183,17 @@ main (int argc, char **argv)
{
logmsg (LOG_INFO, _("restart command ignored"));
action = ACTION_CONT;
}
break;
+ case ACTION_RELOAD:
+ pies_reload ();
+ action = ACTION_CONT;
+ break;
+
case ACTION_STOP:
if (init_process)
{
debug (1, ("ignoring stop/restart"));
action = ACTION_CONT;
}
diff --git a/src/pies.h b/src/pies.h
index e0d24d2..ad8e8ee 100644
--- a/src/pies.h
+++ b/src/pies.h
@@ -95,13 +95,12 @@ enum return_action
#define STATUS_SIG_BIT 0x80000000
#define STATUS_CODE(c) ((c) & ~STATUS_SIG_BIT)
struct action
{
- struct action *next;
size_t nstat;
unsigned *status;
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 */
@@ -199,14 +198,22 @@ enum pies_comp_mode
#define CF_SIGGROUP 0x100 /* Send signals to the process group */
#define CF_NULLINPUT 0x200 /* Provide null input stream */
#define ISCF_TCPMUX(f) ((f) & (CF_TCPMUX | CF_TCPMUXPLUS))
+struct prog;
+
struct component
{
+ struct component *prev, *next; /* Components form doubly-linked list. */
+ int listidx; /* Index of the list. */
+ size_t arridx; /* Index of this component. */
+ size_t ref_count; /* Reference count. */
+ struct prog *prog; /* Prog associated with this component. */
+
enum pies_comp_mode mode;
char *tag; /* Entry tag (for diagnostics purposes) */
char *program; /* Program name */
size_t argc; /* Number of command line arguments */
char **argv; /* Program command line */
char **env; /* Program environment */
@@ -214,13 +221,13 @@ struct component
struct grecs_list *prereq; /* Prerequisites */
struct grecs_list *depend; /* Dependency targets */
int flags; /* CF_ bitmask */
size_t max_instances; /* Maximum number of simultaneously running
instances */
char *rmfile; /* Try to remove this file before starting */
- struct pies_privs privs; /* UID/GIDS+groups to run under */
+ struct pies_privs privs; /* UID/GIDS+groups to run as */
mode_t umask; /* Umask to install before starting */
limits_record_t limits; /* System limits */
/* For exec (init) components */
char *runlevels;
@@ -246,25 +253,25 @@ struct component
char *max_ip_connections_message;
/* Redirectors: */
int facility; /* Syslog facility. */
struct redirector redir[2]; /* Repeaters for stdout and stderr */
/* Actions to execute on various exit codes: */
- struct action *act_head, *act_tail;
- struct action act_temp; /* Auxiliary object used during configuration */
+ struct grecs_list *act_list;
/* ACLs for control interface */
pies_acl_t list_acl; /* List access control list */
pies_acl_t adm_acl; /* Administrative ACL (stop, start, etc.) */
};
#define is_sysvinit(cp) ((cp)->mode >= pies_mark_sysvinit || (cp)->runlevels)
enum pies_action {
ACTION_CONT,
ACTION_STOP,
ACTION_RESTART,
+ ACTION_RELOAD,
ACTION_CTRLALTDEL,
ACTION_KBREQUEST
};
extern char *instance;
extern char *log_tag;
@@ -286,41 +293,44 @@ extern int initdefault;
extern int dfl_level;
extern size_t pies_master_argc;
extern char **pies_master_argv;
extern char *default_control_url[2];
-enum config_syntax
+enum config_syntax_type
{
CONF_PIES,
CONF_META1,
CONF_INETD,
CONF_INITTAB
};
-int str_to_config_syntax (const char *str, enum config_syntax *psynt);
-void add_config (enum config_syntax syntax, const char *name);
+struct config_syntax;
+
+struct config_syntax *str_to_config_syntax (const char *str);
+void config_file_add (struct config_syntax *syntax, const char *name);
+void config_file_add_type (enum config_syntax_type syntax, const char *name);
void free_redirector (struct redirector *rp);
void pies_schedule_action (int act);
+void free_action (struct action *act);
void register_prog (struct component *comp);
int progman_running_p (void);
size_t progman_running_count (void);
void progman_start (void);
void progman_wake_sleeping (int);
void progman_stop (void);
void progman_cleanup (int expect_term);
void progman_filter (int (*filter) (struct component *, void *data),
void *data);
+int progman_wait_until (int (*cond) (void *), void *data);
void progman_stop_tag (const char *name);
-void progman_dump_prereq (void);
-void progman_dump_depmap (void);
int progman_accept (int socket, void *data);
-int progman_build_depmap (void);
+
void progman_create_sockets (void);
struct component *progman_lookup_component (const char *tag);
struct component *progman_lookup_tcpmux (const char *service,
const char *master);
void progman_run_comp (struct component *comp, int fd,
@@ -348,12 +358,17 @@ enum pies_depmap_direction
};
pies_depmap_t depmap_alloc (size_t count);
pies_depmap_t depmap_copy (pies_depmap_t dpm);
void depmap_set (pies_depmap_t dmap, size_t row, size_t col);
int depmap_isset (pies_depmap_t dmap, size_t row, size_t col);
+void depmap_clear (pies_depmap_t dmap, size_t row, size_t col);
+
+void depmap_clear_all (pies_depmap_t dmap, enum pies_depmap_direction dir,
+ size_t coord);
+
void depmap_tc (pies_depmap_t dmap);
size_t depmap_first (pies_depmap_t dmap, enum pies_depmap_direction dir,
size_t coord, pies_depmap_pos_t *ppos);
size_t depmap_next (pies_depmap_t dmap, pies_depmap_pos_t pos);
void depmap_end (pies_depmap_pos_t pos);
@@ -362,16 +377,31 @@ int assert_grecs_value_type (grecs_locus_t *locus,
int str_to_socket_type (const char *str, int *pret);
int socket_type_to_str (int socket_type, const char **pres);
struct component *component_create (const char *name);
void component_free (struct component *comp);
+void component_ref_incr (struct component *comp);
+void component_ref_decr (struct component *comp);
+
+void component_config_begin (void);
+void component_config_rollback (void);
+void component_config_commit (void);
+
+int component_is_active (struct component *comp);
void component_finish (struct component *comp, grecs_locus_t *locus);
struct grecs_keyword *find_component_keyword (const char *ident);
+void components_dump_depmap (void);
+void components_trace (char **argv, enum pies_depmap_direction dir);
+
+struct component *component_depmap_first (enum pies_depmap_direction dir,
+ size_t idx, pies_depmap_pos_t *ppos);
+struct component *component_depmap_next (pies_depmap_pos_t pos);
+
void pies_pause (void);
enum
{
@@ -398,12 +428,13 @@ void disable_socket (int fd);
void enable_socket (int fd);
int parse_limits (limits_record_t *plrec, char *str, char **endp);
int set_limits (const char *name, limits_record_t lrec);
void free_limits (limits_record_t rec);
+int limits_cmp (limits_record_t a, limits_record_t b);
void meta1_parser_set_debug (void);
int meta1lex (void);
int meta1error (char const *s);
int meta1parse (void);
@@ -448,15 +479,19 @@ void debug_msg (const char *fmt, ...) PIES_PRINTFLIKE(1,2);
/* userprivs.c */
int switch_to_privs (uid_t uid, gid_t gid, struct grecs_list *retain_groups);
void pies_priv_setup (struct pies_privs *);
void pies_epriv_setup (struct pies_privs *);
+
+int pies_privs_cmp (struct pies_privs const *a, struct pies_privs const *b);
+void pies_privs_free (struct pies_privs *p);
+
/* inetd.c */
-int inetd_parse_conf (const char *file);
+int inetd_config_parse (const char *file);
/* inetd-bi.c */
struct inetd_builtin
{
const char *service;
int socktype;
diff --git a/src/prog.h b/src/prog.h
index 6590d4e..a29de04 100644
--- a/src/prog.h
+++ b/src/prog.h
@@ -43,48 +43,49 @@ struct conn_class
struct prog
{
struct prog *next, *prev;
enum prog_type type;
pid_t pid; /* PID */
- char *tag; /* Entry tag (for diagnostics purposes) */
- char **prereq;
int facility;
union
{
struct
{
struct component *comp;
size_t idx; /* Numeric identifier */
int socket;
struct prog *redir[2]; /* Pointers to redirectors */
time_t timestamp; /* Time of last startup */
size_t failcount; /* Number of failed starts since timestamp */
enum prog_status status; /* Current component status */
- char *runlevels;
/* If status == status_listener: */
size_t num_instances; /* Number of running instances */
/* If comp->type == pies_comp_inetd && status == status_enabled */
struct prog *listener;
union pies_sockaddr_storage sa_storage;
size_t sa_len;
struct conn_class *cclass;
} p;
struct
{
+ char *tag;
struct prog *master;
} r;
struct
{
+ char *tag;
char *command;
} c;
} v;
};
#define IS_COMPONENT(p) ((p)->type == TYPE_COMPONENT)
struct prog *progman_locate (const char *name);
void progman_foreach (int (*filter) (struct prog *, void *data), void *data);
void prog_stop (struct prog *prog, int sig);
void progman_stop_component (struct prog *prog);
+
+char const *prog_tag (struct prog const *prog);
diff --git a/src/progman.c b/src/progman.c
index 0079149..4f63d9a 100644
--- a/src/progman.c
+++ b/src/progman.c
@@ -14,25 +14,23 @@
You should have received a copy of the GNU General Public License
along with GNU Pies. If not, see <http://www.gnu.org/licenses/>. */
#include "pies.h"
#include "prog.h"
-static size_t numcomp;
static struct prog *proghead, *progtail;
-static pies_depmap_t depmap;
static int recompute_alarm;
static struct grecs_symtab *conn_tab;
struct prog *
progman_locate (const char *name)
{
struct prog *prog;
for (prog = proghead; prog; prog = prog->next)
- if (strcmp (prog->tag, name) == 0)
+ if (strcmp (prog_tag (prog), name) == 0)
break;
return prog;
}
void
progman_foreach (int (*filter) (struct prog *, void *data), void *data)
@@ -70,13 +68,13 @@ prog_lookup_by_pid (pid_t pid)
struct prog *
prog_lookup_by_tag (const char *tag)
{
struct prog *prog;
for (prog = proghead; prog; prog = prog->next)
- if (strcmp (prog->tag, tag) == 0)
+ if (strcmp (prog_tag (prog), tag) == 0)
break;
return prog;
}
struct prog *
prog_lookup_by_service (const char *service)
@@ -92,13 +90,13 @@ prog_lookup_by_service (const char *service)
struct component *
progman_lookup_component (const char *tag)
{
struct prog *prog;
for (prog = proghead; prog; prog = prog->next)
- if (IS_COMPONENT (prog) && strcmp (prog->tag, tag) == 0)
+ if (IS_COMPONENT (prog) && strcmp (prog_tag (prog), tag) == 0)
return prog->v.p.comp;
return NULL;
}
struct component *
progman_lookup_tcpmux (const char *service, const char *master)
@@ -126,12 +124,29 @@ prog_lookup_by_idx (unsigned idx)
return prog;
}
void prog_stop (struct prog *prog, int sig);
static int prog_start_prerequisites (struct prog *prog);
+char const *
+prog_tag (struct prog const *prog)
+{
+ switch (prog->type)
+ {
+ case TYPE_COMPONENT:
+ return prog->v.p.comp->tag;
+
+ case TYPE_REDIRECTOR:
+ return prog->v.r.tag;
+
+ case TYPE_COMMAND:
+ return prog->v.c.tag;
+ }
+ abort ();
+ }
+
void
link_prog (struct prog *pp, int prepend)
{
if (prepend)
{
if (proghead)
@@ -155,12 +170,13 @@ link_prog (struct prog *pp, int prepend)
}
void
unlink_prog (struct prog *pp)
{
struct prog *x;
+
if ((x = pp->prev))
x->next = pp->next;
else
proghead = pp->next;
if ((x = pp->next))
x->prev = pp->prev;
@@ -169,69 +185,69 @@ unlink_prog (struct prog *pp)
}
void
destroy_prog (struct prog **pp)
{
struct prog *p = *pp;
+
+ unlink_prog (p);
switch (p->type)
{
case TYPE_COMPONENT:
+ component_ref_decr (p->v.p.comp);
+ if (p->v.p.status == status_listener)
+ deregister_socket (p->v.p.socket);
break;
-
+
case TYPE_REDIRECTOR:
{
struct prog *master = p->v.r.master;
+ component_ref_decr (master->v.p.comp);
if (p == master->v.p.redir[0])
master->v.p.redir[0] = NULL;
else if (p == master->v.p.redir[1])
master->v.p.redir[1] = NULL;
/* else
logmsg (LOG_NOTICE, _("orphan redirector: %s"), p->tag);*/
+ free (p->v.r.tag);
}
break;
-
+
case TYPE_COMMAND:
+ free (p->v.c.tag);
free (p->v.c.command);
}
- unlink_prog (*pp);
- free (*pp);
+ free (p);
*pp = NULL;
}
static char *
redir_tag (struct prog *master, int type)
{
static char *redirstr[2] = { "stdout", "stderr" };
char *str = NULL;
size_t len = 0;
+ char const *tag = prog_tag (master);
if (type < ARRAY_SIZE(redirstr))
- grecs_asprintf (&str, &len, "%s/%s", master->tag, redirstr[type]);
+ grecs_asprintf (&str, &len, "%s/%s", tag, redirstr[type]);
else
- grecs_asprintf (&str, &len, "%s/%d", master->tag, type);
+ grecs_asprintf (&str, &len, "%s/%d", tag, type);
return str;
}
static struct prog *
register_redir (int type, struct prog *master)
{
char *tag = redir_tag (master, type);
- char *pstr;
- struct prog *pp = grecs_zalloc (sizeof (*pp) + strlen (tag) + 1 +
- 2 * sizeof (char**));
+ struct prog *pp = grecs_zalloc (sizeof (*pp));
pp->type = TYPE_REDIRECTOR;
- pstr = (char *) (pp + 1);
- pp->tag = pstr;
- strcpy (pp->tag, tag);
- pstr += strlen (pp->tag) + 1;
- free (tag);
+ pp->v.r.tag = tag;
pp->v.r.master = master;
- pp->prereq = (char**)pstr;
- pp->prereq[0] = master->tag;
- pp->prereq[1] = NULL;
link_prog (pp, 1);
+ component_ref_incr (master->v.p.comp);
return pp;
}
void
update_redir (int type, struct prog *master, pid_t pid)
{
@@ -245,107 +261,52 @@ update_redir (int type, struct prog *master, pid_t pid)
pp = register_redir (type, master);
master->v.p.redir[type] = pp;
pp->pid = pid;
}
static struct prog *
-register_prog0 (struct component *comp, unsigned index)
+register_prog0 (struct component *comp)
{
struct prog *newp;
newp = grecs_zalloc (sizeof (*newp));
newp->type = TYPE_COMPONENT;
- newp->tag = comp->tag;
newp->pid = 0;
newp->facility = comp->facility;
newp->v.p.comp = comp;
- newp->v.p.idx = index;
newp->v.p.socket = -1;
if (comp->flags & CF_DISABLED)
newp->v.p.status = status_disabled;
else if (comp->mode == pies_comp_inetd)
newp->v.p.status = status_listener;
if (comp->mode != pies_comp_exec)
comp->redir[RETR_OUT].type = redir_null;
link_prog (newp, 0);
+ component_ref_incr (comp);
return newp;
}
void
register_prog (struct component *comp)
{
- register_prog0 (comp, numcomp++);
+ comp->prog = register_prog0 (comp);
}
void
register_command (char *tag, char *command, pid_t pid)
{
struct prog *newp = grecs_zalloc (sizeof (*newp));
newp->type = TYPE_COMMAND;
- newp->tag = tag;
newp->pid = pid;
+ newp->v.c.tag = grecs_strdup (tag);
newp->v.c.command = command;
link_prog (newp, 0);
}
-void
-prog_rebuild_prerequisites (struct prog *prog)
-{
- struct component *comp = prog->v.p.comp;
- struct prog *p;
- int dep_all = 0;
- size_t depc = 0;
-
- if (comp->prereq)
- {
- depc = grecs_list_size (comp->prereq);
- if (depc == 1)
- {
- const char *item = grecs_list_index (comp->prereq, 0);
- if (strcmp (item, "all") == 0)
- {
- dep_all = 1;
- for (p = proghead; p; p = p->next)
- if (p->type == TYPE_COMPONENT)
- depc++;
- }
- else if (strcmp (item, "none") == 0)
- {
- grecs_list_free (comp->prereq);
- comp->prereq = NULL;
- }
- }
- }
-
- if (depc == 0)
- return;
-
- prog->prereq = grecs_calloc (depc + 1, sizeof (prog->prereq[0]));
-
- depc = 0;
- if (comp->prereq)
- {
- if (dep_all)
- {
- for (p = proghead; p; p = p->next)
- if (p->type == TYPE_COMPONENT)
- prog->prereq[depc++] = p->tag;
- }
- else
- {
- struct grecs_list_entry *ep;
-
- for (ep = comp->prereq->head; ep; ep = ep->next)
- prog->prereq[depc++] = (char*) ep->data;
- }
- }
- prog->prereq[depc] = NULL;
-}
-
int
progman_running_p ()
{
struct prog *prog;
for (prog = proghead; prog; prog = prog->next)
@@ -470,27 +431,27 @@ open_redirector (struct prog *master, int stream)
signal_setup (redir_exit);
close (p[1]);
fp = fdopen (p[0], "r");
if (fp == NULL)
_exit (1);
- openlog (master->tag, LOG_PID, master->facility);
+ openlog (prog_tag (master), LOG_PID, master->facility);
prio = master->v.p.comp->redir[stream].v.prio;
while (getline (&buf, &size, fp) > 0)
syslog (prio, "%s", buf);
_exit (0);
case -1:
logmsg (LOG_CRIT,
_("cannot run redirector `%s': fork failed: %s"),
- master->tag, strerror (errno));
+ prog_tag (master), strerror (errno));
return -1;
default:
debug (1, (_("redirector for %s started, pid=%lu"),
- master->tag, (unsigned long) pid));
+ prog_tag (master), (unsigned long) pid));
update_redir (stream, master, pid);
close (p[0]);
return p[1];
}
}
@@ -953,13 +914,13 @@ check_spawn_rate (struct prog *prog)
if (check_rate (prog, TESTTIME, MAXSPAWN))
{
logmsg (LOG_NOTICE,
ngettext ("%s is respawning too fast, disabled for %d minute",
"%s is respawning too fast, disabled for %d minutes",
SLEEPTIME / 60),
- prog->tag, SLEEPTIME / 60);
+ prog_tag (prog), SLEEPTIME / 60);
return 1;
}
return 0;
}
static int
@@ -970,13 +931,13 @@ check_connection_rate (struct prog *prog)
if (max_rate && check_rate (prog, 60, max_rate))
{
logmsg (LOG_NOTICE,
ngettext ("%s is starting too often, disabled for %d minute",
"%s is starting too often, disabled for %d minutes",
SLEEPTIME / 60),
- prog->tag, SLEEPTIME / 60);
+ prog_tag (prog), SLEEPTIME / 60);
return 1;
}
return 0;
}
@@ -1008,13 +969,13 @@ prog_start_prologue (struct prog *prog)
{
if (prog->v.p.comp->dir)
{
debug (1, (_("chdir %s"), prog->v.p.comp->dir));
if (chdir (prog->v.p.comp->dir))
logmsg (LOG_ERR, _("%s: cannot change to directory %s: %s"),
- prog->tag, prog->v.p.comp->dir, strerror (errno));
+ 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));
if (init_process)
@@ -1022,13 +983,13 @@ prog_start_prologue (struct prog *prog)
DEBUG_ENVIRON (4);
pies_priv_setup (&prog->v.p.comp->privs);
if (prog->v.p.comp->umask)
umask (prog->v.p.comp->umask);
- set_limits (prog->tag,
+ set_limits (prog_tag (prog),
prog->v.p.comp->limits ?
prog->v.p.comp->limits : pies_limits);
if (debug_level >= 1)
{
int i;
@@ -1054,22 +1015,22 @@ prog_execute (struct prog *prog)
}
execvp (prog->v.p.comp->program ?
prog->v.p.comp->program : prog->v.p.comp->argv[0],
prog->v.p.comp->argv);
openlog (log_tag, LOG_PID, prog->v.p.comp->facility);
- syslog (LOG_CRIT, _("cannot start `%s': %s"), prog->tag,
+ syslog (LOG_CRIT, _("cannot start `%s': %s"), prog_tag (prog),
strerror (errno));
_exit (EX_SOFTWARE);
}
void
progman_run_comp (struct component *comp, int fd,
union pies_sockaddr_storage *sa, socklen_t salen)
{
- struct prog *prog = register_prog0 (comp, -1);
+ struct prog *prog = register_prog0 (comp);
prog->v.p.socket = fd;
prog->v.p.sa_storage = *sa;
prog->v.p.sa_len = salen;
prog->v.p.cclass = conn_class_lookup (comp->tag, sa, salen);
prog_start_prologue (prog);
prog_sockenv (prog);
@@ -1090,13 +1051,13 @@ prog_start (struct prog *prog)
{
if (!init_process)
{
if (prog->v.p.status != status_disabled)
{
logmsg (LOG_NOTICE, "disabling sysvinit component %s",
- prog->tag);
+ prog_tag (prog));
prog->v.p.status = status_disabled;
}
return;
}
debug (1, ("ok to start %s", prog->v.p.comp->tag));
}
@@ -1144,20 +1105,20 @@ prog_start (struct prog *prog)
return;
default:
break;
}
- debug (1, (_("starting %s"), prog->tag));
+ debug (1, (_("starting %s"), prog_tag (prog)));
if (prog->v.p.comp->rmfile)
{
debug (1, (_("unlinking %s"), prog->v.p.comp->rmfile));
if (unlink (prog->v.p.comp->rmfile) && errno != ENOENT)
logmsg (LOG_ERR, _("%s: cannot remove file `%s': %s"),
- prog->tag, prog->v.p.comp->rmfile, strerror (errno));
+ prog_tag (prog), prog->v.p.comp->rmfile, strerror (errno));
}
if (prog->v.p.comp->builtin && prog->v.p.comp->builtin->single_process)
{
prog->v.p.comp->builtin->fun (prog->v.p.socket, prog->v.p.comp);
return;
@@ -1256,13 +1217,13 @@ prog_start (struct prog *prog)
prog_execute (prog);
case -1:
logmsg (LOG_CRIT,
_("cannot run `%s': fork failed: %s"),
- prog->tag, strerror (errno));
+ prog_tag (prog), strerror (errno));
break;
default:
if (prog->v.p.comp->mode == pies_comp_pass_fd)
{
pass_fd (prog->v.p.comp->pass_fd_socket, prog->v.p.socket,
@@ -1276,21 +1237,22 @@ prog_start (struct prog *prog)
}
else if (prog->v.p.comp->mode == pies_comp_accept ||
prog->v.p.comp->mode == pies_comp_inetd ||
prog->v.p.comp->mode == pies_comp_pass_fd)
close (prog->v.p.socket);
else if (is_sysvinit (prog->v.p.comp))
- sysvinit_acct (SYSV_ACCT_PROC_START, "", prog->tag, pid, "");
+ sysvinit_acct (SYSV_ACCT_PROC_START, "", prog_tag (prog), pid, "");
if (redir[RETR_OUT] != -1)
close (redir[RETR_OUT]);
if (redir[RETR_ERR])
close (redir[RETR_ERR]);
prog->pid = pid;
prog->v.p.status = status_enabled;
- debug (1, (_("%s started, pid=%lu"), prog->tag, (unsigned long) pid));
+ debug (1, (_("%s started, pid=%lu"), prog_tag (prog),
+ (unsigned long) pid));
}
}
int
check_acl (pies_acl_t acl, struct sockaddr *s, socklen_t salen,
pies_identity_t identity)
@@ -1358,13 +1320,13 @@ _prog_accept (struct prog *p)
return 1;
}
if (debug_level >= 1)
{
char *s = sockaddr_to_astr ((struct sockaddr *)&addr, addrlen);
- logmsg (LOG_DEBUG, _("%s wants %s"), s, p->tag);
+ logmsg (LOG_DEBUG, _("%s wants %s"), s, prog_tag (p));
free (s);
}
if (check_acl (p->v.p.comp->acl, (struct sockaddr *)&addr, addrlen, NULL)
|| check_acl (pies_acl, (struct sockaddr *)&addr, addrlen, NULL))
{
@@ -1376,28 +1338,28 @@ _prog_accept (struct prog *p)
if (p->v.p.comp->max_instances &&
p->v.p.num_instances >= p->v.p.comp->max_instances)
{
char *s = sockaddr_to_astr ((struct sockaddr *)&addr, addrlen);
logmsg (LOG_ERR,
_("%s: access from %s denied: too many instances running"),
- p->tag, s);
+ prog_tag (p), s);
free (s);
fd_report (fd, p->v.p.comp->max_instances_message);
close (fd);
return 1;
}
- pcclass = conn_class_lookup (p->tag, &addr, addrlen);
+ pcclass = conn_class_lookup (prog_tag (p), &addr, addrlen);
if (p->v.p.comp->max_ip_connections &&
pcclass->count >= p->v.p.comp->max_ip_connections)
{
char *s = sockaddr_to_astr ((struct sockaddr *)&addr, addrlen);
logmsg (LOG_ERR,
_("%s: access from %s denied: "
"too many connections from that ip"),
- p->tag, s);
+ prog_tag (p), s);
free (s);
fd_report (fd, p->v.p.comp->max_ip_connections_message);
close (fd);
return 1;
}
@@ -1410,13 +1372,13 @@ _prog_accept (struct prog *p)
pcclass->count++;
if (debug_level > 1)
conn_class_report (LOG_DEBUG, pcclass);
- pinst = register_prog0 (p->v.p.comp, -1);
+ pinst = register_prog0 (p->v.p.comp);
pinst->v.p.socket = fd;
pinst->v.p.listener = p;
pinst->v.p.sa_storage = addr;
pinst->v.p.sa_len = addrlen;
pinst->v.p.cclass = pcclass;
prog_start (pinst);
@@ -1429,24 +1391,24 @@ _prog_accept (struct prog *p)
static int
_prog_wait (struct prog *p)
{
struct prog *pinst;
- debug (1, (_("someone wants %s"), p->tag));
+ debug (1, (_("someone wants %s"), prog_tag (p)));
if (p->v.p.comp->max_instances
&& p->v.p.num_instances >= p->v.p.comp->max_instances)
{
logmsg (LOG_ERR,
_("%s: too many instances running, dropping connection"),
- p->tag);
+ prog_tag (p));
return 1;
}
- pinst = register_prog0 (p->v.p.comp, -1);
+ pinst = register_prog0 (p->v.p.comp);
pinst->v.p.socket = p->v.p.socket;
pinst->v.p.listener = p;
prog_start (pinst);
pinst->v.p.socket = -1;
@@ -1462,182 +1424,25 @@ 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);
}
-
-
-void
-component_fixup_depend (struct component *comp)
-{
- struct grecs_list_entry *ep;
-
- if (comp->depend == NULL)
- return;
-
- for (ep = comp->depend->head; ep; ep = ep->next)
- {
- const char *tag = ep->data;
- struct component *tgt;
-
- tgt = progman_lookup_component (tag);
- if (!tgt)
- {
- logmsg (LOG_ERR,
- _("component %s declares dependency target %s, "
- "which is not declared"),
- comp->tag, tag);
- continue;
- }
- if (!tgt->prereq)
- {
- tgt->prereq = grecs_list_create();
- }
- /* FIXME: memory allocation */
- grecs_list_append (tgt->prereq, grecs_strdup (comp->tag));
- }
- grecs_list_free (comp->depend);
- comp->depend = NULL;
-}
-
-void
-fixup_prerequisites ()
-{
- struct prog *prog;
-
- for (prog = proghead; prog; prog = prog->next)
- if (IS_COMPONENT (prog))
- component_fixup_depend (prog->v.p.comp);
-}
-
-void
-rebuild_prerequisites ()
-{
- struct prog *prog;
- for (prog = proghead; prog; prog = prog->next)
- if (IS_COMPONENT (prog))
- prog_rebuild_prerequisites (prog);
-}
-
-void
-print_dep (struct prog *prog)
-{
- pies_depmap_pos_t pos;
- size_t n;
-
- logmsg_printf (LOG_NOTICE, "%s -> ", prog->tag);
- for (n = depmap_first (depmap, depmap_col, prog->v.p.idx, &pos);
- n != (size_t)-1;
- n = depmap_next (depmap, pos))
- {
- struct prog *dp = prog_lookup_by_idx (n);
- logmsg_printf (LOG_NOTICE, "%s -> ", dp->tag);
- }
- depmap_end (pos);
- logmsg_printf (LOG_NOTICE, "%s\n", prog->tag);
-}
-
-void
-progman_dump_prereq ()
-{
- struct prog *prog;
- for (prog = proghead; prog; prog = prog->next)
- if (prog->prereq)
- {
- int i;
- printf ("%s:", prog->tag);
- for (i = 0; prog->prereq[i]; i++)
- printf (" %s", prog->prereq[i]);
- printf ("\n");
- }
-}
-
-void
-progman_dump_depmap ()
-{
- struct prog *prog;
- size_t i, j;
-
- printf ("%s:\n", _("Dependency map"));
- printf (" ");
- for (i = 0; i < numcomp; i++)
- printf (" %2lu", (unsigned long)i);
- printf ("\n");
- for (i = 0; i < numcomp; i++)
- {
- printf ("%2lu ", (unsigned long)i);
- for (j = 0; j < numcomp; j++)
- printf (" %c ", depmap_isset (depmap, i, j) ? 'X' : ' ');
- printf ("\n");
- }
- printf ("\n%s:\n", _("Legend"));
- for (i = 0; i < numcomp; i++)
- {
- prog = prog_lookup_by_idx (i);
- if (prog)
- printf ("%2lu: %s\n", (unsigned long)i, prog->tag);
- }
-}
-
-int
-progman_build_depmap ()
-{
- int rc = 0;
- size_t i;
- struct prog *prog;
- pies_depmap_t dp;
-
- fixup_prerequisites ();
- rebuild_prerequisites ();
- depmap = depmap_alloc (numcomp);
- for (prog = proghead; prog; prog = prog->next)
- if (prog->prereq)
- {
- for (i = 0; prog->prereq[i]; i++)
- {
- struct prog *dep = prog_lookup_by_tag (prog->prereq[i]);
- if (!dep)
- {
- prog->v.p.status = status_disabled;
- logmsg (LOG_ERR, _("component %s depends on %s, "
- "which is not declared"),
- prog->tag, prog->prereq[i]);
- rc++;
- }
- else
- depmap_set (depmap, prog->v.p.idx, dep->v.p.idx);
- }
- }
- dp = depmap_copy (depmap);
- depmap_tc (dp);
- for (i = 0; i < numcomp; i++)
- if (depmap_isset (dp, i, i))
- {
- prog = prog_lookup_by_idx (i);
- logmsg (LOG_ERR, _("component %s depends on itself"), prog->tag);
- print_dep (prog);
- prog->v.p.status = status_disabled;
- rc++;
- }
- free (dp);
- return rc;
-}
-
void
progman_create_sockets ()
{
struct prog *prog;
for (prog = proghead; prog; prog = prog->next)
{
if (IS_COMPONENT (prog))
{
struct component *comp = prog->v.p.comp;
- if (comp->mode == pies_comp_inetd && !ISCF_TCPMUX (comp->flags))
+ if (comp->mode == pies_comp_inetd && !ISCF_TCPMUX (comp->flags)
+ && prog->v.p.socket == -1)
{
int fd = create_socket (comp->socket_url,
comp->socket_type,
comp->privs.user, comp->umask);
if (fd == -1)
prog->v.p.status = status_disabled;
@@ -1722,13 +1527,13 @@ 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"),
- prog->tag);
+ prog_tag (prog));
else if (prog->v.p.comp->flags & CF_SIGGROUP)
kill (-prog->pid, SIGKILL);
else
kill (prog->pid, SIGKILL);
}
else
@@ -1787,29 +1592,34 @@ progman_wake_sleeping (int onalrm)
progman_recompute_alarm ();
}
static int
prog_start_prerequisites (struct prog *prog)
{
- int i;
- int ret;
-
+ int ret = 0;
+ pies_depmap_pos_t pos;
+ struct component *comp;
+ int warned = 0;
+
if (prog->v.p.status == status_disabled)
return 1;
- if (!prog->prereq)
- return 0; /* Ok to startup */
- debug (1, ("starting prerequisites of %s", prog->tag));
- ret = 0;
- for (i = 0; prog->prereq[i]; i++)
- {
- struct prog *dp = prog_lookup_by_tag (prog->prereq[i]);
- if (!IS_COMPONENT (dp)) /* Skip redirectors */
- continue;
- if (prog->v.p.comp->flags & CF_PRECIOUS)
+ for (comp = component_depmap_first (depmap_col, prog->v.p.comp->arridx, &pos);
+ comp;
+ comp = component_depmap_next (pos))
+ {
+ struct prog *p;
+
+ if (!comp->prog || comp->flags & CF_PRECIOUS)
continue;
- switch (dp->v.p.status)
+ if (!warned)
+ {
+ debug (1, ("starting prerequisites of %s", prog_tag (prog)));
+ warned = 1;
+ }
+ p = comp->prog;
+ switch (p->v.p.status)
{
case status_enabled:
if (prog->pid != 0)
continue;
break;
@@ -1822,24 +1632,26 @@ prog_start_prerequisites (struct prog *prog)
case status_sleeping:
/* FIXME: What to do in this case? */
break;
case status_stopping:
- check_stopping (dp, time (NULL));
+ check_stopping (p, time (NULL));
ret = 1;
continue;
case status_finished:
continue;
}
- prog_start (dp);
- if (dp->v.p.comp->mode == pies_comp_once ||
- !(dp->v.p.status == status_enabled && dp->pid))
+ prog_start (p);
+ if (p->v.p.comp->mode == pies_comp_once ||
+ !(p->v.p.status == status_enabled && p->pid))
ret = 1;
}
+ depmap_end (pos);
+
return ret;
}
void
prog_stop_redirectors (struct prog *prog)
{
@@ -1849,27 +1661,27 @@ prog_stop_redirectors (struct prog *prog)
prog_stop (prog->v.p.redir[RETR_ERR], SIGTERM);
}
void
prog_stop_dependents (struct prog *prog)
{
+ struct component *comp;
pies_depmap_pos_t pos;
- size_t n;
int warned = 0;
prog_stop_redirectors (prog);
- for (n = depmap_first (depmap, depmap_row, prog->v.p.idx, &pos);
- n != (size_t)-1;
- n = depmap_next (depmap, pos))
+ for (comp = component_depmap_first (depmap_row, prog->v.p.comp->arridx, &pos);
+ comp;
+ comp = component_depmap_next (pos))
{
- struct prog *dp = prog_lookup_by_idx (n);
+ struct prog *dp = comp->prog;
if (!dp) /* should not happen */
continue;
if (!warned && dp->pid)
{
- debug (1, ("stopping dependencies of %s", prog->tag));
+ debug (1, ("stopping dependencies of %s", prog_tag (prog)));
warned = 1;
}
prog_stop (dp, SIGTERM);
}
depmap_end (pos);
}
@@ -1885,13 +1697,13 @@ prog_stop (struct prog *prog, int sig)
{
prog->v.p.status = status_stopping;
prog->v.p.timestamp = time (NULL);
recompute_alarm = 1;
}
}
- debug (1, ("stopping %s (%lu)", prog->tag, (unsigned long) prog->pid));
+ debug (1, ("stopping %s (%lu)", prog_tag (prog), (unsigned long) prog->pid));
if (prog->type == TYPE_COMPONENT && prog->v.p.comp->flags & CF_SIGGROUP)
kill (-prog->pid, sig);
else
kill (prog->pid, sig);
}
@@ -1905,36 +1717,42 @@ prog_stop_all (int sig)
if (IS_COMPONENT (prog)
&& (prog->v.p.status == status_enabled
|| prog->v.p.status == status_stopping))
prog_stop (prog, sig);
}
-static int
-progman_wait ()
+int
+progman_wait_until (int (*cond) (void *), void *data)
{
time_t start = time (NULL);
do
{
progman_cleanup (1);
- if (progman_running_count () == 0)
+ if (cond && cond (data))
return 0;
sleep (1);
}
while (time (NULL) - start < shutdown_timeout);
return 1;
}
+static int
+no_children_left (void *p)
+{
+ return progman_running_count () == 0;
+}
+
void
progman_stop ()
{
prog_stop_all (SIGTERM);
- if (progman_wait ())
+ if (progman_wait_until (no_children_left, NULL))
{
prog_stop_all (SIGKILL);
- progman_wait ();
+ progman_wait_until (no_children_left, NULL);
}
}
static void
print_status (const char *tag, pid_t pid, int status, int expect_term)
{
@@ -2334,13 +2152,13 @@ run_command (struct action *act, struct prog *prog, unsigned retcode,
if (pid == 0)
{
debug (1, (_("executing %s"), act->command));
/* Child */
setsid ();
setenv ("PIES_VERSION", PACKAGE_VERSION, 1);
- setenv ("PIES_COMPONENT", prog->tag, 1);
+ setenv ("PIES_COMPONENT", prog_tag (prog), 1);
setenv ("PIES_PID", umaxtostr (child_pid, buf), 1);
if (retcode & STATUS_SIG_BIT)
setenv ("PIES_SIGNAL", umaxtostr (STATUS_CODE (retcode), buf), 1);
else
setenv ("PIES_STATUS", umaxtostr (STATUS_CODE (retcode), buf), 1);
@@ -2362,66 +2180,73 @@ run_command (struct action *act, struct prog *prog, unsigned retcode,
}
static void
react (struct prog *prog, int status, pid_t pid)
{
unsigned retcode;
- struct action *act = prog->v.p.comp->act_head;
-
- if (!act)
- act = default_component.act_head;
+ struct grecs_list *list = prog->v.p.comp->act_list;
+
+ if (!list)
+ list = default_component.act_list;
if (WIFEXITED (status))
{
retcode = WEXITSTATUS (status);
- debug (1, (_("%s: terminated with code %d"), prog->tag, retcode));
+ debug (1, (_("%s: terminated with code %d"), prog_tag (prog), retcode));
}
else if (WIFSIGNALED (status))
{
retcode = WTERMSIG (status);
- debug (1, (_("%s: terminated on signal %d"), prog->tag, retcode));
+ debug (1, (_("%s: terminated on signal %d"), prog_tag (prog), retcode));
retcode |= STATUS_SIG_BIT;
}
else
{
- debug (1, (_("%s: unrecognized termination status"), prog->tag));
+ debug (1, (_("%s: unrecognized termination status"), prog_tag (prog)));
/* Enforce default action: */
- act = NULL;
+ list = NULL;
}
-
- for (; act; act = act->next)
+
+ if (list)
{
- if (status_matches_p (act, retcode))
+ struct grecs_list_entry *ep;
+ for (ep = list->head; ep; ep = ep->next)
{
- if (act->command)
+ struct action *act = ep->data;
+
+ if (status_matches_p (act, retcode))
{
- run_command (act, prog, retcode, pid);
- }
+ 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;
+ 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->v.p.status = status_disabled;
- /* FIXME:
- if (prog->v.p.comp->mode == pies_comp_inetd)
- disable_socket (prog->v.p.socket);
- */
+ case action_disable:
+ logmsg (LOG_NOTICE, _("disabling component %s"),
+ prog_tag (prog));
+ prog->v.p.status = status_disabled;
+ /* FIXME:
+ if (prog->v.p.comp->mode == pies_comp_inetd)
+ disable_socket (prog->v.p.socket);
+ */
+ }
+ if (act->addr)
+ notify (prog_tag (prog), status, act);
+ break;
}
- if (act->addr)
- notify (prog->tag, status, act);
- break;
}
}
- if (!act && prog->v.p.comp->mode != pies_comp_inetd)
+ if (!list && prog->v.p.comp->mode != pies_comp_inetd)
/* Default action: */
prog_start (prog);
}
void
@@ -2438,13 +2263,13 @@ progman_cleanup (int expect_term)
continue;
}
prog->pid = 0;
switch (prog->type)
{
case TYPE_COMPONENT:
- print_status (prog->tag, pid, status, expect_term);
+ print_status (prog_tag (prog), pid, status, 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)
@@ -2458,47 +2283,64 @@ progman_cleanup (int expect_term)
prog->v.p.cclass = NULL;
}
}
prog_stop_redirectors (prog);
destroy_prog (&prog);
- react (listener, status, pid);
- if (listener->v.p.comp->flags & CF_WAIT)
- enable_socket (listener->v.p.socket);
- }
- else if (prog->v.p.comp->mode >= pies_mark_sysvinit)
- {
- sysvinit_acct (SYSV_ACCT_PROC_STOP, "", prog->tag, pid, "");
- prog->v.p.status = status_finished;
+ if (listener->v.p.num_instances == 0
+ && !component_is_active (prog->v.p.comp))
+ destroy_prog (&listener);
+ else
+ {
+ if (!expect_term)
+ react (listener, status, pid);
+ if (listener->v.p.comp->flags & CF_WAIT)
+ enable_socket (listener->v.p.socket);
+ }
}
else
{
- if (is_sysvinit (prog->v.p.comp))
- sysvinit_acct (SYSV_ACCT_PROC_STOP, "", prog->tag, pid, "");
+ if (prog->v.p.comp->mode >= pies_mark_sysvinit)
+ {
+ sysvinit_acct (SYSV_ACCT_PROC_STOP, "", prog_tag (prog),
+ pid, "");
+ prog->v.p.status = status_finished;
+ }
+ else
+ {
+ if (is_sysvinit (prog->v.p.comp))
+ sysvinit_acct (SYSV_ACCT_PROC_STOP, "",
+ prog_tag (prog), pid, "");
- prog->v.p.status = (prog->v.p.comp->flags & CF_DISABLED)
+ prog->v.p.status =
+ (prog->v.p.comp->flags & CF_DISABLED)
? status_disabled : status_enabled;
- prog_stop_dependents (prog);
- if (!expect_term)
- react (prog, status, pid);
+ prog_stop_dependents (prog);
+ if (!expect_term)
+ react (prog, status, pid);
+ }
+
+ if (!component_is_active (prog->v.p.comp))
+ destroy_prog (&prog);
}
+
break;
case TYPE_REDIRECTOR:
/* It was a redirector of an already finished process. */
- print_status (prog->tag, pid, status,
+ print_status (prog_tag (prog), pid, status,
expect_term ||
(prog->v.r.master &&
prog->v.r.master->v.p.status == status_stopping));
debug (1, (_("removing redirector %s, pid=%lu"),
- prog->tag, (unsigned long)pid));
+ prog_tag (prog), (unsigned long)pid));
destroy_prog (&prog);
break;
case TYPE_COMMAND:
- print_status (prog->tag, pid, status, expect_term);
+ print_status (prog_tag (prog), pid, status, expect_term);
destroy_prog (&prog);
break;
}
}
if (!expect_term)
@@ -2512,33 +2354,33 @@ progman_stop_component (struct prog *prog)
if (prog && IS_COMPONENT (prog))
{
switch (prog->v.p.status)
{
case status_enabled:
case status_listener:
- logmsg (LOG_INFO, _("stopping component `%s'"), prog->tag);
+ logmsg (LOG_INFO, _("stopping component `%s'"), prog_tag (prog));
prog_stop (prog, SIGTERM);
break;
case status_disabled:
if (!(prog->v.p.comp->flags & CF_DISABLED))
{
- logmsg (LOG_INFO, _("enabling component `%s'"), prog->tag);
+ logmsg (LOG_INFO, _("enabling component `%s'"), prog_tag (prog));
prog->v.p.status = status_enabled;
}
break;
case status_sleeping:
- logmsg (LOG_INFO, _("waking up component `%s'"), prog->tag);
+ logmsg (LOG_INFO, _("waking up component `%s'"), prog_tag (prog));
prog->v.p.failcount = 0;
break;
default:
logmsg (LOG_INFO,
_("stopping component `%s': component not started"),
- prog->tag);
+ prog_tag (prog));
}
}
}
void
progman_stop_tag (const char *name)
diff --git a/src/sysvinit.c b/src/sysvinit.c
index 375a0d5..a4e0d63 100644
--- a/src/sysvinit.c
+++ b/src/sysvinit.c
@@ -1,8 +1,8 @@
/* This file is part of GNU Pies.
- Copyright (C) 2013 Sergey Poznyakoff
+ Copyright (C) 2013-2016 Sergey Poznyakoff
GNU Pies is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
@@ -276,13 +276,13 @@ runlevel_setup_prog (struct prog *prog, void *data)
if (rc < 0)
return 0;
if (rc)
prog->v.p.status = status_enabled;
else
prog->v.p.status = status_disabled;
- debug (1, ("%s: %s", prog->tag,
+ debug (1, ("%s: %s", prog_tag (prog),
prog->v.p.status == status_enabled ?
"enabled" : "disabled"));
}
return 0;
}
@@ -873,22 +873,23 @@ inittab_parse (const char *file)
debug_level = atoi (ws.ws_wordv[3]);
}
else if (strcmp (ws.ws_wordv[2], "next") == 0)
{
if (ws.ws_wordc >= 5)
{
- enum config_syntax synt;
+ struct config_syntax *synt =
+ str_to_config_syntax (ws.ws_wordv[3]);
- if (str_to_config_syntax (ws.ws_wordv[3], &synt))
+ if (!synt)
logmsg (LOG_ERR, "%s:%u: %s",
file, line_no, _("unknown syntax type"));
else
- add_config (synt, ws.ws_wordv[4]);
+ config_file_add (synt, ws.ws_wordv[4]);
}
else if (ws.ws_wordc == 4)
- add_config (CONF_PIES, ws.ws_wordv[3]);
+ config_file_add_type (CONF_PIES, ws.ws_wordv[3]);
}
else if (strcmp (ws.ws_wordv[2], "stop") == 0)
{
wordsplit_free (&ws);
break;
}
@@ -930,58 +931,36 @@ inittab_parse (const char *file)
logmsg (LOG_ERR, "%s:%u: %s",
file, line_no, _("unknown action"));
err = 1;
continue;
}
- comp = calloc (1, sizeof (*comp));
- if (!comp)
- {
- logmsg (LOG_ERR, "%s:%u: %s", file, line_no,
- _("not enough memory"));
- err = 1;
- continue;
- }
-
+ comp = component_create (id);
comp->mode = ap->mode;
- comp->tag = strdup (id);
- comp->runlevels = strdup (runlevels);
-
- if (!comp->tag || !comp->runlevels)
- {
- component_free (comp);
- logmsg (LOG_ERR, "%s:%u: %s", file, line_no,
- _("not enough memory"));
- err = 1;
- continue;
- }
+ comp->runlevels = grecs_strdup (runlevels);
if (wordsplit (process, &ws, WRDSF_DEFFLAGS))
{
component_free (comp);
logmsg (LOG_ERR, "%s:%u: wordsplit: %s", file, line_no,
strerror (errno));
err = 1;
continue;
}
- comp->argc = ws.ws_wordc;
- comp->argv = ws.ws_wordv;
- comp->program = strdup (ws.ws_wordv[0]);
- ws.ws_wordc = 0;
- ws.ws_wordv = NULL;
+ wordsplit_getwords (&ws, &comp->argc, &comp->argv);
+ comp->program = grecs_strdup (comp->argv[0]);
wordsplit_free (&ws);
comp->flags |= CF_SIGGROUP;
if (ap->parser && ap->parser (comp, file, line_no))
{
component_free (comp);
err = 1;
continue;
}
- register_prog (comp);
}
free (buf);
fclose (fp);
return err;
}
diff --git a/src/userprivs.c b/src/userprivs.c
index 646421e..9f9724f 100644
--- a/src/userprivs.c
+++ b/src/userprivs.c
@@ -247,6 +247,29 @@ pies_epriv_setup (struct pies_privs *privs)
{
logmsg (LOG_ERR, _("cannot switch to EUID %lu: %s"),
(unsigned long) uid, strerror (errno));
exit (EX_USAGE);
}
}
+
+int
+pies_privs_cmp (struct pies_privs const *a, struct pies_privs const *b)
+{
+ if (!a)
+ return !!b;
+ else if (!b)
+ return 1;
+ if (safe_strcmp (a->user, b->user))
+ return 1;
+ if (a->allgroups != b->allgroups)
+ return 1;
+ return grecs_list_compare (a->groups, b->groups);
+}
+
+void
+pies_privs_free (struct pies_privs *p)
+{
+ grecs_free (p->user);
+ grecs_list_free (p->groups);
+}
+
+

Return to:

Send suggestions and report system problems to the System administrator.