aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitmodules3
-rw-r--r--Makefile.am4
-rw-r--r--bootstrap.conf8
-rw-r--r--configure.ac16
-rw-r--r--gnulib.modules9
m---------grecs0
-rw-r--r--lib/Makefile.am17
-rw-r--r--lib/config.c115
-rw-r--r--lib/intprops.h79
-rw-r--r--lib/libpies.h45
-rw-r--r--lib/nls.c11
-rw-r--r--lib/parsetime.c6
-rw-r--r--lib/proctitle.c10
-rw-r--r--lib/userprivs.c291
-rw-r--r--src/Makefile.am34
-rw-r--r--src/depmap.c18
-rw-r--r--src/limits.c27
-rw-r--r--src/meta1gram.y395
-rw-r--r--src/meta1lex.h14
-rw-r--r--src/meta1lex.l83
-rw-r--r--src/pies.c1614
-rw-r--r--src/pies.h133
-rw-r--r--src/progman.c557
-rw-r--r--src/socket.c197
24 files changed, 1750 insertions, 1936 deletions
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..fea8f96
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
1[submodule "grecs"]
2 path = grecs
3 url = git://git.gnu.org.ua/grecs.git
diff --git a/Makefile.am b/Makefile.am
index f665de1..67e64f3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,6 +1,6 @@
1ACLOCAL_AMFLAGS = -I m4 -I am 1ACLOCAL_AMFLAGS = -I m4 -I am -I grecs/am
2 2
3SUBDIRS=gnu lib src doc po 3SUBDIRS=gnu grecs lib src doc po
4 4
5# Define the following variables in order to use the ChangeLog rule below: 5# Define the following variables in order to use the ChangeLog rule below:
6# prev_change_log [optional] Name of the previous ChangeLog file. 6# prev_change_log [optional] Name of the previous ChangeLog file.
diff --git a/bootstrap.conf b/bootstrap.conf
index ff05127..02ae139 100644
--- a/bootstrap.conf
+++ b/bootstrap.conf
@@ -17,6 +17,12 @@
17source_base=gnu 17source_base=gnu
18gnulib_name=libgnu 18gnulib_name=libgnu
19gnulib_mk=Makefile.am 19gnulib_mk=Makefile.am
20SKIP_PO=t
21
22if git config submodule.grecs.url >/dev/null; then : ; else
23 git submodule init || exit $?
24 git submodule update || exit $?
25fi
20 26
21MODAVOID="xalloc-die openat-die" 27MODAVOID="xalloc-die openat-die"
22 28
@@ -25,7 +31,7 @@ if [ -n "$MODAVOID" ]; then
25fi 31fi
26 32
27# gnulib modules used by this package. 33# gnulib modules used by this package.
28gnulib_modules=`grep '^[^#]' gnulib.modules` 34gnulib_modules=`grep -h '^[^#]' gnulib.modules grecs/gnulib.modules | sort | uniq`
29 35
30NLS_MARKERS="\ 36NLS_MARKERS="\
31 mu_error:1" 37 mu_error:1"
diff --git a/configure.ac b/configure.ac
index 192fc53..e454566 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,19 +1,18 @@
1# This file is part of Pies. -*- autoconf -*- 1# This file is part of Pies. -*- autoconf -*-
2# Copyright (C) 2009 Sergey Poznyakoff 2# Copyright (C) 2009 Sergey Poznyakoff
3# 3#
4# This program is free software; you can redistribute it and/or modify 4# Pies is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by 5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 3, or (at your option) 6# the Free Software Foundation; either version 3, or (at your option)
7# any later version. 7# any later version.
8# 8#
9# This program is distributed in the hope that it will be useful, 9# Pies is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details. 12# GNU General Public License for more details.
13# 13#
14# You should have received a copy of the GNU General Public License 14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>. 15# along with Pies. If not, see <http://www.gnu.org/licenses/>.
16# Process this file with autoconf to produce a configure script.
17 16
18AC_PREREQ([2.63]) 17AC_PREREQ([2.63])
19AC_INIT([pies], [1.0], [bug-mailfromd@gnu.org.ua]) 18AC_INIT([pies], [1.0], [bug-mailfromd@gnu.org.ua])
@@ -57,11 +56,8 @@ AC_CHECK_FUNCS([alarm dup2 gethostbyname isascii memmove memset select setenv so
57# Gnulib 56# Gnulib
58gl_INIT 57gl_INIT
59 58
60# ********************** 59# Grecs
61# Mailutils 60GRECS_SETUP
62# **********************
63# FIXME
64AM_GNU_MAILUTILS(2.0, [mailer cfg argp], [:])
65 61
66# Test for setproctitle 62# Test for setproctitle
67MF_PROCTITLE 63MF_PROCTITLE
@@ -90,6 +86,8 @@ esac
90 86
91AC_CONFIG_FILES([Makefile 87AC_CONFIG_FILES([Makefile
92 gnu/Makefile 88 gnu/Makefile
89 grecs/Makefile
90 grecs/src/Makefile
93 lib/Makefile 91 lib/Makefile
94 src/Makefile 92 src/Makefile
95 doc/Makefile 93 doc/Makefile
diff --git a/gnulib.modules b/gnulib.modules
index ef40e06..e505b7e 100644
--- a/gnulib.modules
+++ b/gnulib.modules
@@ -1,10 +1,15 @@
1# List of gnulib modules needed for Pies. 1# List of gnulib modules needed for Pies.
2# A module name per line. Empty lines and comments are ignored. 2# A module name per line. Empty lines and comments are ignored.
3 3
4argp
5c-ctype
6c-strcase
4gettext 7gettext
5gitlog-to-changelog 8gitlog-to-changelog
6inttostr 9inttostr
7inttypes 10inttypes
8xalloc 11obstack
12progname
9sysexits 13sysexits
10c-ctype 14xalloc
15xvasprintf
diff --git a/grecs b/grecs
new file mode 160000
Subproject 0addbd7aa72859139542010ee21bfc370f32e13
diff --git a/lib/Makefile.am b/lib/Makefile.am
index f83e7e3..a3ffed2 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -1,31 +1,30 @@
1# This file is part of Mailfromd. 1# This file is part of Pies.
2# Copyright (C) 2005, 2006, 2007, 2008 Sergey Poznyakoff 2# Copyright (C) 2005, 2006, 2007, 2008 Sergey Poznyakoff
3# 3#
4# This program is free software; you can redistribute it and/or modify 4# Pies is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by 5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 3, or (at your option) 6# the Free Software Foundation; either version 3, or (at your option)
7# any later version. 7# any later version.
8# 8#
9# This program is distributed in the hope that it will be useful, 9# Pies is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details. 12# GNU General Public License for more details.
13# 13#
14# You should have received a copy of the GNU General Public License 14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>. 15# along with Pies. If not, see <http://www.gnu.org/licenses/>. */
16 16
17noinst_LIBRARIES=libmf.a 17noinst_LIBRARIES=libpies.a
18 18
19noinst_HEADERS = libpies.h 19noinst_HEADERS = libpies.h
20 20
21libmf_a_SOURCES=\ 21libpies_a_SOURCES=\
22 config.c\
23 nls.c\ 22 nls.c\
24 parsetime.c\ 23 parsetime.c\
25 proctitle.c\ 24 proctitle.c\
26 userprivs.c 25 strtotok.c
27 26
28libmf_a_LIBADD=$(LIBOBJS) 27libpies_a_LIBADD=$(LIBOBJS)
29 28
30INCLUDES = -I$(top_srcdir)/gnu -I../gnu 29INCLUDES = -I$(top_srcdir)/gnu -I../gnu
31 30
diff --git a/lib/config.c b/lib/config.c
deleted file mode 100644
index 8fcb926..0000000
--- a/lib/config.c
+++ /dev/null
@@ -1,115 +0,0 @@
1/* This file is part of Pies.
2 Copyright (C) 2007, 2008, 2009 Sergey Poznyakoff
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
16
17#ifdef HAVE_CONFIG_H
18# include <config.h>
19#endif
20
21#include <libpies.h>
22
23
24char **
25config_array_to_argv (mu_config_value_t *val, mu_debug_t debug)
26{
27 int i, j;
28 int argc;
29 char **argv;
30
31 argc = val->v.arg.c;
32 argv = xcalloc (argc + 1, sizeof (argv[0]));
33 for (i = j = 0; i < argc; i++)
34 {
35 if (mu_cfg_assert_value_type (&val->v.arg.v[i], MU_CFG_STRING,
36 debug) == 0)
37 argv[j++] = xstrdup (val->v.arg.v[i].v.string);
38 }
39 argv[j] = NULL;
40 return argv;
41}
42
43char *
44config_array_to_string (mu_config_value_t *val, mu_debug_t debug)
45{
46 size_t len = 0;
47 int i;
48 char *str, *p;
49
50 for (i = 0; i < val->v.arg.c; i++)
51 {
52 if (mu_cfg_assert_value_type (&val->v.arg.v[i], MU_CFG_STRING, debug))
53 return NULL;
54 len += strlen (val->v.arg.v[i].v.string) + 1;
55 }
56
57 str = xmalloc (len);
58 p = str;
59 for (i = 0; i < val->v.arg.c; i++)
60 {
61 size_t n = strlen (val->v.arg.v[i].v.string);
62 memcpy (p, val->v.arg.v[i].v.string, n);
63 p += n;
64 *p++ = ' ';
65 }
66 str[len-1] = 0;
67 return str;
68}
69
70
71int
72config_cb_timeout (struct timeval *pt, mu_debug_t debug,
73 mu_config_value_t *val)
74{
75 int rc;
76 const char *endp;
77 time_t t;
78 const char *str;
79 char *alloc_str = NULL;
80
81 switch (val->type)
82 {
83 case MU_CFG_STRING:
84 str = val->v.string;
85 break;
86
87 case MU_CFG_ARRAY:
88 str = alloc_str = config_array_to_string (val, debug);
89 if (!str)
90 return 1;
91 break;
92
93 case MU_CFG_LIST:
94 mu_cfg_format_error (debug, MU_DEBUG_ERROR,
95 _("unexpected list"));
96 return 1;
97 }
98
99 rc = parse_time_interval (str, &t, &endp);
100 if (rc)
101 mu_cfg_format_error (debug, MU_DEBUG_ERROR,
102 _("unrecognized time format (near `%s')"),
103 endp);
104 else
105 {
106 pt->tv_usec = 0;
107 pt->tv_sec = t;
108 }
109 free (alloc_str);
110 return 0;
111}
112
113
114
115
diff --git a/lib/intprops.h b/lib/intprops.h
deleted file mode 100644
index 7db55e9..0000000
--- a/lib/intprops.h
+++ /dev/null
@@ -1,79 +0,0 @@
1/* intprops.h -- properties of integer types
2
3 Copyright (C) 2001, 2002, 2003, 2004, 2005,
4 2007 Free Software Foundation, Inc.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3, or (at your option)
9 any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software Foundation,
18 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
19
20/* Written by Paul Eggert. */
21
22#include <limits.h>
23
24/* The extra casts in the following macros work around compiler bugs,
25 e.g., in Cray C 5.0.3.0. */
26
27/* True if the arithmetic type T is an integer type. bool counts as
28 an integer. */
29#define TYPE_IS_INTEGER(t) ((t) 1.5 == 1)
30
31/* True if negative values of the signed integer type T use two's
32 complement, ones' complement, or signed magnitude representation,
33 respectively. Much GNU code assumes two's complement, but some
34 people like to be portable to all possible C hosts. */
35#define TYPE_TWOS_COMPLEMENT(t) ((t) ~ (t) 0 == (t) -1)
36#define TYPE_ONES_COMPLEMENT(t) ((t) ~ (t) 0 == 0)
37#define TYPE_SIGNED_MAGNITUDE(t) ((t) ~ (t) 0 < (t) -1)
38
39/* True if the arithmetic type T is signed. */
40#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
41
42/* The maximum and minimum values for the integer type T. These
43 macros have undefined behavior if T is signed and has padding bits.
44 If this is a problem for you, please let us know how to fix it for
45 your host. */
46#define TYPE_MINIMUM(t) \
47 ((t) (! TYPE_SIGNED (t) \
48 ? (t) 0 \
49 : TYPE_SIGNED_MAGNITUDE (t) \
50 ? ~ (t) 0 \
51 : ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1)))
52#define TYPE_MAXIMUM(t) \
53 ((t) (! TYPE_SIGNED (t) \
54 ? (t) -1 \
55 : ~ (~ (t) 0 << (sizeof (t) * CHAR_BIT - 1))))
56
57/* Return zero if T can be determined to be an unsigned type.
58 Otherwise, return 1.
59 When compiling with GCC, INT_STRLEN_BOUND uses this macro to obtain a
60 tighter bound. Otherwise, it overestimates the true bound by one byte
61 when applied to unsigned types of size 2, 4, 16, ... bytes.
62 The symbol signed_type_or_expr__ is private to this header file. */
63#if __GNUC__ >= 2
64# define signed_type_or_expr__(t) TYPE_SIGNED (__typeof__ (t))
65#else
66# define signed_type_or_expr__(t) 1
67#endif
68
69/* Bound on length of the string representing an integer type or expression T.
70 Subtract 1 for the sign bit if T is signed; log10 (2.0) < 146/485;
71 add 1 for integer division truncation; add 1 more for a minus sign
72 if needed. */
73#define INT_STRLEN_BOUND(t) \
74 ((sizeof (t) * CHAR_BIT - signed_type_or_expr__ (t)) * 146 / 485 \
75 + signed_type_or_expr__ (t) + 1)
76
77/* Bound on buffer size needed to represent an integer type or expression T,
78 including the terminating null. */
79#define INT_BUFSIZE_BOUND(t) (INT_STRLEN_BOUND (t) + 1)
diff --git a/lib/libpies.h b/lib/libpies.h
index 4733c63..7822595 100644
--- a/lib/libpies.h
+++ b/lib/libpies.h
@@ -1,24 +1,22 @@
1/* This file is part of Pies. 1/* This file is part of Pies.
2 Copyright (C) 2009 Sergey Poznyakoff 2 Copyright (C) 2009 Sergey Poznyakoff
3 3
4 This program is free software; you can redistribute it and/or modify 4 Pies is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option) 6 the Free Software Foundation; either version 3, or (at your option)
7 any later version. 7 any later version.
8 8
9 This program is distributed in the hope that it will be useful, 9 Pies is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details. 12 GNU General Public License for more details.
13 13
14 You should have received a copy of the GNU General Public License 14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 along with Pies. If not, see <http://www.gnu.org/licenses/>. */
16 16
17#include <unistd.h> 17#include <unistd.h>
18#include <stdlib.h> 18#include <stdlib.h>
19#include <gettext.h> 19#include <gettext.h>
20#include <mailutils/types.h>
21#include <mailutils/cfg.h>
22 20
23 21
24#define _(String) gettext(String) 22#define _(String) gettext(String)
@@ -41,30 +39,25 @@ void *xcalloc (size_t count, size_t size);
41char *xstrdup (const char *str); 39char *xstrdup (const char *str);
42 40
43 41
44struct mf_privs
45{
46 char *user;
47 int allgroups;
48 mu_list_t groups;
49};
50
51int switch_to_privs (uid_t uid, gid_t gid, mu_list_t retain_groups);
52int get_user_groups (mu_list_t *pgrouplist, const char *user);
53
54void mf_priv_setup (struct mf_privs *);
55void mf_epriv_setup (struct mf_privs *);
56
57
58char **config_array_to_argv (mu_config_value_t *val, mu_debug_t debug);
59char *config_array_to_string (mu_config_value_t *val, mu_debug_t debug);
60
61int config_cb_timeout (struct timeval *pt, mu_debug_t debug,
62 mu_config_value_t *val);
63
64
65void mf_proctitle_init (int argc, char *argv[], char *env[]); 42void mf_proctitle_init (int argc, char *argv[], char *env[]);
66void mf_proctitle_format (const char *fmt, ...); 43void mf_proctitle_format (const char *fmt, ...);
67 44
68 45
69size_t longtostr (long i, char *buf, size_t size); 46size_t longtostr (long i, char *buf, size_t size);
70size_t ulongtostr (unsigned long i, char *buf, size_t size); 47size_t ulongtostr (unsigned long i, char *buf, size_t size);
48
49
50struct tokendef
51{
52 char *name;
53 int tok;
54};
55
56int strtotok_len (struct tokendef *tab, const char *str, size_t len,
57 int *pres);
58int strtotok_len_ci (struct tokendef *tab, const char *str, size_t len,
59 int *pres);
60int strtotok (struct tokendef *tab, const char *str, int *pres);
61int strtotok_ci (struct tokendef *tab, const char *str, int *pres);
62int toktostr (struct tokendef *tab, int tok, const char **pres);
63
diff --git a/lib/nls.c b/lib/nls.c
index f2b067e..b42192f 100644
--- a/lib/nls.c
+++ b/lib/nls.c
@@ -1,18 +1,18 @@
1/* This file is part of Mailfromd. 1/* This file is part of Pies.
2 Copyright (C) 2007, 2008 Sergey Poznyakoff 2 Copyright (C) 2009 Sergey Poznyakoff
3 3
4 This program is free software; you can redistribute it and/or modify 4 Pies is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option) 6 the Free Software Foundation; either version 3, or (at your option)
7 any later version. 7 any later version.
8 8
9 This program is distributed in the hope that it will be useful, 9 Pies is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details. 12 GNU General Public License for more details.
13 13
14 You should have received a copy of the GNU General Public License 14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 along with Pies. If not, see <http://www.gnu.org/licenses/>. */
16 16
17#ifdef HAVE_CONFIG_H 17#ifdef HAVE_CONFIG_H
18# include <config.h> 18# include <config.h>
@@ -25,7 +25,6 @@ void
25mf_init_nls () 25mf_init_nls ()
26{ 26{
27#ifdef ENABLE_NLS 27#ifdef ENABLE_NLS
28 mu_init_nls ();
29 setlocale (LC_ALL, ""); 28 setlocale (LC_ALL, "");
30 bindtextdomain (PACKAGE, LOCALEDIR); 29 bindtextdomain (PACKAGE, LOCALEDIR);
31 bindtextdomain ("mailfromd", LOCALEDIR); 30 bindtextdomain ("mailfromd", LOCALEDIR);
diff --git a/lib/parsetime.c b/lib/parsetime.c
index 99d8079..6b74501 100644
--- a/lib/parsetime.c
+++ b/lib/parsetime.c
@@ -1,18 +1,18 @@
1/* This file is part of Pies. 1/* This file is part of Pies.
2 Copyright (C) 2007, 2008, 2009 Sergey Poznyakoff 2 Copyright (C) 2007, 2008, 2009 Sergey Poznyakoff
3 3
4 This program is free software; you can redistribute it and/or modify 4 Pies is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option) 6 the Free Software Foundation; either version 3, or (at your option)
7 any later version. 7 any later version.
8 8
9 This program is distributed in the hope that it will be useful, 9 Pies is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details. 12 GNU General Public License for more details.
13 13
14 You should have received a copy of the GNU General Public License 14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 along with Pies. If not, see <http://www.gnu.org/licenses/>. */
16 16
17#ifdef HAVE_CONFIG_H 17#ifdef HAVE_CONFIG_H
18# include <config.h> 18# include <config.h>
diff --git a/lib/proctitle.c b/lib/proctitle.c
index f9ff967..430811c 100644
--- a/lib/proctitle.c
+++ b/lib/proctitle.c
@@ -1,18 +1,18 @@
1/* This file is part of Mailfromd. 1/* This file is part of Pies.
2 Copyright (C) 2007, 2008 Sergey Poznyakoff 2 Copyright (C) 2007, 2008, 2009 Sergey Poznyakoff
3 3
4 This program is free software; you can redistribute it and/or modify 4 Pies is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option) 6 the Free Software Foundation; either version 3, or (at your option)
7 any later version. 7 any later version.
8 8
9 This program is distributed in the hope that it will be useful, 9 Pies is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details. 12 GNU General Public License for more details.
13 13
14 You should have received a copy of the GNU General Public License 14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 along with Pies. If not, see <http://www.gnu.org/licenses/>. */
16 16
17#ifdef HAVE_CONFIG_H 17#ifdef HAVE_CONFIG_H
18# include <config.h> 18# include <config.h>
diff --git a/lib/userprivs.c b/lib/userprivs.c
deleted file mode 100644
index 8d13c38..0000000
--- a/lib/userprivs.c
+++ /dev/null
@@ -1,291 +0,0 @@
1/* This file is part of Mailfromd.
2 Copyright (C) 2007, 2008 Sergey Poznyakoff
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */
16
17#ifdef HAVE_CONFIG_H
18# include <config.h>
19#endif
20#include <stdlib.h>
21#include <string.h>
22#include <pwd.h>
23#include <grp.h>
24#include <unistd.h>
25#include <mailutils/assoc.h>
26#include <mailutils/errno.h>
27#include <mailutils/error.h>
28#include <mailutils/errno.h>
29#include <mailutils/nls.h>
30#include <mailutils/list.h>
31#include <mailutils/iterator.h>
32/* FIXME: */
33#include <sysexits.h>
34#include "libpies.h"
35
36int
37get_user_groups (mu_list_t *pgrouplist, const char *user)
38{
39 int rc;
40 struct group *gr;
41 mu_list_t list;
42
43 if (!*pgrouplist)
44 {
45 rc = mu_list_create (pgrouplist);
46 if (rc)
47 {
48 mu_error (_("%s: cannot create list: %s"),
49 "get_user_groups", mu_strerror (rc));
50 return rc;
51 }
52 }
53 list = *pgrouplist;
54 setgrent ();
55 for (rc = 0; rc == 0 && (gr = getgrent ());)
56 {
57 char **p;
58 for (p = gr->gr_mem; *p; p++)
59 if (strcmp (*p, user) == 0)
60 {
61 /* FIXME: Avoid duplicating gids */
62 rc = mu_list_append (list, (void *) gr->gr_gid);
63 if (rc)
64 mu_error (_("%s: cannot append to list: %s"),
65 "get_user_groups", mu_strerror (rc));
66 break;
67 }
68 }
69 endgrent ();
70 return rc;
71}
72
73/* Switch to the given UID/GID */
74int
75switch_to_privs (uid_t uid, gid_t gid, mu_list_t retain_groups)
76{
77 int rc = 0;
78 gid_t *emptygidset;
79 size_t size = 1, j = 1;
80 mu_iterator_t itr;
81
82 if (uid == 0)
83 {
84 mu_error (_("Refusing to run as root"));
85 return 1;
86 }
87
88 /* Create a list of supplementary groups */
89 mu_list_count (retain_groups, &size);
90 size++;
91 emptygidset = xmalloc (size * sizeof emptygidset[0]);
92 emptygidset[0] = gid ? gid : getegid ();
93
94 if (mu_list_get_iterator (retain_groups, &itr) == 0)
95 {
96 for (mu_iterator_first (itr);
97 !mu_iterator_is_done (itr); mu_iterator_next (itr))
98 mu_iterator_current (itr, (void **) (emptygidset + j++));
99 mu_iterator_destroy (&itr);
100 }
101
102 /* Reset group permissions */
103 if (geteuid () == 0 && setgroups (j, emptygidset))
104 {
105 mu_error (_("setgroups(1, %lu) failed: %s"),
106 (unsigned long) emptygidset[0], mu_strerror (errno));
107 rc = 1;
108 }
109 free (emptygidset);
110
111 /* Switch to the user's gid. On some OSes the effective gid must
112 be reset first */
113
114#if defined(HAVE_SETEGID)
115 if ((rc = setegid (gid)) < 0)
116 mu_error (_("setegid(%lu) failed: %s"),
117 (unsigned long) gid, mu_strerror (errno));
118#elif defined(HAVE_SETREGID)
119 if ((rc = setregid (gid, gid)) < 0)
120 mu_error (_("setregid(%lu,%lu) failed: %s"),
121 (unsigned long) gid, (unsigned long) gid, mu_strerror (errno));
122#elif defined(HAVE_SETRESGID)
123 if ((rc = setresgid (gid, gid, gid)) < 0)
124 mu_error (_("setresgid(%lu,%lu,%lu) failed: %s"),
125 (unsigned long) gid,
126 (unsigned long) gid, (unsigned long) gid, mu_strerror (errno));
127#endif
128
129 if (rc == 0 && gid != 0)
130 {
131 if ((rc = setgid (gid)) < 0 && getegid () != gid)
132 mu_error (_("setgid(%lu) failed: %s"),
133 (unsigned long) gid, mu_strerror (errno));
134 if (rc == 0 && getegid () != gid)
135 {
136 mu_error (_("Cannot set effective gid to %lu"),
137 (unsigned long) gid);
138 rc = 1;
139 }
140 }
141
142 /* Now reset uid */
143 if (rc == 0 && uid != 0)
144 {
145 uid_t euid;
146
147 if (setuid (uid)
148 || geteuid () != uid
149 || (getuid () != uid && (geteuid () == 0 || getuid () == 0)))
150 {
151
152#if defined(HAVE_SETREUID)
153 if (geteuid () != uid)
154 {
155 if (setreuid (uid, -1) < 0)
156 {
157 mu_error (_("setreuid(%lu,-1) failed: %s"),
158 (unsigned long) uid, mu_strerror (errno));
159 rc = 1;
160 }
161 if (setuid (uid) < 0)
162 {
163 mu_error (_("second setuid(%lu) failed: %s"),
164 (unsigned long) uid, mu_strerror (errno));
165 rc = 1;
166 }
167 }
168 else
169#endif
170 {
171 mu_error (_("setuid(%lu) failed: %s"),
172 (unsigned long) uid, mu_strerror (errno));
173 rc = 1;
174 }
175 }
176
177 euid = geteuid ();
178 if (uid != 0 && setuid (0) == 0)
179 {
180 mu_error (_("seteuid(0) succeeded when it should not"));
181 rc = 1;
182 }
183 else if (uid != euid && setuid (euid) == 0)
184 {
185 mu_error (_("Cannot drop non-root setuid privileges"));
186 rc = 1;
187 }
188
189 }
190
191 return rc;
192}
193
194
195static int
196translate_item (void *item, void *data)
197{
198 mu_list_t dst = data;
199 struct group *group = getgrnam (item);
200 if (!group)
201 {
202 mu_error (_("Unknown group: %s"), (char *) item);
203 return 1;
204 }
205 return mu_list_append (dst, (void *) group->gr_gid);
206}
207
208static int
209grouplist_translate (mu_list_t * pdst, mu_list_t src)
210{
211 mu_list_t dst;
212 int rc;
213
214 if (!src)
215 return 0;
216 rc = mu_list_create (&dst);
217 if (rc)
218 {
219 mu_error (_("%s: cannot create list: %s"),
220 "grouplist_translate", mu_strerror (rc));
221 return rc;
222 }
223 *pdst = dst;
224 return mu_list_do (src, translate_item, dst);
225}
226
227void
228mf_priv_setup (struct mf_privs *privs)
229{
230 struct passwd *pw;
231 mu_list_t grp = NULL;
232
233 if (!privs || !privs->user)
234 return;
235
236 pw = getpwnam (privs->user);
237 if (!pw)
238 {
239 mu_error (_("No such user: %s"), privs->user);
240 exit (EX_CONFIG);
241 }
242
243 grouplist_translate (&grp, privs->groups);
244 if (privs->allgroups && get_user_groups (&grp, privs->user))
245 exit (EX_CONFIG);
246 if (switch_to_privs (pw->pw_uid, pw->pw_gid, grp))
247 exit (EX_SOFTWARE);
248 mu_list_destroy (&grp);
249}
250
251
252void
253mf_epriv_setup (struct mf_privs *privs)
254{
255 uid_t uid;
256 gid_t gid;
257
258 if (privs)
259 {
260 struct passwd *pw;
261 if (!privs->user)
262 return;
263
264 pw = getpwnam (privs->user);
265 if (!pw)
266 {
267 mu_error (_("No such user: %s"), privs->user);
268 exit (EX_CONFIG);
269 }
270 uid = pw->pw_uid;
271 gid = pw->pw_gid;
272 }
273 else
274 {
275 uid = 0;
276 gid = 0;
277 }
278
279 if (setegid (gid))
280 {
281 mu_error (_("Cannot switch to EGID %lu: %s"),
282 (unsigned long) gid, mu_strerror (errno));
283 exit (EX_USAGE);
284 }
285 if (seteuid (uid))
286 {
287 mu_error (_("Cannot switch to EUID %lu: %s"),
288 (unsigned long) uid, mu_strerror (errno));
289 exit (EX_USAGE);
290 }
291}
diff --git a/src/Makefile.am b/src/Makefile.am
index 52648c8..c0c3b8a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,31 +1,38 @@
1# This file is part of mailfrom filter. 1# This file is part of Pies.
2# Copyright (C) 2008, 2009 Sergey Poznyakoff 2# Copyright (C) 2008, 2009 Sergey Poznyakoff
3# 3#
4# This program is free software; you can redistribute it and/or modify 4# Pies is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by 5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 3, or (at your option) 6# the Free Software Foundation; either version 3, or (at your option)
7# any later version. 7# any later version.
8# 8#
9# This program is distributed in the hope that it will be useful, 9# Pies is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of 10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details. 12# GNU General Public License for more details.
13# 13#
14# You should have received a copy of the GNU General Public License 14# You should have received a copy of the GNU General Public License
15# along with this program. If not, see <http://www.gnu.org/licenses/>. 15# along with Pies. If not, see <http://www.gnu.org/licenses/>. */
16 16
17sbin_PROGRAMS = pies 17sbin_PROGRAMS = pies
18 18
19pies_SOURCES = \ 19pies_SOURCES = \
20 acl.c\
21 addrfmt.c\
20 depmap.c\ 22 depmap.c\
23 diag.c\
21 limits.c\ 24 limits.c\
25 meta.c\
22 meta1gram.y\ 26 meta1gram.y\
23 meta1lex.l\ 27 meta1lex.l\
24 pies.c\ 28 pies.c\
25 progman.c\ 29 progman.c\
26 socket.c 30 socket.c\
31 url.c\
32 userprivs.c
27 33
28noinst_HEADERS = \ 34noinst_HEADERS = \
35 acl.h\
29 meta1gram.h\ 36 meta1gram.h\
30 meta1lex.h\ 37 meta1lex.h\
31 pies.h 38 pies.h
@@ -38,20 +45,25 @@ DISTCLEANFILES = pies.rc
38 45
39meta1lex.c: meta1gram.h 46meta1lex.c: meta1gram.h
40 47
48incdir=$(pkgdatadir)/$(VERSION)/include
49inc_DATA = pp-setup
50
41INCLUDES = \ 51INCLUDES = \
42 $(MAILUTILS_INCLUDES)\
43 $(MU_COMMON_INCLUDES)\
44 -I$(top_srcdir)/lib\ 52 -I$(top_srcdir)/lib\
45 -I$(top_srcdir)/gnu 53 -I$(top_srcdir)/gnu\
54 -I$(top_srcdir)/grecs/src
46 55
47LDADD = \ 56LDADD = \
48 ../lib/libmf.a\ 57 ../lib/libpies.a\
58 ../grecs/src/libgrecs.a\
49 ../gnu/libgnu.a\ 59 ../gnu/libgnu.a\
50 $(MAILUTILS_LIBS)\
51 $(MF_PROCTITLE_LIBS) 60 $(MF_PROCTITLE_LIBS)
52 61
53AM_CPPFLAGS=-DSYSCONFDIR=\"$(sysconfdir)\"\ 62AM_CPPFLAGS=-DSYSCONFDIR=\"$(sysconfdir)\"\
54 -DSTATEDIR=\"$(localstatedir)\" 63 -DSTATEDIR=\"$(localstatedir)\"\
64 -DDEFAULT_PREPROCESSOR="$(DEFAULT_PREPROCESSOR)"\
65 -DDEFAULT_VERSION_INCLUDE_DIR=\"$(incdir)\"\
66 -DDEFAULT_INCLUDE_DIR=\"$(pkgdatadir)/include\"
55 67
56AM_YFLAGS=-dvt -pmeta1 68AM_YFLAGS=-dvt -pmeta1
57AM_LFLAGS=-dvp -Pmeta1 -olex.yy.c 69AM_LFLAGS=-dvp -Pmeta1 -olex.yy.c
diff --git a/src/depmap.c b/src/depmap.c
index 76b492f..8a2772f 100644
--- a/src/depmap.c
+++ b/src/depmap.c
@@ -1,18 +1,18 @@
1/* This file is part of Mailfromd. 1/* This file is part of Pies.
2 Copyright (C) 2008 Sergey Poznyakoff 2 Copyright (C) 2008, 2009 Sergey Poznyakoff
3 3
4 This program is free software; you can redistribute it and/or modify it 4 Pies is free software; you can redistribute it and/or modify
5 under the terms of the GNU General Public License as published by the 5 it under the terms of the GNU General Public License as published by
6 Free Software Foundation; either version 3 of the License, or (at your 6 the Free Software Foundation; either version 3, or (at your option)
7 option) any later version. 7 any later version.
8 8
9 This program is distributed in the hope that it will be useful, 9 Pies is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details. 12 GNU General Public License for more details.
13 13
14 You should have received a copy of the GNU General Public License along 14 You should have received a copy of the GNU General Public License
15 with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 along with Pies. If not, see <http://www.gnu.org/licenses/>. */
16 16
17#include "pies.h" 17#include "pies.h"
18 18
diff --git a/src/limits.c b/src/limits.c
index 90d6459..3d430af 100644
--- a/src/limits.c
+++ b/src/limits.c
@@ -1,18 +1,18 @@
1/* This file is part of Mailfromd. 1/* This file is part of Pies.
2 Copyright (C) 2008 Sergey Poznyakoff 2 Copyright (C) 2008, 2009 Sergey Poznyakoff
3 3
4 This program is free software; you can redistribute it and/or modify 4 Pies is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option) 6 the Free Software Foundation; either version 3, or (at your option)
7 any later version. 7 any later version.
8 8
9 This program is distributed in the hope that it will be useful, 9 Pies is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details. 12 GNU General Public License for more details.
13 13
14 You should have received a copy of the GNU General Public License 14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 along with Pies. If not, see <http://www.gnu.org/licenses/>. */
16 16
17#include <pies.h> 17#include <pies.h>
18 18
@@ -50,15 +50,14 @@ do_set_limit (int rlimit, rlim_t limit)
50{ 50{
51 struct rlimit rlim; 51 struct rlimit rlim;
52 52
53 MU_DEBUG2 (pies_debug, MU_DEBUG_TRACE1, 53 debug (1, ("setting limit %d to %lu", rlimit, (unsigned long) limit));
54 "Setting limit %d to %lu\n", rlimit, (unsigned long) limit);
55 rlim.rlim_cur = limit; 54 rlim.rlim_cur = limit;
56 rlim.rlim_max = limit; 55 rlim.rlim_max = limit;
57 56
58 if (setrlimit(rlimit, &rlim)) 57 if (setrlimit(rlimit, &rlim))
59 { 58 {
60 mu_diag_output (MU_DIAG_NOTICE, _("error setting limit: %s"), 59 logmsg (LOG_NOTICE, _("error setting limit: %s"),
61 mu_strerror (errno)); 60 strerror (errno));
62 return 1; 61 return 1;
63 } 62 }
64 return 0; 63 return 0;
@@ -67,11 +66,11 @@ do_set_limit (int rlimit, rlim_t limit)
67static int 66static int
68set_prio (int prio) 67set_prio (int prio)
69{ 68{
70 MU_DEBUG1 (pies_debug, MU_DEBUG_TRACE2, "Setting priority to %d\n", prio); 69 debug (2, ("Setting priority to %d", prio));
71 if (setpriority (PRIO_PROCESS, 0, prio)) 70 if (setpriority (PRIO_PROCESS, 0, prio))
72 { 71 {
73 mu_diag_output (MU_DIAG_NOTICE, _("error setting priority: %s"), 72 logmsg (LOG_NOTICE, _("error setting priority: %s"),
74 mu_strerror (errno)); 73 strerror (errno));
75 return 1; 74 return 1;
76 } 75 }
77 return 0; 76 return 0;
@@ -81,7 +80,7 @@ set_prio (int prio)
81static int 80static int
82check_logins (const char *name, int limit) 81check_logins (const char *name, int limit)
83{ 82{
84 mu_diag_output (MU_DIAG_NOTICE, _("L limit is not implemented")); 83 logmsg (LOG_NOTICE, _("L limit is not implemented"));
85 return 0; 84 return 0;
86} 85}
87 86
@@ -93,7 +92,7 @@ set_limits (const char *name, struct limits_rec *lrec)
93 if (!lrec) 92 if (!lrec)
94 return 0; 93 return 0;
95 94
96 MU_DEBUG1 (pies_debug, MU_DEBUG_TRACE2, "Setting limits for %s\n", name); 95 debug (2, ("setting limits for %s", name));
97 96
98#if defined(RLIMIT_AS) 97#if defined(RLIMIT_AS)
99 if (lrec->set & SET_LIMIT_AS) 98 if (lrec->set & SET_LIMIT_AS)
diff --git a/src/meta1gram.y b/src/meta1gram.y
index 4966634..db92d61 100644
--- a/src/meta1gram.y
+++ b/src/meta1gram.y
@@ -1,6 +1,6 @@
1%{ 1%{
2/* MeTA1 configuration parser for Mailfromd. 2/* MeTA1 configuration parser for Pies.
3 Copyright (C) 2008 Sergey Poznyakoff 3 Copyright (C) 2008, 2009 Sergey Poznyakoff
4 4
5 This program is free software; you can redistribute it and/or modify 5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by 6 it under the terms of the GNU General Public License as published by
@@ -22,99 +22,98 @@
22#include "pies.h" 22#include "pies.h"
23#include "meta1lex.h" 23#include "meta1lex.h"
24 24
25/* FIXME: Use mu_opool_alloc? */ 25#define META1_QUEUE_DIR() \
26static mu_config_value_t * 26 (meta1_queue_dir ? meta1_queue_dir : "/var/spool/meta1")
27create_value (int type) 27
28enum meta1_stmt_type
29{
30 meta1_simple,
31 meta1_block
32};
33
34struct meta1_stmt
35{
36 struct meta1_stmt *next;
37 grecs_locus_t locus;
38 enum meta1_stmt_type type;
39 const char *ident;
40 union
41 {
42 grecs_value_t *value;
43 struct meta1_stmt *list;
44 } v;
45};
46
47struct meta1_stmt *
48meta1_stmt_create (enum meta1_stmt_type type, const char *ident)
28{ 49{
29 mu_config_value_t *val = mu_alloc (sizeof (*val)); 50 struct meta1_stmt *p = xmalloc (sizeof (*p));
30 val->type = type; 51 p->next = NULL;
31 return val; 52 p->type = type;
53 p->ident = ident;
54 p->locus = meta1_locus;
55 return p;
32} 56}
33 57
34static mu_config_value_t * 58static struct meta1_stmt *
35config_value_dup (mu_config_value_t *src) 59_reverse (struct meta1_stmt *list, struct meta1_stmt **root)
36{ 60{
37 if (!src) 61 struct meta1_stmt *next;
38 return NULL; 62
39 else 63 if (list->next == NULL)
40 { 64 {
41 mu_config_value_t *val = mu_alloc (sizeof (*val)); 65 *root = list;
42 *val = *src; 66 return list;
43 return val;
44 } 67 }
68 next = _reverse (list->next, root);
69 next->next = list;
70 list->next = NULL;
71 return list;
45} 72}
46 73
47static mu_cfg_node_t * 74static struct meta1_stmt *
48alloc_node (enum mu_cfg_node_type type, mu_cfg_locus_t *loc, 75reverse (struct meta1_stmt *in)
49 const char *tag, mu_config_value_t *label,
50 mu_cfg_node_t *node)
51{ 76{
52 char *p; 77 struct meta1_stmt *root;
53 mu_cfg_node_t *np; 78 if (!in)
54 size_t size = sizeof *np + strlen (tag) + 1; 79 return in;
55 np = mu_alloc (size); 80 _reverse (in, &root);
56 np->type = type; 81 return root;
57 np->locus = *loc;
58 p = (char*) (np + 1);
59 np->tag = p;
60 strcpy (p, tag);
61 np->label = label;
62 np->node = node;
63 np->next = NULL;
64 return np;
65} 82}
66 83
67static mu_cfg_node_t *translate_component (mu_cfg_node_t *); 84static void meta1_translate (struct meta1_stmt *);
68
69mu_cfg_node_t *meta1_parse_head;
70
71%} 85%}
72 86
73%union { 87%union {
74 mu_cfg_node_t node;
75 mu_cfg_node_t *pnode;
76 mu_config_value_t *value;
77 struct { mu_cfg_node_t *head, *tail; } nodelist;
78 char *string; 88 char *string;
79 unsigned long number; 89 gl_list_t list;
80 mu_list_t list; 90 grecs_value_t *value;
91 struct meta1_stmt *stmt;
81} 92}
82 93
83%token <string> META1_IDENT META1_STRING META1_NUMBER 94%token <string> META1_IDENT META1_STRING META1_NUMBER
84 95%type <list> slist values list
85%type <nodelist> stmtlist 96%type <value> value
86%type <pnode> stmt simple block
87%type <list> slist list values
88%type <string> string ident 97%type <string> string ident
89%type <value> value 98%type <stmt> stmtlist stmt simple block
90
91%% 99%%
92 100
93input : stmtlist 101input : stmtlist
94 { 102 {
95 mu_cfg_node_t *node; 103 struct meta1_stmt *stmt;
96 meta1_parse_head = NULL; 104 for (stmt = $1; stmt; stmt = stmt->next)
97 for (node = $1.head; node; node = node->next) 105 meta1_translate (stmt);
98 {
99 mu_cfg_node_t *new_node = translate_component (node);
100 if (new_node)
101 {
102 new_node->next = meta1_parse_head;
103 meta1_parse_head = new_node;
104 }
105 }
106 } 106 }
107 ; 107 ;
108 108
109stmtlist: stmt 109stmtlist: stmt
110 { 110 {
111 $$.head = $$.tail = $1; 111 $$ = $1;
112 } 112 }
113 | stmtlist stmt 113 | stmtlist stmt
114 { 114 {
115 $$ = $1; 115 $2->next = $1;
116 $$.tail->next = $2; 116 $$ = $2;
117 $$.tail = $2;
118 } 117 }
119 ; 118 ;
120 119
@@ -124,18 +123,15 @@ stmt : simple
124 123
125simple : ident '=' value opt_sc 124simple : ident '=' value opt_sc
126 { 125 {
127 $$ = alloc_node (mu_cfg_node_param, &meta1_locus, 126 $$ = meta1_stmt_create (meta1_simple, $1);
128 $1, $3, 127 $$->v.value = $3;
129 NULL);
130 } 128 }
131 ; 129 ;
132 130
133block : ident tag '{' stmtlist '}' opt_sc 131block : ident tag '{' stmtlist '}' opt_sc
134 { 132 {
135 /* FIXME: tag is currently ignored */ 133 $$ = meta1_stmt_create (meta1_block, $1);
136 $$ = alloc_node (mu_cfg_node_tag, &meta1_locus, 134 $$->v.list = reverse ($4);
137 $1, NULL,
138 $4.head);
139 } 135 }
140 ; 136 ;
141 137
@@ -148,49 +144,50 @@ ident : META1_IDENT
148 144
149value : string 145value : string
150 { 146 {
151 $$ = create_value (MU_CFG_STRING); 147 $$ = xmalloc (sizeof (*$$));
148 $$->type = GRECS_TYPE_STRING;
152 $$->v.string = $1; 149 $$->v.string = $1;
153 } 150 }
154 | list 151 | list
155 { 152 {
156 $$ = create_value (MU_CFG_LIST); 153 $$ = xmalloc (sizeof (*$$));
154 $$->type = GRECS_TYPE_LIST;
157 $$->v.list = $1; 155 $$->v.list = $1;
158 } 156 }
159 | META1_NUMBER 157 | META1_NUMBER
160 { 158 {
161 $$ = create_value (MU_CFG_STRING); 159 $$ = xmalloc (sizeof (*$$));
160 $$->type = GRECS_TYPE_STRING;
162 $$->v.string = $1; 161 $$->v.string = $1;
163 } 162 }
164 ; 163 ;
165 164
166string : META1_IDENT 165string : META1_IDENT
167 | slist 166 | slist
168 { 167 {
169 mu_iterator_t itr; 168 const void *p;
170 mu_list_get_iterator ($1, &itr); 169 gl_list_iterator_t itr = gl_list_iterator ($1);
171 170
172 meta1_line_begin (); 171 meta1_line_begin ();
173 for (mu_iterator_first (itr); 172 while (gl_list_iterator_next (&itr, &p, NULL))
174 !mu_iterator_is_done (itr); mu_iterator_next (itr)) 173 meta1_line_add (p, strlen (p));
175 { 174 gl_list_iterator_free (&itr);
176 char *p;
177 mu_iterator_current (itr, (void**)&p);
178 meta1_line_add (p, strlen (p));
179 }
180 $$ = meta1_line_finish (); 175 $$ = meta1_line_finish ();
181 mu_iterator_destroy (&itr);
182 mu_list_destroy (&$1);
183 } 176 }
184 ; 177 ;
185 178
186slist : META1_STRING 179slist : META1_STRING
187 { 180 {
188 mu_list_create (&$$); 181 $$ = gl_list_create_empty (&gl_linked_list_implementation,
189 mu_list_append ($$, $1); 182 NULL,
183 NULL,
184 NULL,
185 true);
186 gl_list_add_last ($$, $1);
190 } 187 }
191 | slist META1_STRING 188 | slist META1_STRING
192 { 189 {
193 mu_list_append ($1, $2); 190 gl_list_add_last ($1, $2);
194 $$ = $1; 191 $$ = $1;
195 } 192 }
196 ; 193 ;
@@ -207,12 +204,16 @@ list : '{' values '}'
207 204
208values : value 205values : value
209 { 206 {
210 mu_list_create (&$$); 207 $$ = gl_list_create_empty (&gl_linked_list_implementation,
211 mu_list_append ($$, $1); 208 NULL,
209 NULL,
210 NULL,
211 true);
212 gl_list_add_last ($$, $1);
212 } 213 }
213 | values ',' value 214 | values ',' value
214 { 215 {
215 mu_list_append ($1, $3); 216 gl_list_add_last ($1, $3);
216 $$ = $1; 217 $$ = $1;
217 } 218 }
218 ; 219 ;
@@ -232,19 +233,27 @@ yyerror (char *s)
232void 233void
233meta1_parser_set_debug () 234meta1_parser_set_debug ()
234{ 235{
235 mu_log_level_t lev = mu_global_debug_level ("meta1"); 236 char *p = getenv ("META1_DEBUG_YACC");
236 if (lev & MU_DEBUG_LEVEL_MASK (MU_DEBUG_TRACE6)) 237 yydebug = p && (*p - '0') > 0;
237 yydebug = 1;
238} 238}
239 239
240static struct meta1_stmt *
241find_stmt (struct meta1_stmt *stmt, const char *ident)
242{
243 for (; stmt; stmt = stmt->next)
244 if (strcmp (stmt->ident, ident) == 0)
245 break;
246 return stmt;
247}
248
249
240struct node_trans 250struct node_trans
241{ 251{
242 char *name; 252 char *name;
243 char *new_name; 253 char *new_name;
244 mu_cfg_node_t *(*fun) (const char *, mu_cfg_node_t *); 254 int (*xlat) (struct meta1_stmt *stmt, struct component *comp);
245}; 255};
246 256
247
248static struct node_trans * 257static struct node_trans *
249find_node_trans (struct node_trans *tab, const char *name) 258find_node_trans (struct node_trans *tab, const char *name)
250{ 259{
@@ -254,54 +263,43 @@ find_node_trans (struct node_trans *tab, const char *name)
254 return NULL; 263 return NULL;
255} 264}
256 265
257static mu_cfg_node_t * 266static int
258find_node (mu_cfg_node_t *list, const char *name) 267xlat_listen_socket (struct meta1_stmt *stmt, struct component *comp)
259{
260 for (; list; list = list->next)
261 {
262 if (strcmp (list->tag, name) == 0)
263 return list;
264 }
265 return NULL;
266}
267
268static mu_cfg_node_t *
269xlat_listen_socket (const char *name, mu_cfg_node_t *src)
270{ 268{
271 mu_cfg_node_t *p; 269 struct meta1_stmt *p;
272 mu_config_value_t *val; 270 grecs_value_t *val;
273 271
272 p = find_stmt (stmt->v.list, "type");
273 if (!p || !p->v.value || p->v.value->type != GRECS_TYPE_STRING)
274 return 1;
274 meta1_line_begin (); 275 meta1_line_begin ();
275 p = find_node (src->node, "type"); 276 meta1_line_add (p->v.value->v.string, strlen (p->v.value->v.string));
276 if (!p || !p->label || p->label->type != MU_CFG_STRING)
277 return NULL;
278 meta1_line_add (p->label->v.string, strlen (p->label->v.string));
279 meta1_line_add ("://", 3); 277 meta1_line_add ("://", 3);
280 if (strcmp (p->label->v.string, "inet") == 0) 278 if (strcmp (p->v.value->v.string, "inet") == 0)
281 { 279 {
282 const char *addr; 280 const char *addr;
283 p = find_node (src->node, "address"); 281 p = find_stmt (stmt->v.list, "address");
284 if (p) 282 if (p)
285 { 283 {
286 if (p->label->type != MU_CFG_STRING) 284 if (p->v.value->type != GRECS_TYPE_STRING)
287 return NULL; 285 return 1;
288 addr = p->label->v.string; 286 addr = p->v.value->v.string;
289 } 287 }
290 else 288 else
291 addr = "0.0.0.0"; 289 addr = "0.0.0.0";
292 meta1_line_add (addr, strlen (addr)); 290 meta1_line_add (addr, strlen (addr));
293 meta1_line_add (":", 1); 291 meta1_line_add (":", 1);
294 p = find_node (src->node, "port"); 292 p = find_stmt (stmt->v.list, "port");
295 if (p->label->type != MU_CFG_STRING) 293 if (p->v.value->type != GRECS_TYPE_STRING)
296 return NULL; 294 return 1;
297 meta1_line_add (p->label->v.string, strlen (p->label->v.string)); 295 meta1_line_add (p->v.value->v.string, strlen (p->v.value->v.string));
298 } 296 }
299 else if (strcmp (p->label->v.string, "unix") == 0) 297 else if (strcmp (p->v.value->v.string, "unix") == 0)
300 { 298 {
301 p = find_node (src->node, "path"); 299 p = find_stmt (stmt->v.list, "path");
302 if (!p || p->label->type != MU_CFG_STRING) 300 if (!p || p->v.value->type != GRECS_TYPE_STRING)
303 return NULL; 301 return 1;
304 meta1_line_add (p->label->v.string, strlen (p->label->v.string)); 302 meta1_line_add (p->v.value->v.string, strlen (p->v.value->v.string));
305 /* FIXME: Other substatements: 303 /* FIXME: Other substatements:
306 listen_socket { 304 listen_socket {
307 type=unix; 305 type=unix;
@@ -312,11 +310,15 @@ xlat_listen_socket (const char *name, mu_cfg_node_t *src)
312 } 310 }
313 */ 311 */
314 } 312 }
315 val = create_value (MU_CFG_STRING); 313 val = xmalloc (sizeof (*val));
314 val->type = GRECS_TYPE_STRING;
316 val->v.string = meta1_line_finish (); 315 val->v.string = meta1_line_finish ();
317 return alloc_node (mu_cfg_node_param, &src->locus, "socket", val, NULL); 316 stmt->type = meta1_simple;
317 stmt->v.value = val;
318 return 0;
318} 319}
319 320
321
320static struct node_trans root_node_trans[] = { 322static struct node_trans root_node_trans[] = {
321 { "listen_socket", "socket", xlat_listen_socket }, 323 { "listen_socket", "socket", xlat_listen_socket },
322 { "start_action", "mode" }, 324 { "start_action", "mode" },
@@ -328,112 +330,45 @@ static struct node_trans root_node_trans[] = {
328 { NULL } 330 { NULL }
329}; 331};
330 332
331static mu_cfg_node_t * 333static void
332create_string_node (const char *tag, const char *str, mu_cfg_locus_t *locus) 334meta1_translate_stmt (struct meta1_stmt *stmt, struct component *comp)
333{ 335{
334 mu_config_value_t *val = create_value (MU_CFG_STRING); 336 struct grecs_keyword *kwp;
335 337
336 val->v.string = meta1_string (str, strlen (str)); 338 struct node_trans *nt = find_node_trans (root_node_trans, stmt->ident);
337 return alloc_node (mu_cfg_node_param, locus, tag, val, NULL); 339 if (!nt)
338} 340 return;
339
340static mu_cfg_node_t *
341create_redir_node (const char *tag, const char *dir,
342 const char *name, mu_cfg_locus_t *locus)
343{
344 mu_config_value_t *val = create_value (MU_CFG_ARRAY);
345 val->v.arg.c = 2;
346 val->v.arg.v = mu_alloc (2 * sizeof (val->v.arg.v[0]));
347 341
348 val->v.arg.v[1].type = MU_CFG_STRING; 342 kwp = find_component_keyword (nt->new_name);
349 val->v.arg.v[0].v.string = meta1_string ("file", 4); 343 if (!kwp)
344 abort ();
350 345
351 val->v.arg.v[1].type = MU_CFG_STRING; 346 if (nt->xlat && nt->xlat (stmt, comp))
352 meta1_line_begin (); 347 return;
353 meta1_line_add (dir, strlen (dir));
354 meta1_line_add ("/", 1);
355 meta1_line_add (name, strlen (name));
356 meta1_line_add (".log", 4);
357 val->v.arg.v[1].v.string = meta1_line_finish ();
358 348
359 return alloc_node (mu_cfg_node_param, locus, tag, val, NULL); 349 grecs_process_ident (kwp, stmt->v.value, comp, &stmt->locus);
360} 350}
361 351
362static mu_cfg_node_t * 352static void
363translate_node (mu_cfg_node_t *src) 353meta1_translate (struct meta1_stmt *stmt)
364{ 354{
365 mu_cfg_node_t *dst = NULL; 355 struct component *comp;
366 struct node_trans *nt = find_node_trans (root_node_trans, src->tag); 356 struct meta1_stmt *p;
367 357
368 if (nt) 358 if (stmt->type != meta1_block)
369 { 359 return;
370 if (nt->fun)
371 dst = nt->fun (nt->new_name, src);
372 else
373 dst = alloc_node (mu_cfg_node_param, &src->locus,
374 nt->new_name, config_value_dup (src->label),
375 NULL);
376 }
377 return dst;
378}
379
380#define META1_QUEUE_DIR() \
381 (meta1_queue_dir ? meta1_queue_dir : "/var/spool/meta1")
382
383static mu_cfg_node_t *
384translate_node_list (mu_cfg_node_t *src, const char *name)
385{
386 mu_cfg_node_t *head = NULL, *tail = NULL;
387 mu_cfg_locus_t *locus = &src->locus;
388 360
389 for (; src; src = src->next) 361 comp = component_create (stmt->ident);
390 { 362 for (p = stmt->v.list; p; p = p->next)
391 mu_cfg_node_t *dst = translate_node (src);
392 if (dst)
393 {
394 if (tail)
395 tail->next = dst;
396 else
397 head = dst;
398 tail = dst;
399 }
400 }
401 if (head)
402 { 363 {
403 /* Add common statements: */ 364 meta1_translate_stmt (p, comp);
404 mu_cfg_node_t *node;
405
406 node = create_string_node ("allgroups", "yes", locus);
407 tail->next = node;
408 tail = node;
409
410 node = create_string_node ("chdir", META1_QUEUE_DIR (), locus);
411 tail->next = node;
412 tail = node;
413
414 node = create_redir_node ("stderr", META1_QUEUE_DIR (), name, locus);
415 tail->next = node;
416 tail = node;
417
418 node = create_string_node ("settle-timeout", "1", locus);
419 tail->next = node;
420 tail = node;
421 } 365 }
422 return head; 366 comp->privs.allgroups = 1;
367 comp->dir = META1_QUEUE_DIR ();
368 comp->settle_timeout = 1;
369 comp->redir[RETR_ERR].type = redir_file;
370 comp->redir[RETR_ERR].v.file = xasprintf ("%s/%s.log",
371 META1_QUEUE_DIR (),
372 comp->tag);
373 component_finish (comp, &stmt->locus);
423} 374}
424
425static mu_cfg_node_t *
426translate_component (mu_cfg_node_t *src)
427{
428 mu_cfg_node_t *dst = NULL;
429 if (src->type == mu_cfg_node_tag)
430 {
431 mu_config_value_t *val = create_value (MU_CFG_STRING);
432 val->v.string = meta1_string (src->tag, strlen (src->tag));
433 dst = alloc_node (mu_cfg_node_tag, &src->locus,
434 "component", val,
435 translate_node_list (src->node, val->v.string));
436 }
437 return dst;
438}
439
diff --git a/src/meta1lex.h b/src/meta1lex.h
index 8db32f9..035204b 100644
--- a/src/meta1lex.h
+++ b/src/meta1lex.h
@@ -1,23 +1,21 @@
1/* This file is part of Mailfromd. 1/* This file is part of Pies.
2 Copyright (C) 2008 Sergey Poznyakoff 2 Copyright (C) 2009, 2009 Sergey Poznyakoff
3 3
4 This program is free software; you can redistribute it and/or modify 4 Pies is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option) 6 the Free Software Foundation; either version 3, or (at your option)
7 any later version. 7 any later version.
8 8
9 This program is distributed in the hope that it will be useful, 9 Pies is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details. 12 GNU General Public License for more details.
13 13
14 You should have received a copy of the GNU General Public License 14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 along with Pies. If not, see <http://www.gnu.org/licenses/>. */
16 16
17extern mu_cfg_locus_t meta1_locus; 17extern grecs_locus_t meta1_locus;
18extern size_t meta1_error_count; 18extern size_t meta1_error_count;
19extern mu_cfg_node_t *meta1_parse_head;
20extern mu_cfg_tree_t *meta1_parse_tree;
21extern char *meta1_queue_dir; 19extern char *meta1_queue_dir;
22 20
23char *meta1_string (const char *str, size_t len); 21char *meta1_string (const char *str, size_t len);
diff --git a/src/meta1lex.l b/src/meta1lex.l
index 312a1fd..0f08d87 100644
--- a/src/meta1lex.l
+++ b/src/meta1lex.l
@@ -1,6 +1,6 @@
1%{ 1%{
2/* MeTA1 configuration lexer for Mailfromd. 2/* MeTA1 configuration lexer for Pies.
3 Copyright (C) 2008 Sergey Poznyakoff 3 Copyright (C) 2008, 2009 Sergey Poznyakoff
4 4
5 This program is free software; you can redistribute it and/or modify 5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by 6 it under the terms of the GNU General Public License as published by
@@ -22,9 +22,10 @@
22#include "meta1gram.h" 22#include "meta1gram.h"
23#include "meta1lex.h" 23#include "meta1lex.h"
24 24
25mu_cfg_locus_t meta1_locus; 25grecs_locus_t meta1_locus;
26size_t meta1_error_count; 26size_t meta1_error_count;
27mu_opool_t meta1_pool; 27struct obstack meta1_stk;
28int meta1_stk_init;
28char *meta1_queue_dir; 29char *meta1_queue_dir;
29 30
30#define yylval meta1lval 31#define yylval meta1lval
@@ -98,7 +99,22 @@ yywrap ()
98void 99void
99meta1_line_add (const char *text, size_t len) 100meta1_line_add (const char *text, size_t len)
100{ 101{
101 mu_opool_append (meta1_pool, text, len); 102 obstack_grow (&meta1_stk, text, len);
103}
104
105static char quote_transtab[] = "\\\\\"\"a\ab\bf\fn\nr\rt\tv\v";
106
107static int
108unescape_char (int c)
109{
110 char *p;
111
112 for (p = quote_transtab; *p; p += 2)
113 {
114 if (*p == c)
115 return p[1];
116 }
117 return c;
102} 118}
103 119
104static void 120static void
@@ -110,17 +126,17 @@ unescape_to_line (int c)
110 t = '\v'; 126 t = '\v';
111 else 127 else
112 { 128 {
113 t = mu_argcv_unquote_char (c); 129 t = unescape_char (c);
114 if (t == c && t != '\\' && t != '\"') 130 if (t == c && t != '\\' && t != '\"')
115 meta1_parse_error (_("unknown escape sequence '\\%c'"), c); 131 meta1_parse_error (_("unknown escape sequence '\\%c'"), c);
116 } 132 }
117 mu_opool_append_char (meta1_pool, t); 133 obstack_1grow (&meta1_stk, t);
118} 134}
119 135
120void 136void
121meta1_line_add_unescape_last (const char *text, size_t len) 137meta1_line_add_unescape_last (const char *text, size_t len)
122{ 138{
123 mu_opool_append (meta1_pool, text, len - 2); 139 obstack_grow (&meta1_stk, text, len - 2);
124 unescape_to_line (text[len - 1]); 140 unescape_to_line (text[len - 1]);
125} 141}
126 142
@@ -129,24 +145,25 @@ meta1_line_add_unescape_hex (const char *text, size_t len)
129{ 145{
130 for (; text[len-1] != 'x' && len > 0; len--) 146 for (; text[len-1] != 'x' && len > 0; len--)
131 ; 147 ;
132 mu_opool_append (meta1_pool, text, len - 2); 148 obstack_grow (&meta1_stk, text, len - 2);
133 mu_opool_append_char (meta1_pool, (char) strtoul (text + len, NULL, 16)); 149 obstack_1grow (&meta1_stk, (char) strtoul (text + len, NULL, 16));
134} 150}
135 151
136void 152void
137meta1_line_begin () 153meta1_line_begin ()
138{ 154{
139 if (!meta1_pool) 155 if (!meta1_stk_init)
140 mu_opool_create (&meta1_pool, 1); 156 {
141 else 157 obstack_init (&meta1_stk);
142 mu_opool_clear (meta1_pool); 158 meta1_stk_init = 1;
159 }
143} 160}
144 161
145char * 162char *
146meta1_line_finish () 163meta1_line_finish ()
147{ 164{
148 mu_opool_append_char (meta1_pool, 0); 165 obstack_1grow (&meta1_stk, 0);
149 return mu_opool_finish (meta1_pool, NULL); 166 return obstack_finish (&meta1_stk);
150} 167}
151 168
152char * 169char *
@@ -161,34 +178,23 @@ void
161meta1_parse_error (const char *fmt, ...) 178meta1_parse_error (const char *fmt, ...)
162{ 179{
163 va_list ap; 180 va_list ap;
164 mu_debug_t debug;
165 181
166 mu_diag_get_debug (&debug); 182 logmsg_printf (LOG_ERR, "%s:%lu: ", meta1_locus.file,
167 mu_debug_printf (debug, 0, "%s:%lu: ", meta1_locus.file,
168 (unsigned long) meta1_locus.line); 183 (unsigned long) meta1_locus.line);
169 va_start (ap, fmt); 184 va_start (ap, fmt);
170 mu_debug_vprintf (debug, 0, fmt, ap); 185 logmsg_vprintf (LOG_ERR, fmt, ap);
171 mu_debug_printf (debug, 0, "\n");
172 va_end (ap); 186 va_end (ap);
187 logmsg_printf (LOG_ERR, "\n");
173 meta1_error_count++; 188 meta1_error_count++;
174} 189}
175 190
176void 191void
177meta1_lexer_set_debug () 192meta1_lexer_set_debug ()
178{ 193{
179 mu_log_level_t lev = mu_global_debug_level ("meta1"); 194 char *p = getenv ("META1_DEBUG_LEX");
180 yy_flex_debug = (lev & MU_DEBUG_LEVEL_MASK (MU_DEBUG_TRACE7)); 195 yy_flex_debug = p && (*p - '0') > 0;
181} 196}
182 197
183static int
184_cfg_default_printer (void *unused, mu_log_level_t level, const char *str)
185{
186 fprintf (stderr, "%s", str);
187 return 0;
188}
189
190mu_cfg_tree_t *meta1_parse_tree;
191
192/* Parse MeTA1 configuration file `name'. Populate `meta1_parse_tree' with 198/* Parse MeTA1 configuration file `name'. Populate `meta1_parse_tree' with
193 the parse tree. */ 199 the parse tree. */
194int 200int
@@ -200,7 +206,8 @@ meta1_config_parse (const char *name)
200 fp = fopen (name, "r"); 206 fp = fopen (name, "r");
201 if (!fp) 207 if (!fp)
202 { 208 {
203 mu_error (_("%s: cannot open file: %s"), name, mu_strerror (errno)); 209 logmsg (LOG_ERR,
210 _("%s: cannot open file: %s"), name, strerror (errno));
204 return 1; 211 return 1;
205 } 212 }
206 meta1_locus.file = meta1_string (name, strlen (name)); 213 meta1_locus.file = meta1_string (name, strlen (name));
@@ -213,16 +220,6 @@ meta1_config_parse (const char *name)
213 fclose (fp); 220 fclose (fp);
214 if (meta1_error_count) 221 if (meta1_error_count)
215 rc = 1; 222 rc = 1;
216 if (rc == 0)
217 {
218 meta1_parse_tree = mu_alloc (sizeof (*meta1_parse_tree));
219 mu_debug_create (&meta1_parse_tree->debug, NULL);
220 mu_debug_set_print (meta1_parse_tree->debug, _cfg_default_printer, NULL);
221 mu_debug_set_level (meta1_parse_tree->debug,
222 mu_global_debug_level ("meta1"));
223 meta1_parse_tree->node = meta1_parse_head;
224 meta1_parse_tree->pool = meta1_pool;
225 }
226 return rc; 223 return rc;
227} 224}
228 225
diff --git a/src/pies.c b/src/pies.c
index 10862c2..f36c21f 100644
--- a/src/pies.c
+++ b/src/pies.c
@@ -1,27 +1,29 @@
1/* This file is part of Mailfromd. 1/* This file is part of Pies.
2 Copyright (C) 2008, 2009 Sergey Poznyakoff 2 Copyright (C) 2008, 2009 Sergey Poznyakoff
3 3
4 This program is free software; you can redistribute it and/or modify 4 Pies is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option) 6 the Free Software Foundation; either version 3, or (at your option)
7 any later version. 7 any later version.
8 8
9 This program is distributed in the hope that it will be useful, 9 Pies is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details. 12 GNU General Public License for more details.
13 13
14 You should have received a copy of the GNU General Public License 14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 along with Pies. If not, see <http://www.gnu.org/licenses/>. */
16 16
17#include "pies.h" 17#include "pies.h"
18#include "meta1lex.h" 18#include "meta1lex.h"
19 19
20int log_to_stderr; /* Use stderr for logging */ 20char *conffile = SYSCONFDIR "/pies.conf";
21char *log_tag; /* override mu_log_tag */ 21int preprocess_only; /* Preprocess config, do nothing more */
22mu_log_level_t debug_level; 22int lint_mode; /* Test configuration syntax and exit */
23mu_debug_t pies_debug; 23int log_to_stderr; /* Use stderr for logging */
24struct mf_privs pies_privs; 24int log_facility = LOG_USER;
25char *log_tag;
26struct pies_privs pies_privs;
25int foreground; 27int foreground;
26int command; 28int command;
27char *pidfile = STATEDIR "/pies.pid"; 29char *pidfile = STATEDIR "/pies.pid";
@@ -29,34 +31,21 @@ char *ctlfile = STATEDIR "/pies.ctl";
29char *statfile = STATEDIR "/pies.stat"; 31char *statfile = STATEDIR "/pies.stat";
30mode_t pies_umask = 0; 32mode_t pies_umask = 0;
31unsigned long shutdown_timeout = 5; 33unsigned long shutdown_timeout = 5;
32mu_acl_t pies_acl; 34pies_acl_t pies_acl;
33limits_record_t pies_limits; 35limits_record_t pies_limits;
34int force_option; 36int force_option;
35
36 37
38
37/* Logging */ 39/* Logging */
38void 40void
39log_setup (int want_stderr) 41log_setup (int want_stderr)
40{ 42{
41 mu_debug_t debug;
42
43 mu_diag_get_debug (&debug);
44
45 if (log_tag)
46 mu_log_tag = log_tag;
47
48 if (!want_stderr) 43 if (!want_stderr)
49 { 44 openlog (log_tag, LOG_PID, log_facility);
50 openlog (MU_LOG_TAG (), LOG_PID, mu_log_facility);
51 mu_debug_set_print (debug, mu_diag_syslog_printer, NULL);
52 mu_debug_default_printer = mu_debug_syslog_printer;
53 }
54 else
55 mu_debug_default_printer = mu_debug_stderr_printer;
56} 45}
57 46
58static int 47static int
59stderr_closed_p() 48stderr_closed_p ()
60{ 49{
61 int fd = dup (0); 50 int fd = dup (0);
62 if (fd < 0) 51 if (fd < 0)
@@ -64,77 +53,90 @@ stderr_closed_p()
64 close (fd); 53 close (fd);
65 return fd <= 2; 54 return fd <= 2;
66} 55}
67
68 56
69static int 57
70_cb_action (mu_debug_t debug, void *data, mu_config_value_t *arg) 58int
59assert_grecs_value_type (grecs_locus_t * locus,
60 const grecs_value_t * value, int type)
71{ 61{
72 enum return_action *pact = data; 62 if (!value || value->type != type)
73 static struct mu_kwd actab[] = {
74 { "disable", action_disable },
75 { "restart", action_restart },
76 { NULL }
77 };
78 int res;
79
80 if (mu_cfg_assert_value_type (arg, MU_CFG_STRING, debug))
81 return 1;
82 if (mu_kwd_xlat_name (actab, arg->v.string, &res))
83 { 63 {
84 mu_cfg_format_error (debug, MU_DEBUG_ERROR, 64 grecs_error (locus, 0, _("expected %s, but found %s"),
85 _("unknown action code: %s"), arg); 65 grecs_data_type_string (type),
86 return 0; 66 grecs_data_type_string (value->type));
67 return 1;
87 } 68 }
88 *pact = res;
89 return 0; 69 return 0;
90} 70}
91 71
72int
73assert_scalar_stmt (grecs_locus_t * locus, enum grecs_callback_command cmd)
74{
75 if (cmd != grecs_callback_set_value)
76 {
77 grecs_error (locus, 0, _("Unexpected block statement"));
78 return 1;
79 }
80 return 0;
81}
82
83
92static int 84static int
93_cb_notify_addr (mu_debug_t debug, void *data, mu_config_value_t *arg) 85_cb_action (enum grecs_callback_command cmd,
86 grecs_locus_t * locus,
87 void *varptr, grecs_value_t * value, void *cb_data)
94{ 88{
95 mu_address_t *paddr = data; 89 enum return_action *pact = varptr;
96 mu_address_t addr; 90 static struct tokendef actab[] = {
97 int rc; 91 {"disable", action_disable},
92 {"restart", action_restart},
93 {NULL}
94 };
95 int res;
98 96
99 if (mu_cfg_assert_value_type (arg, MU_CFG_STRING, debug)) 97 if (assert_scalar_stmt (locus, cmd)
98 || assert_grecs_value_type (locus, value, GRECS_TYPE_STRING))
100 return 1; 99 return 1;
101 rc = mu_address_create (&addr, arg->v.string); 100 if (strtotok (actab, value->v.string, &res))
102 if (rc)
103 mu_cfg_format_error (debug, MU_DEBUG_ERROR,
104 _("%s: invalid e-mail address: %s"),
105 arg->v.string, mu_strerror (rc));
106 if (*paddr)
107 { 101 {
108 mu_address_union (paddr, addr); 102 grecs_error (locus, 0, _("unknown action code: %s"), value->v.string);
109 mu_address_destroy (&addr); 103 return 1;
110 } 104 }
111 else 105 *pact = res;
112 *paddr = addr;
113 return 0; 106 return 0;
114} 107}
115 108
116struct mu_cfg_param return_code_cfg_param[] = { 109struct grecs_keyword return_code_cfg_param[] = {
117 { "action", mu_cfg_callback, NULL, 110 {"action",
118 mu_offsetof (struct component, act_temp.act), _cb_action, 111 /* TRANSLATORS: disable and restart are keywords, do not translate them. */
119 N_("Specifies action to take when a component finishes with this " 112 N_("arg: {disable | restart}"),
120 "return code."), 113 N_("Specifies action to take when a component finishes with this "
121 /* TRANSLATORS: disable and restart are keywords, do not translate them. */ 114 "return code."),
122 N_("arg: {disable | restart}") }, 115 grecs_type_string, NULL, offsetof (struct component, act_temp.act),
123 { "notify", mu_cfg_callback, NULL, 116 _cb_action,
124 mu_offsetof (struct component, act_temp.addr), _cb_notify_addr, 117 },
125 N_("Notify this address when then component terminates."), 118 {"notify",
126 N_("arg: email-list") }, 119 N_("arg: emails"),
127 { "message", mu_cfg_string, NULL, 120 N_("Notify this address when then component terminates."),
128 mu_offsetof (struct component, act_temp.message), NULL, 121 grecs_type_string, NULL, offsetof (struct component, act_temp.addr)
129 N_("Notification message text (with headers).") }, 122 },
130 { "exec", mu_cfg_string, NULL, 123 {"message",
131 mu_offsetof (struct component, act_temp.command), NULL, 124 NULL,
132 N_("Execute this command.") }, 125 N_("Notification message text (with headers)."),
133 { NULL } 126 grecs_type_string, NULL, offsetof (struct component, act_temp.message),
127 NULL},
128 {"exec",
129 NULL,
130 N_("Execute this command."),
131 grecs_type_string, NULL,
132 offsetof (struct component, act_temp.command),
133 NULL,
134 },
135 {NULL}
134}; 136};
135 137
136#define S(s) { #s, s } 138#define S(s) { #s, s }
137static struct mu_kwd ex_kwtab[] = { 139static struct tokendef ex_tokendef[] = {
138 S (EX_OK), 140 S (EX_OK),
139 S (EX_USAGE), 141 S (EX_USAGE),
140 S (EX_DATAERR), 142 S (EX_DATAERR),
@@ -151,39 +153,39 @@ static struct mu_kwd ex_kwtab[] = {
151 S (EX_PROTOCOL), 153 S (EX_PROTOCOL),
152 S (EX_NOPERM), 154 S (EX_NOPERM),
153 S (EX_CONFIG), 155 S (EX_CONFIG),
154 { NULL } 156 {NULL}
155}; 157};
156 158
157static struct mu_kwd sig_kwtab[] = { 159static struct tokendef sig_tokendef[] = {
158 S (SIGHUP), 160 S (SIGHUP),
159 S (SIGINT), 161 S (SIGINT),
160 S (SIGQUIT), 162 S (SIGQUIT),
161 S (SIGILL), 163 S (SIGILL),
162 S (SIGTRAP), 164 S (SIGTRAP),
163 S (SIGABRT), 165 S (SIGABRT),
164 S (SIGIOT), 166 S (SIGIOT),
165 S (SIGBUS), 167 S (SIGBUS),
166 S (SIGFPE), 168 S (SIGFPE),
167 S (SIGKILL), 169 S (SIGKILL),
168 S (SIGUSR1), 170 S (SIGUSR1),
169 S (SIGSEGV), 171 S (SIGSEGV),
170 S (SIGUSR2), 172 S (SIGUSR2),
171 S (SIGPIPE), 173 S (SIGPIPE),
172 S (SIGALRM), 174 S (SIGALRM),
173 S (SIGTERM), 175 S (SIGTERM),
174#ifdef SIGSTKFLT 176#ifdef SIGSTKFLT
175 S (SIGSTKFLT), 177 S (SIGSTKFLT),
176#endif 178#endif
177 S (SIGCHLD), 179 S (SIGCHLD),
178 S (SIGCONT), 180 S (SIGCONT),
179 S (SIGSTOP), 181 S (SIGSTOP),
180 S (SIGTSTP), 182 S (SIGTSTP),
181 S (SIGTTIN), 183 S (SIGTTIN),
182 S (SIGTTOU), 184 S (SIGTTOU),
183#ifdef SIGURG 185#ifdef SIGURG
184 S (SIGURG), 186 S (SIGURG),
185#endif 187#endif
186#ifdef SIGXCPU 188#ifdef SIGXCPU
187 S (SIGXCPU), 189 S (SIGXCPU),
188#endif 190#endif
189#ifdef SIGXFSZ 191#ifdef SIGXFSZ
@@ -210,14 +212,16 @@ static struct mu_kwd sig_kwtab[] = {
210#ifdef SIGSYS 212#ifdef SIGSYS
211 S (SIGSYS), 213 S (SIGSYS),
212#endif 214#endif
213 { NULL } 215 {NULL}
214}; 216};
217
215#undef S 218#undef S
216 219
217static struct action * 220static struct action *
218create_action(struct component *comp, 221create_action (struct component *comp,
219 mu_debug_t debug, mu_config_value_t *val, int argc, 222 grecs_locus_t * locus,
220 const char *(*getarg) (mu_config_value_t *, int, mu_debug_t)) 223 grecs_value_t * val, int argc,
224 const char *(*getarg) (grecs_value_t *, int, grecs_locus_t *))
221{ 225{
222 int i; 226 int i;
223 unsigned *retv; 227 unsigned *retv;
@@ -226,24 +230,23 @@ create_action(struct component *comp,
226 struct action *act; 230 struct action *act;
227 231
228 retv = xcalloc (argc, sizeof *retv); 232 retv = xcalloc (argc, sizeof *retv);
229 if (argc == 0 || (argc == 1 && strcmp (getarg(val, 0, debug), "*") == 0)) 233 if (argc == 0 || (argc == 1 && strcmp (getarg (val, 0, locus), "*") == 0))
230 allflag = 1; 234 allflag = 1;
231 else 235 else
232 { 236 {
233 for (i = 0; i < argc; i++) 237 for (i = 0; i < argc; i++)
234 { 238 {
235 unsigned n; 239 unsigned n;
236 const char *arg = getarg(val, i, debug); 240 const char *arg = getarg (val, i, locus);
237 size_t len = strlen (arg); 241 size_t len = strlen (arg);
238 242
239 if (isdigit (arg[0])) 243 if (isdigit (arg[0]))
240 { 244 {
241 char *p; 245 char *p;
242 n = strtoul (arg, &p, 0); 246 n = strtoul (arg, &p, 0);
243 if (*p) 247 if (*p)
244 { 248 {
245 mu_cfg_format_error (debug, MU_DEBUG_ERROR, 249 grecs_error (locus, 0, _("%s: not a number"), p);
246 _("%s: not a number"), p);
247 continue; 250 continue;
248 } 251 }
249 } 252 }
@@ -255,26 +258,23 @@ create_action(struct component *comp,
255 n = strtoul (arg + 4, &p, 0); 258 n = strtoul (arg + 4, &p, 0);
256 if (*p) 259 if (*p)
257 { 260 {
258 mu_cfg_format_error (debug, MU_DEBUG_ERROR, 261 grecs_error (locus, 0, _("%s: not a number"), p);
259 _("%s: not a number"), p);
260 continue; 262 continue;
261 } 263 }
262 } 264 }
263 else if (mu_kwd_xlat_name_ci (sig_kwtab, arg, &n)) 265 else if (strtotok_ci (sig_tokendef, arg, &n))
264 { 266 {
265 mu_cfg_format_error (debug, MU_DEBUG_ERROR, 267 grecs_error (locus, 0, _("%s: not a signal code"), arg);
266 _("%s: not a signal code"), arg);
267 continue; 268 continue;
268 } 269 }
269 n |= STATUS_SIG_BIT; 270 n |= STATUS_SIG_BIT;
270 } 271 }
271 else if (mu_kwd_xlat_name_ci (ex_kwtab, arg, &n)) 272 else if (strtotok_ci (ex_tokendef, arg, &n))
272 { 273 {
273 mu_cfg_format_error (debug, MU_DEBUG_ERROR, 274 grecs_error (locus, 0, _("%s: not a return code"), arg);
274 _("%s: not a return code"), arg);
275 continue; 275 continue;
276 } 276 }
277 277
278 /* Alles in ordnung */ 278 /* Alles in ordnung */
279 retv[retc++] = n; 279 retv[retc++] = n;
280 } 280 }
@@ -301,7 +301,7 @@ create_action(struct component *comp,
301} 301}
302 302
303const char * 303const char *
304_get_string_arg (mu_config_value_t *val, int num, mu_debug_t debug) 304_get_string_arg (grecs_value_t * val, int num, grecs_locus_t * locus)
305{ 305{
306 if (num != 0) 306 if (num != 0)
307 return NULL; 307 return NULL;
@@ -309,128 +309,130 @@ _get_string_arg (mu_config_value_t *val, int num, mu_debug_t debug)
309} 309}
310 310
311const char * 311const char *
312_get_array_arg (mu_config_value_t *val, int num, mu_debug_t debug) 312_get_array_arg (grecs_value_t * val, int num, grecs_locus_t * locus)
313{ 313{
314 if (num < val->v.arg.c) 314 if (num < val->v.arg.c)
315 { 315 {
316 if (mu_cfg_assert_value_type (&val->v.arg.v[num], MU_CFG_STRING, 316 if (assert_grecs_value_type (locus, val, GRECS_TYPE_STRING) == 0)
317 debug) == 0)
318 return val->v.arg.v[num].v.string; 317 return val->v.arg.v[num].v.string;
319 } 318 }
320 return NULL; 319 return NULL;
321} 320}
322 321
323const char * 322const char *
324_get_list_arg (mu_config_value_t *val, int num, mu_debug_t debug) 323_get_list_arg (grecs_value_t * val, int num, grecs_locus_t * locus)
325{ 324{
326 mu_config_value_t *elt; 325 grecs_value_t *elt = (grecs_value_t *) gl_list_get_at (val->v.list, num);
327 int rc = mu_list_get (val->v.list, num, (void**)&elt); 326 if (!elt)
328 if (rc)
329 { 327 {
330 mu_cfg_format_error (debug, MU_DEBUG_ERROR, 328 grecs_error (locus, 0, _("cannot get list item"));
331 _("cannot get list item: %s"),
332 mu_strerror (rc));
333 } 329 }
334 else if (mu_cfg_assert_value_type (elt, MU_CFG_STRING, debug) == 0) 330 else if (assert_grecs_value_type (locus, elt, GRECS_TYPE_STRING) == 0)
335 return elt->v.string; 331 return elt->v.string;
336 return NULL; 332 return NULL;
337} 333}
338 334
339static int 335static int
340return_code_section_parser (enum mu_cfg_section_stage stage, 336return_code_section_parser (enum grecs_callback_command cmd,
341 const mu_cfg_node_t *node, 337 grecs_locus_t * locus,
342 const char *section_label, void **section_data, 338 void *varptr,
343 void *call_data, 339 grecs_value_t * value, void *cb_data)
344 mu_cfg_tree_t *tree)
345{ 340{
346 struct component *comp = *section_data; 341 struct component *comp = varptr;
347 size_t count; 342 size_t count;
348 struct action *act; 343 struct action *act;
349 344
350 if (!node->label) 345 switch (cmd)
351 {
352 mu_cfg_format_error (tree->debug, MU_DEBUG_ERROR, _("missing tag"));
353 return 1;
354 }
355
356 switch (stage)
357 { 346 {
358 case mu_cfg_section_start: 347 case grecs_callback_section_begin:
359 switch (node->label->type) 348 if (!value)
360 { 349 {
361 case MU_CFG_STRING: 350 grecs_error (locus, 0, _("missing tag"));
362 act = create_action (comp, tree->debug, node->label, 351 return 1;
363 1, 352 }
364 _get_string_arg); 353
354 switch (value->type)
355 {
356 case GRECS_TYPE_STRING:
357 act = create_action (comp, locus, value, 1, _get_string_arg);
365 break; 358 break;
366 359
367 case MU_CFG_ARRAY: 360 case GRECS_TYPE_ARRAY:
368 act = create_action (comp, tree->debug, node->label, 361 act = create_action (comp, locus, value,
369 node->label->v.arg.c, 362 value->v.arg.c, _get_array_arg);
370 _get_array_arg);
371 break; 363 break;
372 364
373 case MU_CFG_LIST: 365 case GRECS_TYPE_LIST:
374 mu_list_count (node->label->v.list, &count); 366 count = gl_list_size (value->v.list);
375 act = create_action (comp, tree->debug, node->label, 367 act = create_action (comp, locus, value, count, _get_list_arg);
376 count,
377 _get_list_arg);
378 } 368 }
379 369 *(struct component **) cb_data = comp;
380 if (!act) 370 if (!act)
381 return 1; 371 return 1;
382 memset (&comp->act_temp, 0, sizeof (comp->act_temp)); 372 memset (&comp->act_temp, 0, sizeof (comp->act_temp));
383 break; 373 break;
384 374
385 case mu_cfg_section_end: 375 case grecs_callback_section_end:
386 act = comp->act_tail; 376 act = comp->act_tail;
387 act->act = comp->act_temp.act; 377 act->act = comp->act_temp.act;
388 act->addr = comp->act_temp.addr; 378 act->addr = comp->act_temp.addr;
389 act->message = comp->act_temp.message; 379 act->message = comp->act_temp.message;
390 act->command = comp->act_temp.command; 380 act->command = comp->act_temp.command;
391 break; 381 break;
382
383 case grecs_callback_set_value:
384 grecs_error (locus, 0, _("invalid use of block statement"));
392 } 385 }
393 return 0; 386 return 0;
394} 387}
395 388
396void 389static char **
397return_code_cfg_init () 390config_array_to_argv (grecs_value_t *val, grecs_locus_t *locus)
398{ 391{
399 struct mu_cfg_section *section; 392 int i, j;
400 393 int argc;
401 if (mu_create_canned_section ("return-code", &section)) 394 char **argv;
402 exit (EX_SOFTWARE); 395
403 section->parser = return_code_section_parser; 396 argc = val->v.arg.c;
404 section->label = N_("<tag: exit-code-list>"); 397 argv = xcalloc (argc + 1, sizeof (argv[0]));
405 mu_cfg_section_add_params (section, return_code_cfg_param); 398 for (i = j = 0; i < argc; i++)
399 {
400 if (assert_grecs_value_type (locus, &val->v.arg.v[i], GRECS_TYPE_STRING)
401 == 0)
402 argv[j++] = xstrdup (val->v.arg.v[i].v.string);
403 }
404 argv[j] = NULL;
405 return argv;
406} 406}
407 407
408static int 408static int
409_cb_command (mu_debug_t debug, void *data, mu_config_value_t *val) 409_cb_command (enum grecs_callback_command cmd,
410 grecs_locus_t * locus,
411 void *varptr, grecs_value_t * value, void *cb_data)
410{ 412{
411 int argc; 413 int argc;
412 char **argv, ***pargv = data; 414 char **argv, ***pargv = varptr;
413 int rc; 415 struct wordsplit ws;
414 416
415 switch (val->type) 417 switch (value->type)
416 { 418 {
417 case MU_CFG_STRING: 419 case GRECS_TYPE_STRING:
418 rc = mu_argcv_get (val->v.string, "", NULL, &argc, &argv); 420 if (wordsplit (value->v.string, &ws, WRDSF_DEFFLAGS))
419 if (rc)
420 { 421 {
421 mu_cfg_format_error (debug, MU_DEBUG_ERROR, 422 grecs_error (locus, 0, "wordsplit: %s", strerror (errno));
422 "mu_argcv_get: %s", mu_strerror (rc));
423 return 1; 423 return 1;
424 } 424 }
425 argc = ws.ws_wordc;
426 argv = ws.ws_wordv;
427 ws.ws_wordv = NULL;
425 break; 428 break;
426 429
427 case MU_CFG_ARRAY: 430 case GRECS_TYPE_ARRAY:
428 argv = config_array_to_argv (val, debug); 431 argv = config_array_to_argv (value, locus);
429 break; 432 break;
430 433
431 case MU_CFG_LIST: 434 case GRECS_TYPE_LIST:
432 mu_cfg_format_error (debug, MU_DEBUG_ERROR, 435 grecs_error (locus, 0, _("unexpected list"));
433 _("unexpected list"));
434 return 1; 436 return 1;
435 } 437 }
436 *pargv = argv; 438 *pargv = argv;
@@ -438,19 +440,21 @@ _cb_command (mu_debug_t debug, void *data, mu_config_value_t *val)
438} 440}
439 441
440static int 442static int
441_cb_umask (mu_debug_t debug, void *data, mu_config_value_t *arg) 443_cb_umask (enum grecs_callback_command cmd,
444 grecs_locus_t * locus,
445 void *varptr, grecs_value_t * value, void *cb_data)
442{ 446{
443 mode_t *pmode = data; 447 mode_t *pmode = varptr;
444 char *p; 448 char *p;
445 unsigned long n; 449 unsigned long n;
446 450
447 if (mu_cfg_assert_value_type (arg, MU_CFG_STRING, debug)) 451 if (assert_scalar_stmt (locus, cmd)
452 || assert_grecs_value_type (locus, value, GRECS_TYPE_STRING))
448 return 1; 453 return 1;
449 n = strtoul (arg->v.string, &p, 8); 454 n = strtoul (value->v.string, &p, 8);
450 if (*p) 455 if (*p)
451 { 456 {
452 mu_cfg_format_error (debug, MU_DEBUG_ERROR, 457 grecs_error (locus, 0, _("invalid octal number"));
453 _("invalid octal number"));
454 return 1; 458 return 1;
455 } 459 }
456 *pmode = n; 460 *pmode = n;
@@ -458,310 +462,434 @@ _cb_umask (mu_debug_t debug, void *data, mu_config_value_t *arg)
458} 462}
459 463
460static int 464static int
461_cb_env (mu_debug_t debug, void *data, mu_config_value_t *val) 465_cb_env (enum grecs_callback_command cmd,
466 grecs_locus_t * locus,
467 void *varptr, grecs_value_t * value, void *cb_data)
462{ 468{
463 int rc;
464 int argc; 469 int argc;
465 char **argv; 470 char **argv;
466 char ***penv = data; 471 char ***penv = varptr;
467 472 struct wordsplit ws;
468 switch (val->type) 473
474 switch (value->type)
469 { 475 {
470 case MU_CFG_STRING: 476 case GRECS_TYPE_STRING:
471 rc = mu_argcv_get_np (val->v.string, strlen (val->v.string), "", 477 if (wordsplit (value->v.string, &ws, WRDSF_DEFFLAGS))
472 NULL, 0, &argc, &argv, NULL);
473 if (rc)
474 { 478 {
475 mu_cfg_format_error (debug, MU_DEBUG_ERROR, 479 grecs_error (locus, 0, "wordsplit: %s", strerror (errno));
476 "mu_argcv_get: %s", mu_strerror (rc));
477 return 1; 480 return 1;
478 } 481 }
482 argc = ws.ws_wordc;
483 argv = ws.ws_wordv;
484 ws.ws_wordv = NULL;
479 break; 485 break;
480 486
481 case MU_CFG_ARRAY: 487 case GRECS_TYPE_ARRAY:
482 argv = config_array_to_argv (val, debug); 488 argv = config_array_to_argv (value, locus);
483 break; 489 break;
484 490
485 case MU_CFG_LIST: 491 case GRECS_TYPE_LIST:
486 mu_cfg_format_error (debug, MU_DEBUG_ERROR, _("unexpected list")); 492 grecs_error (locus, 0, _("unexpected list"));
487 return 1; 493 return 1;
488 } 494 }
489 495
490 *penv = argv; 496 *penv = argv;
491 return 0; 497 return 0;
492} 498}
499
500
501int
502string_to_syslog_priority (const char *key, int *pres)
503{
504 static struct tokendef tokdef_prio[] = {
505 {"EMERG", LOG_EMERG},
506 {"ALERT", LOG_ALERT},
507 {"CRIT", LOG_CRIT},
508 {"ERR", LOG_ERR},
509 {"WARNING", LOG_WARNING},
510 {"NOTICE", LOG_NOTICE},
511 {"INFO", LOG_INFO},
512 {"DEBUG", LOG_DEBUG},
513 {NULL}
514 };
515
516 return strtotok_ci (tokdef_prio, key, pres);
517}
518
519int
520string_to_syslog_facility (const char *key, int *pres)
521{
522 static struct tokendef tokdef_fac[] = {
523 {"auth", LOG_AUTH},
524 {"authpriv", LOG_AUTHPRIV},
525 {"cron", LOG_CRON},
526 {"daemon", LOG_DAEMON},
527 {"ftp", LOG_FTP},
528 {"kern", LOG_KERN},
529 {"lpr", LOG_LPR},
530 {"mail", LOG_MAIL},
531 {"news", LOG_NEWS},
532 {"syslog", LOG_SYSLOG},
533 {"user", LOG_USER},
534 {"uucp", LOG_UUCP},
535 {"local0", LOG_LOCAL0},
536 {"local1", LOG_LOCAL1},
537 {"local2", LOG_LOCAL2},
538 {"local3", LOG_LOCAL3},
539 {"local4", LOG_LOCAL4},
540 {"local5", LOG_LOCAL5},
541 {"local6", LOG_LOCAL6},
542 {"local7", LOG_LOCAL7},
543 {NULL}
544 };
545
546 return strtotok_ci (tokdef_fac, key, pres);
547}
493 548
494static int 549static int
495_cb_facility (mu_debug_t debug, void *data, mu_config_value_t *val) 550cb_syslog_facility (enum grecs_callback_command cmd,
551 grecs_locus_t * locus,
552 void *varptr, grecs_value_t * value, void *cb_data)
496{ 553{
497 if (mu_cfg_assert_value_type (val, MU_CFG_STRING, debug)) 554 const char *str;
555
556 if (assert_grecs_value_type (locus, value, GRECS_TYPE_STRING))
498 return 1; 557 return 1;
499 558 str = value->v.string;
500 if (mu_string_to_syslog_facility (val->v.string, data)) 559 if (c_isdigit (str[0]))
501 { 560 {
502 mu_cfg_format_error (debug, MU_DEBUG_ERROR, 561 char *p;
503 _("unknown syslog facility `%s'"), 562 int n = strtoul (str, &p, 10);
504 val->v.string); 563 if (*p)
505 return 1; 564 grecs_error (locus, 0,
565 _("expected facility number or symbolic name"));
566 else
567 *(int *) varptr = n;
506 } 568 }
507 return 0; 569 else if (string_to_syslog_facility (str, varptr))
570 grecs_error (locus, 0, _("unknown syslog facility `%s'"), str);
571 return 0;
508} 572}
509 573
510static int 574static int
511_cb_redir (mu_debug_t debug, void *data, mu_config_value_t *arg) 575_cb_redir (enum grecs_callback_command cmd,
576 grecs_locus_t * locus,
577 void *varptr, grecs_value_t * value, void *cb_data)
512{ 578{
513 struct redirector *rp = data; 579 struct redirector *rp = varptr;
514 static struct mu_kwd redirtab[] = { 580 static struct tokendef redirtab[] = {
515 { "null", redir_null }, 581 {"null", redir_null},
516 { "syslog", redir_syslog }, 582 {"syslog", redir_syslog},
517 { "file", redir_file }, 583 {"file", redir_file},
518 { NULL } 584 {NULL}
519 }; 585 };
520 int res; 586 int res;
521 587
522 switch (arg->type) 588 switch (value->type)
523 { 589 {
524 case MU_CFG_STRING: 590 case GRECS_TYPE_STRING:
525 if (strcmp (arg->v.string, "null") == 0) 591 if (strcmp (value->v.string, "null") == 0)
526 { 592 {
527 rp->type = redir_null; 593 rp->type = redir_null;
528 break; 594 break;
529 } 595 }
530 rp->type = redir_syslog; 596 rp->type = redir_syslog;
531 if (mu_string_to_syslog_priority (arg->v.string, &rp->v.prio)) 597 if (string_to_syslog_priority (value->v.string, &rp->v.prio))
532 { 598 {
533 mu_cfg_format_error (debug, MU_DEBUG_ERROR, 599 grecs_error (locus, 0, _("unknown syslog priority `%s'"),
534 _("unknown syslog priority `%s'"), 600 value->v.string);
535 arg);
536 return 0; 601 return 0;
537 } 602 }
538 break; 603 break;
539 604
540 case MU_CFG_ARRAY: 605 case GRECS_TYPE_ARRAY:
541 if (mu_cfg_assert_value_type (&arg->v.arg.v[0], MU_CFG_STRING, debug)) 606 if (assert_grecs_value_type (locus, &value->v.arg.v[0],
607 GRECS_TYPE_STRING))
542 return 0; 608 return 0;
543 if (mu_kwd_xlat_name (redirtab, arg->v.arg.v[0].v.string, &res)) 609 if (strtotok (redirtab, value->v.arg.v[0].v.string, &res))
544 mu_cfg_format_error (debug, MU_DEBUG_ERROR, 610 grecs_error (locus, 0, _("%s: unrecognised redirector type"),
545 _("%s: unrecognised redirector type"), 611 value->v.arg.v[0].v.string);
546 arg->v.arg.v[0].v.string);
547 else 612 else
548 { 613 {
549 if (res != redir_null) 614 if (res != redir_null)
550 { 615 {
551 if (arg->v.arg.c != 2) 616 if (value->v.arg.c != 2)
552 { 617 {
553 mu_cfg_format_error (debug, MU_DEBUG_ERROR, 618 grecs_error (locus, 0, _("wrong number of arguments"));
554 _("wrong number of arguments"));
555 return 0; 619 return 0;
556 } 620 }
557 if (mu_cfg_assert_value_type (&arg->v.arg.v[1], MU_CFG_STRING, 621 if (assert_grecs_value_type (locus, &value->v.arg.v[1],
558 debug)) 622 GRECS_TYPE_STRING))
559 return 0; 623 return 0;
560 624
561 switch (res) 625 switch (res)
562 { 626 {
563 case redir_null: 627 case redir_null:
564 break; 628 break;
565 629
566 case redir_syslog: 630 case redir_syslog:
567 if (mu_string_to_syslog_priority (arg->v.arg.v[1].v.string, 631 if (string_to_syslog_priority (value->v.arg.v[1].v.string,
568 &rp->v.prio)) 632 &rp->v.prio))
569 { 633 {
570 mu_cfg_format_error (debug, MU_DEBUG_ERROR, 634 grecs_error (locus, 0,
571 _("unknown syslog priority `%s'"), 635 _("unknown syslog priority `%s'"),
572 arg->v.arg.v[1].v.string); 636 value->v.arg.v[1].v.string);
573 return 0; 637 return 0;
574 } 638 }
575 break; 639 break;
576 640
577 case redir_file: 641 case redir_file:
578 rp->v.file = xstrdup (arg->v.arg.v[1].v.string); 642 rp->v.file = xstrdup (value->v.arg.v[1].v.string);
579 break; 643 break;
580 } 644 }
581 } 645 }
582 rp->type = res; 646 rp->type = res;
583 } 647 }
584 break; 648 break;
585 649
586 default: 650 default:
587 mu_cfg_format_error (debug, MU_DEBUG_ERROR, _("unexpected list")); 651 grecs_error (locus, 0, _("unexpected list"));
588 } 652 }
589 653
590 return 0; 654 return 0;
591} 655}
592 656
593static int 657static int
594_cb_url (mu_debug_t debug, void *data, mu_config_value_t *arg) 658_cb_url (enum grecs_callback_command cmd,
659 grecs_locus_t * locus,
660 void *varptr, grecs_value_t * value, void *cb_data)
595{ 661{
596 int rc; 662 struct pies_url *url;
597 mu_url_t url; 663
598 664 if (assert_scalar_stmt (locus, cmd)
599 if (mu_cfg_assert_value_type (arg, MU_CFG_STRING, debug)) 665 || assert_grecs_value_type (locus, value, GRECS_TYPE_STRING))
600 return 1; 666 return 1;
601 rc = mu_url_create (&url, arg->v.string); 667 if (pies_url_create (&url, value->v.string))
602 if (rc)
603 { 668 {
604 mu_cfg_format_error (debug, MU_DEBUG_ERROR, 669 grecs_error (locus, 0, _("%s: cannot create URL: %s"),
605 _("%s: cannot create URL: %s"), 670 value->v.string, strerror (errno));
606 arg->v.string,
607 mu_strerror (rc));
608 return 0; 671 return 0;
609 } 672 }
610 rc = mu_url_parse (url); 673 *(struct pies_url **) varptr = url;
611 if (rc)
612 {
613 mu_cfg_format_error (debug, MU_DEBUG_ERROR,
614 _("%s: cannot parse URL: %s"),
615 arg->v.string,
616 mu_strerror (rc));
617 mu_url_destroy (&url);
618 return 0;
619 }
620 *(mu_url_t*) data = url;
621 return 0; 674 return 0;
622} 675}
623 676
624static struct mu_kwd modetab[] = { 677static struct tokendef modetab[] = {
625 { "exec", pies_comp_exec }, 678 {"exec", pies_comp_exec},
626 { "wait", pies_comp_exec }, 679 {"wait", pies_comp_exec},
627 { "accept", pies_comp_accept }, 680 {"accept", pies_comp_accept},
628 { "inetd", pies_comp_inetd }, 681 {"inetd", pies_comp_inetd},
629 { "nostartaccept", pies_comp_inetd }, 682 {"nostartaccept", pies_comp_inetd},
630 { "pass-fd", pies_comp_pass_fd }, 683 {"pass-fd", pies_comp_pass_fd},
631 { "pass", pies_comp_pass_fd }, 684 {"pass", pies_comp_pass_fd},
632 { NULL } 685 {NULL}
633}; 686};
634 687
635static int 688static int
636_cb_mode (mu_debug_t debug, void *data, mu_config_value_t *arg) 689_cb_mode (enum grecs_callback_command cmd,
690 grecs_locus_t * locus,
691 void *varptr, grecs_value_t * value, void *cb_data)
637{ 692{
638 int res; 693 int res;
639 694
640 if (mu_cfg_assert_value_type (arg, MU_CFG_STRING, debug)) 695 if (assert_scalar_stmt (locus, cmd)
696 || assert_grecs_value_type (locus, value, GRECS_TYPE_STRING))
641 return 1; 697 return 1;
642 if (mu_kwd_xlat_name (modetab, arg->v.string, &res)) 698 if (strtotok (modetab, value->v.string, &res))
643 mu_cfg_format_error (debug, MU_DEBUG_ERROR, 699 grecs_error (locus, 0, _("%s: unrecognised mode"), value->v.string);
644 _("%s: unrecognised mode"),
645 arg->v.string);
646 else 700 else
647 *(enum pies_comp_mode *)data = res; 701 *(enum pies_comp_mode *) varptr = res;
648 return 0; 702 return 0;
649} 703}
650 704
651static int 705static int
652_cb_limits (mu_debug_t debug, void *data, mu_config_value_t *arg) 706_cb_limits (enum grecs_callback_command cmd,
707 grecs_locus_t * locus,
708 void *varptr, grecs_value_t * value, void *cb_data)
653{ 709{
654 limits_record_t *plrec = data; 710 limits_record_t *plrec = varptr;
655 char *p; 711 char *p;
656 712
657 if (mu_cfg_assert_value_type (arg, MU_CFG_STRING, debug)) 713 if (assert_scalar_stmt (locus, cmd)
714 || assert_grecs_value_type (locus, value, GRECS_TYPE_STRING))
658 return 1; 715 return 1;
659 if (parse_limits (plrec, (char*) arg->v.string, &p)) 716 if (parse_limits (plrec, (char *) value->v.string, &p))
660 mu_cfg_format_error (debug, MU_DEBUG_ERROR, 717 grecs_error (locus, 0, _("invalid limit string (near %s)"), p);
661 _("invalid limit string (near %s)"),
662 p);
663 return 0; 718 return 0;
664} 719}
665 720
666struct mu_cfg_param component_cfg_param[] = { 721struct grecs_keyword component_cfg_param[] = {
667 { "mode", mu_cfg_callback, NULL, 722 {"mode",
668 mu_offsetof (struct component, mode), _cb_mode, 723 /* TRANSLATORS: The words between '{' and '}' are keywords, do not
669 N_("Component execution mode."), 724 translate them. */
670 /* TRANSLATORS: The words between '{' and '}' are keywords, do not 725 N_
671 translate them. */ 726 ("mode: {exec | wait | accept | inetd | nostartaccept | pass-fd | pass}"),
672 N_("mode: {exec | wait | accept | inetd | nostartaccept | pass-fd | pass}") 727 N_("Component execution mode."),
673 }, 728 grecs_type_string, NULL, offsetof (struct component, mode),
674 { "program", mu_cfg_string, NULL, 729 _cb_mode,
675 mu_offsetof (struct component, program), NULL, 730 },
676 N_("Full name of the program.") }, 731 {"program",
677 { "command", mu_cfg_callback, NULL, 732 NULL,
678 mu_offsetof (struct component, argv), _cb_command, 733 N_("Full name of the program."),
679 N_("Command line.") }, 734 grecs_type_string, NULL,
680 { "prerequisites", MU_CFG_LIST_OF(mu_cfg_string), NULL, 735 offsetof (struct component, program),
681 mu_offsetof (struct component, prereq), NULL, 736 NULL,
682 N_("List of prerequisites."), 737 },
683 N_("list") }, 738 {"command",
684 { "dependents", MU_CFG_LIST_OF(mu_cfg_string), NULL, 739 NULL,
685 mu_offsetof (struct component, depend), NULL, 740 N_("Command line."),
686 N_("List of components for which this one is a prerequisite."), 741 grecs_type_string, NULL, offsetof (struct component, argv),
687 N_("list") }, 742 _cb_command,
688 { "disable", mu_cfg_bool, NULL, 743 },
689 mu_offsetof (struct component, disabled), NULL, 744 {"prerequisites",
690 N_("Disable this entry.") }, 745 N_("list"),
691 { "settle-timeout", mu_cfg_uint, NULL, 746 N_("List of prerequisites."),
692 mu_offsetof (struct component, settle_timeout), NULL, 747 grecs_type_string | GRECS_LIST, NULL, offsetof (struct component, prereq),
693 N_("Time to wait before starting this component.") }, 748 NULL,
694 { "precious", mu_cfg_bool, NULL, 749 },
695 mu_offsetof (struct component, precious), NULL, 750 {"dependents",
696 N_("Mark this entry as precious.") }, 751 N_("list"),
697 { "socket", mu_cfg_callback, NULL, 752 N_("List of components for which this one is a prerequisite."),
698 mu_offsetof (struct component, socket_url), _cb_url, 753 grecs_type_string | GRECS_LIST, NULL, offsetof (struct component, depend),
699 N_("Listen on the given url."), 754 NULL,
700 N_("url: string") }, 755 },
701 { "pass-fd-socket", mu_cfg_string, NULL, 756 {"disable",
702 mu_offsetof (struct component, pass_fd_socket), NULL, 757 NULL,
703 N_("Pass fd through this socket."), 758 N_("Disable this entry."),
704 N_("name") }, 759 grecs_type_bool, NULL, offsetof (struct component, disabled),
705 { "acl", mu_cfg_section, NULL, mu_offsetof (struct component, acl), NULL, 760 NULL,
706 N_("Per-component access control list") }, 761 },
707 { "remove-file", mu_cfg_string, NULL, 762 {"settle-timeout",
708 mu_offsetof (struct component, rmfile), NULL, 763 NULL,
709 N_("Remove file before starting the component."), 764 N_("Time to wait before starting this component."),
710 N_("file") }, 765 grecs_type_uint, NULL,
711 { "facility", mu_cfg_callback, NULL, 766 offsetof (struct component, settle_timeout),
712 mu_offsetof (struct component, facility), _cb_facility, 767 NULL,
713 N_("Override default syslog facility for this component."), 768 },
714 N_("arg") }, 769 {"precious",
715 { "stdout", mu_cfg_callback, NULL, 770 NULL,
716 mu_offsetof (struct component, redir[RETR_OUT]), _cb_redir, 771 N_("Mark this entry as precious."),
717 N_("Redirect program's standard output to the given file or " 772 grecs_type_bool, NULL,
718 "syslog priority."), 773 offsetof (struct component, precious),
719 /* TRANSLATORS: file and syslog are keywords. Do not translate them. */ 774 NULL,
720 N_("type: {file | syslog}> <channel: string") 775 },
721 }, 776 {"socket",
722 { "stderr", mu_cfg_callback, NULL, 777 N_("url: string"),
723 mu_offsetof (struct component, redir[RETR_ERR]), _cb_redir, 778 N_("Listen on the given url."),
724 N_("Redirect program's standard error to the given file or " 779 grecs_type_string, NULL,
725 "syslog priority."), 780 offsetof (struct component, socket_url),
726 /* TRANSLATORS: file and syslog are keywords. Do not translate them. */ 781 _cb_url,
727 N_("type: {file | syslog}> <channel: string") 782 },
728 }, 783 {"pass-fd-socket",
729 { "user", mu_cfg_string, NULL, 784 N_("name"),
730 mu_offsetof (struct component, privs.user), NULL, 785 N_("Pass fd through this socket."),
731 N_("Run with this user privileges.") }, 786 grecs_type_string, NULL,
732 { "group", MU_CFG_LIST_OF(mu_cfg_string), NULL, 787 offsetof (struct component, pass_fd_socket),
733 mu_offsetof (struct component, privs.groups), NULL, 788 NULL,
734 N_("Retain supplementary group.") }, 789 },
735 { "allgroups", mu_cfg_bool, NULL, 790 {"acl",
736 mu_offsetof (struct component, privs.allgroups), NULL, 791 N_("name: string"),
737 N_("Retain all supplementary groups of which user is a member.") }, 792 N_("Define ACL."),
738 { "umask", mu_cfg_callback, NULL, 793 grecs_type_section, NULL, 0,
739 mu_offsetof (struct component, umask), _cb_umask, 794 acl_section_parser, NULL, acl_keywords},
740 N_("Force this umask."), 795 {"remove-file",
741 N_("arg: number") }, 796 N_("file"),
742 { "limits", mu_cfg_callback, NULL, 797 N_("Remove file before starting the component."),
743 mu_offsetof (struct component, limits), _cb_limits, 798 grecs_type_string, NULL, offsetof (struct component, rmfile),
744 N_("Set system limits") }, 799 NULL,
745 { "env", mu_cfg_callback, NULL, 800 },
746 mu_offsetof (struct component, env), _cb_env, 801 {"facility",
747 N_("Set program environment. Argument is a list of assignments " 802 N_("arg"),
748 "separated by white space."), 803 N_("Override default syslog facility for this component."),
749 N_("arg: list") }, 804 grecs_type_string, NULL, offsetof (struct component, facility),
750 { "chdir", mu_cfg_string, NULL, 805 cb_syslog_facility,
751 mu_offsetof (struct component, dir), NULL, 806 },
752 N_("Change to this directory before executing the component."), 807 {"stdout",
753 N_("dir") }, 808 /* TRANSLATORS: file and syslog are keywords. Do not translate them. */
754 { "return-code", mu_cfg_section }, 809 N_("type: {file | syslog}> <channel: string"),
755 { NULL } 810 N_("Redirect program's standard output to the given file or "
811 "syslog priority."),
812 grecs_type_string, NULL, offsetof (struct component, redir[RETR_OUT]),
813 _cb_redir,
814 },
815 {"stderr",
816 /* TRANSLATORS: file and syslog are keywords. Do not translate them. */
817 N_("type: {file | syslog}> <channel: string"),
818 N_("Redirect program's standard error to the given file or "
819 "syslog priority."),
820 grecs_type_string, NULL, offsetof (struct component, redir[RETR_ERR]),
821 _cb_redir,
822 },
823 {"user",
824 NULL,
825 N_("Run with this user privileges."),
826 grecs_type_string, NULL, offsetof (struct component, privs.user),
827 NULL,
828 },
829 {"group",
830 NULL,
831 N_("Retain supplementary group."),
832 grecs_type_string | GRECS_LIST, NULL, offsetof (struct component,
833 privs.groups),
834 NULL,
835 },
836 {"allgroups",
837 NULL,
838 N_("Retain all supplementary groups of which user is a member."),
839 grecs_type_bool, NULL, offsetof (struct component, privs.allgroups),
840 NULL,
841 },
842 {"umask",
843 N_("arg: number"),
844 N_("Force this umask."),
845 grecs_type_string, NULL, offsetof (struct component, umask),
846 _cb_umask,
847 },
848 {"limits",
849 NULL,
850 N_("Set system limits"),
851 grecs_type_string, NULL, offsetof (struct component, limits),
852 _cb_limits,
853 },
854 {"env",
855 N_("arg: list"),
856 N_("Set program environment. Argument is a list of assignments "
857 "separated by white space."),
858 grecs_type_string, NULL, offsetof (struct component, env),
859 _cb_env,
860 },
861 {"chdir",
862 N_("dir"),
863 N_("Change to this directory before executing the component."),
864 grecs_type_string, NULL, offsetof (struct component, dir),
865 NULL,
866 },
867 {"return-code",
868 N_("<tag: exit-code-list>"),
869 NULL, /* FIXME: Docstring? */
870 grecs_type_section, NULL, 0,
871 return_code_section_parser, NULL, return_code_cfg_param},
872 {NULL}
756}; 873};
757 874
875struct grecs_keyword *
876find_component_keyword (const char *ident)
877{
878 struct grecs_keyword *kwp;
879
880 for (kwp = component_cfg_param; kwp->ident; kwp++)
881 if (strcmp (kwp->ident, ident) == 0)
882 return kwp;
883 return NULL;
884}
885
758static char * 886static char *
759make_full_name (const char *dir, const char *file) 887make_full_name (const char *dir, const char *file)
760{ 888{
761 char *p; 889 char *p;
762 size_t len = strlen (dir); 890 size_t len = strlen (dir);
763 891
764 while (len > 0 && dir[len-1] == '/') 892 while (len > 0 && dir[len - 1] == '/')
765 len--; 893 len--;
766 p = xmalloc (len + 1 + strlen (file) + 1); 894 p = xmalloc (len + 1 + strlen (file) + 1);
767 memcpy (p, dir, len); 895 memcpy (p, dir, len);
@@ -771,7 +899,7 @@ make_full_name (const char *dir, const char *file)
771} 899}
772 900
773static int 901static int
774component_verify (struct component *comp, mu_debug_t debug) 902component_verify (struct component *comp, grecs_locus_t * locus)
775{ 903{
776 int header = 0; 904 int header = 0;
777 int i; 905 int i;
@@ -780,14 +908,13 @@ component_verify (struct component *comp, mu_debug_t debug)
780 { \ 908 { \
781 if (!header) \ 909 if (!header) \
782 { \ 910 { \
783 mu_cfg_format_error (debug, MU_DEBUG_ERROR, \ 911 grecs_error (locus, 0, _("in component %s:"), comp->tag); \
784 _("in component %s:"), comp->tag); \
785 header = 1; \ 912 header = 1; \
786 } \ 913 } \
787 mu_cfg_format_error (debug, MU_DEBUG_ERROR, fmt, arg); \ 914 grecs_error (locus, 0, fmt, arg); \
788 } \ 915 } \
789 while (0) 916 while (0)
790 917
791 if (!comp->argv) 918 if (!comp->argv)
792 COMPERR ("%s", _("missing command line")); 919 COMPERR ("%s", _("missing command line"));
793 if (comp->pass_fd_socket && comp->mode != pies_comp_pass_fd) 920 if (comp->pass_fd_socket && comp->mode != pies_comp_pass_fd)
@@ -795,10 +922,10 @@ component_verify (struct component *comp, mu_debug_t debug)
795 switch (comp->mode) 922 switch (comp->mode)
796 { 923 {
797 case pies_comp_exec: 924 case pies_comp_exec:
798 if (comp->socket_url) 925 if (comp->socket_url)
799 COMPERR ("%s", _("socket ignored: wrong mode")); 926 COMPERR ("%s", _("socket ignored: wrong mode"));
800 break; 927 break;
801 928
802 case pies_comp_pass_fd: 929 case pies_comp_pass_fd:
803 if (!comp->pass_fd_socket) 930 if (!comp->pass_fd_socket)
804 COMPERR ("%s", _("must supply pass-fd-socket in this mode")); 931 COMPERR ("%s", _("must supply pass-fd-socket in this mode"));
@@ -807,7 +934,7 @@ component_verify (struct component *comp, mu_debug_t debug)
807 if (comp->dir) 934 if (comp->dir)
808 { 935 {
809 char *p = make_full_name (comp->dir, comp->pass_fd_socket); 936 char *p = make_full_name (comp->dir, comp->pass_fd_socket);
810 free (comp->pass_fd_socket); 937 //free (comp->pass_fd_socket);
811 comp->pass_fd_socket = p; 938 comp->pass_fd_socket = p;
812 } 939 }
813 else 940 else
@@ -815,7 +942,7 @@ component_verify (struct component *comp, mu_debug_t debug)
815 "file name or chdir must be specified")); 942 "file name or chdir must be specified"));
816 } 943 }
817 /* Fall through */ 944 /* Fall through */
818 945
819 case pies_comp_accept: 946 case pies_comp_accept:
820 case pies_comp_inetd: 947 case pies_comp_inetd:
821 if (!comp->socket_url) 948 if (!comp->socket_url)
@@ -825,7 +952,7 @@ component_verify (struct component *comp, mu_debug_t debug)
825 return 1; 952 return 1;
826 } 953 }
827 } 954 }
828 955
829 if (comp->mode != pies_comp_exec 956 if (comp->mode != pies_comp_exec
830 && comp->redir[RETR_OUT].type != redir_null) 957 && comp->redir[RETR_OUT].type != redir_null)
831 { 958 {
@@ -835,7 +962,8 @@ component_verify (struct component *comp, mu_debug_t debug)
835 962
836 for (i = RETR_OUT; i <= RETR_ERR; i++) 963 for (i = RETR_OUT; i <= RETR_ERR; i++)
837 { 964 {
838 if (comp->redir[i].type == redir_file && comp->redir[i].v.file[0] != '/') 965 if (comp->redir[i].type == redir_file
966 && comp->redir[i].v.file[0] != '/')
839 { 967 {
840 if (comp->dir) 968 if (comp->dir)
841 { 969 {
@@ -849,162 +977,227 @@ component_verify (struct component *comp, mu_debug_t debug)
849 comp->redir[i].v.file); 977 comp->redir[i].v.file);
850 } 978 }
851 } 979 }
852 980
853 return header; 981 return header;
854#undef COMPERR 982#undef COMPERR
855} 983}
856 984
985struct component *
986component_create (const char *name)
987{
988 struct component *comp = progman_lookup_component (name);
989 if (!comp)
990 {
991 comp = xzalloc (sizeof (*comp));
992 comp->facility = log_facility;
993 comp->redir[RETR_OUT].type = comp->redir[RETR_ERR].type = redir_null;
994 comp->tag = xstrdup (name);
995 }
996 return comp;
997}
998
999void
1000component_finish (struct component *comp, grecs_locus_t *locus)
1001{
1002 if (component_verify (comp, locus) == 0)
1003 {
1004 /* FIXME: The prog list is traversed twice for each component
1005 statement, this is suboptimal. */
1006 if (progman_lookup_component (comp->tag) == NULL)
1007 register_prog (comp);
1008 }
1009}
1010
857static int 1011static int
858component_section_parser (enum mu_cfg_section_stage stage, 1012component_section_parser (enum grecs_callback_command cmd,
859 const mu_cfg_node_t *node, 1013 grecs_locus_t * locus,
860 const char *section_label, void **section_data, 1014 void *varptr, grecs_value_t * value, void *cb_data)
861 void *call_data,
862 mu_cfg_tree_t *tree)
863{ 1015{
864 struct component *comp; 1016 struct component *comp;
1017 void **section_data = cb_data;
865 1018
866 switch (stage) 1019 switch (cmd)
867 { 1020 {
868 case mu_cfg_section_start: 1021 case grecs_callback_section_begin:
869 if (node->label 1022 if (assert_grecs_value_type (locus, value, GRECS_TYPE_STRING))
870 && mu_cfg_assert_value_type (node->label, MU_CFG_STRING,
871 tree->debug))
872 return 1; 1023 return 1;
873 comp = progman_lookup_component (node->label->v.string); 1024 comp = component_create (value->v.string);
874 if (!comp)
875 {
876 comp = xzalloc (sizeof (*comp));
877 comp->facility = mu_log_facility;
878 comp->redir[RETR_OUT].type = comp->redir[RETR_ERR].type = redir_null;
879 comp->tag = node->label ? xstrdup (node->label->v.string) : NULL;
880 }
881 *section_data = comp; 1025 *section_data = comp;
882 break; 1026 break;
883 1027
884 case mu_cfg_section_end: 1028 case grecs_callback_section_end:
885 comp = *(struct component **) section_data; 1029 comp = *(struct component **) section_data;
886 if (component_verify (comp, tree->debug) == 0) 1030 component_finish (comp, locus);
887 {
888 /* FIXME: The prog list is traversed twice for each component
889 statement, this is suboptimal. */
890 if (progman_lookup_component (comp->tag) == NULL)
891 register_prog (comp);
892 }
893 } 1031 }
894 return 0; 1032 return 0;
895} 1033}
1034
896 1035
897void 1036/* syslog */
898component_cfg_init () 1037static struct grecs_keyword syslog_kw[] = {
899{ 1038 {"facility",
900 struct mu_cfg_section *section; 1039 N_("name"),
901 1040 N_("Set syslog facility. Arg is one of the following: user, daemon, "
902 if (mu_create_canned_section ("component", &section)) 1041 "auth, authpriv, mail, cron, local0 through local7 (case-insensitive), "
903 exit (EX_SOFTWARE); 1042 "or a facility number."),
904 section->parser = component_section_parser; 1043 grecs_type_string, &log_facility, 0, cb_syslog_facility},
905 section->label = N_("<tag: string>"); 1044 {"tag", N_("string"), N_("Tag syslog messages with this string"),
906 mu_cfg_section_add_params (section, component_cfg_param); 1045 grecs_type_string, &log_tag},
907} 1046# if 0
908 1047 {"print-priority", N_("arg"), N_("Prefix each message with its priority"),
909 1048 grecs_type_bool, &syslog_include_prio},
1049#endif
1050 {NULL},
1051};
910 1052
1053
911struct component default_component; 1054struct component default_component;
912 1055
913static int 1056static int
914_cb_debug (mu_debug_t debug, void *data, mu_config_value_t *arg) 1057_cm_include_meta1 (enum grecs_callback_command cmd,
1058 grecs_locus_t *locus,
1059 void *varptr, grecs_value_t *value, void *cb_data)
915{ 1060{
916 int rc; 1061 if (assert_grecs_value_type (locus, value, GRECS_TYPE_STRING))
917
918 if (mu_cfg_assert_value_type (arg, MU_CFG_STRING, debug))
919 return 1; 1062 return 1;
920 rc = mu_debug_level_from_string (arg->v.string, &debug_level, debug); 1063 meta1_config_parse (value->v.string);
921 if (rc)
922 return 0;
923 if (!pies_debug)
924 mu_debug_create (&pies_debug, NULL);
925 mu_debug_set_level (pies_debug, debug_level);
926 return 0; 1064 return 0;
927} 1065}
928 1066
929static int _cm_include_meta1 (mu_debug_t, void *, mu_config_value_t *); 1067struct grecs_keyword pies_cfg_param[] = {
930 1068 /* FIXME */
931struct mu_cfg_param pies_cfg_param[] = { 1069 {"component",
932 { "component", mu_cfg_section }, 1070 N_("<tag: string>"),
933 { "debug", mu_cfg_callback, NULL, 0, _cb_debug, 1071 NULL, /* FIXME: Docstring */
934 N_("Set debug verbosity level.") }, 1072 grecs_type_section, NULL, 0,
935 { "pidfile", mu_cfg_string, &pidfile, 0, NULL, 1073 component_section_parser, NULL, component_cfg_param},
936 N_("Write PID to this file.") }, 1074 {"syslog",
937 { "control-file", mu_cfg_string, &ctlfile, 0, NULL, 1075 NULL,
938 N_("Set location of the control file.") }, 1076 N_("Configure syslog logging"),
939 { "stat-file", mu_cfg_string, &statfile, 0, NULL, 1077 grecs_type_section, NULL, 0, NULL, NULL, syslog_kw},
940 N_("Set location of the statistics output file.") }, 1078 {"debug",
941 { "user", mu_cfg_string, &pies_privs.user, 0, NULL, 1079 NULL,
942 N_("Run with this user privileges.") }, 1080 N_("Set debug verbosity level."),
943 { "group", MU_CFG_LIST_OF(mu_cfg_string), &pies_privs.groups, 0, NULL, 1081 grecs_type_uint, &debug_level, 0, NULL},
944 N_("Retain supplementary group.") }, 1082 {"source-info",
945 { "allgroups", mu_cfg_bool, &pies_privs.allgroups, 0, NULL, 1083 NULL,
946 N_("Retain all supplementary groups of which user is a member.") }, 1084 N_("Show source info with debugging messages."),
947 { "umask", mu_cfg_callback, &pies_umask, 0, _cb_umask, 1085 grecs_type_bool, &source_info_option, 0, NULL},
948 N_("Force this umask."), 1086 {"pidfile",
949 N_("arg: number") }, 1087 NULL,
950 { "limits", mu_cfg_callback, &pies_limits, 0, _cb_limits, 1088 N_("Write PID to this file."),
951 N_("Set global system limits.") }, 1089 grecs_type_string, &pidfile, 0,
952 { "shutdown-timeout", mu_cfg_uint, &shutdown_timeout, 0, NULL, 1090 NULL,
953 N_("Wait <n> seconds for all components to shut down."), 1091 },
954 "n" }, 1092 {"control-file",
955 { "return-code", mu_cfg_section, &default_component }, 1093 NULL,
956 { "acl", mu_cfg_section, &pies_acl, 0, NULL, 1094 N_("Set location of the control file."),
957 N_("Global access control list") }, 1095 grecs_type_string, &ctlfile, 0,
958 { "include-meta1", mu_cfg_callback, NULL, 0, _cm_include_meta1, 1096 NULL,
959 N_("Include components from the specified MeTA1 configuration file."), 1097 },
960 N_("file: string") }, 1098 {"stat-file",
961 { "meta1-queue-dir", mu_cfg_string, &meta1_queue_dir, 0, NULL, 1099 NULL,
962 N_("Set name of MeTA1 queue directory (default /var/spool/meta1).") }, 1100 N_("Set location of the statistics output file."),
963 { NULL } 1101 grecs_type_string, &statfile, 0,
1102 NULL,
1103 },
1104 {"user",
1105 NULL,
1106 N_("Run with this user privileges."),
1107 grecs_type_string, &pies_privs.user, 0,
1108 NULL,
1109 },
1110 {"group",
1111 NULL,
1112 N_("Retain supplementary group."),
1113 grecs_type_string | GRECS_LIST, /*FIXME*/ &pies_privs.groups, 0,
1114 NULL,
1115 },
1116 {"allgroups",
1117 NULL,
1118 N_("Retain all supplementary groups of which user is a member."),
1119 grecs_type_bool, &pies_privs.allgroups, 0,
1120 NULL,
1121 },
1122 {"umask",
1123 N_("arg: number"),
1124 N_("Force this umask."),
1125 grecs_type_string, &pies_umask, 0,
1126 _cb_umask,
1127 },
1128 {"limits",
1129 NULL,
1130 N_("Set global system limits."),
1131 grecs_type_string, &pies_limits, 0, _cb_limits,
1132 },
1133 {"shutdown-timeout",
1134 "n",
1135 N_("Wait <n> seconds for all components to shut down."),
1136 grecs_type_uint, &shutdown_timeout, 0,
1137 NULL,
1138 },
1139 {"return-code",
1140 N_("<tag: exit-code-list>"),
1141 NULL, /* FIXME: Docstring? */
1142 grecs_type_section, &default_component, 0,
1143 return_code_section_parser, NULL, return_code_cfg_param},
1144 {"acl",
1145 N_("name: string"),
1146 N_("Define ACL."),
1147 grecs_type_section, NULL, 0,
1148 acl_section_parser, NULL, acl_keywords},
1149 {"include-meta1",
1150 N_("file: string"),
1151 N_("Include components from the specified MeTA1 configuration file."),
1152 grecs_type_string, NULL, 0,
1153 _cm_include_meta1,
1154 },
1155 {"meta1-queue-dir",
1156 NULL,
1157 N_("Set name of MeTA1 queue directory (default /var/spool/meta1)."),
1158 grecs_type_string, &meta1_queue_dir, 0,
1159 NULL,
1160 },
1161 {NULL}
964}; 1162};
965 1163
966static int 1164void
967_cm_include_meta1 (mu_debug_t debug, void *data, mu_config_value_t *arg) 1165config_init ()
968{ 1166{
969 int flags = 0; 1167 grecs_set_keywords (pies_cfg_param);
970 1168 grecs_include_path_setup (DEFAULT_VERSION_INCLUDE_DIR,
971 if (mu_cfg_assert_value_type (arg, MU_CFG_STRING, debug)) 1169 DEFAULT_INCLUDE_DIR, NULL);
972 return 1; 1170 grecs_preprocessor = DEFAULT_PREPROCESSOR;
973 if (meta1_config_parse (arg->v.string) == 0) 1171 grecs_log_to_stderr = log_to_stderr;
974 {
975 if (mu_cfg_parser_verbose)
976 flags |= MU_PARSE_CONFIG_VERBOSE;
977 if (mu_cfg_parser_verbose > 1)
978 flags |= MU_PARSE_CONFIG_DUMP;
979 mu_cfg_tree_reduce (meta1_parse_tree, mu_program_name, pies_cfg_param,
980 flags, NULL);
981 }
982 return 0;
983} 1172}
984 1173
985 1174void
1175config_help ()
1176{
1177 static char docstring[] =
1178 N_("Configuration file structure for pies.\n"
1179 "For more information, use `info pies configuration'.");
1180 grecs_format_docstring (stdout, docstring, 0);
1181 grecs_format_statement_array (stdout, pies_cfg_param, 1, 0);
1182}
986 1183
1184
987const char *program_version = "pies (" PACKAGE_STRING ")"; 1185const char *program_version = "pies (" PACKAGE_STRING ")";
988const char *package_bugreport = "<" PACKAGE_BUGREPORT ">"; 1186const char *package_bugreport = "<" PACKAGE_BUGREPORT ">";
989static char doc[] = N_("pies -- process invocation and execution supervisor"); 1187static char doc[] = N_("pies -- process invocation and execution supervisor");
990static char args_doc[] = ""; 1188static char args_doc[] = "";
991 1189
992static const char *capa[] = { 1190enum
993 "common", 1191{
994 "logging", 1192 OPT_FOREGROUND = 256,
995 "mailer",
996 "debug",
997 NULL
998};
999
1000enum {
1001 OPT_FOREGROUND=256,
1002 OPT_LOG_TAG, 1193 OPT_LOG_TAG,
1003 OPT_SYSLOG, 1194 OPT_SYSLOG,
1004 OPT_STDERR, 1195 OPT_STDERR,
1005 OPT_DUMP_PREREQ, 1196 OPT_DUMP_PREREQ,
1006 OPT_DUMP_DEPMAP, 1197 OPT_DUMP_DEPMAP,
1007 OPT_FORCE 1198 OPT_FORCE,
1199 OPT_CONFIG_HELP,
1200 OPT_SOURCE_INFO
1008}; 1201};
1009 1202
1010#define OPT_RESTART 'R' 1203#define OPT_RESTART 'R'
@@ -1014,53 +1207,77 @@ enum {
1014 1207
1015static struct argp_option options[] = { 1208static struct argp_option options[] = {
1016#define GRP 0 1209#define GRP 0
1017 { "foreground", OPT_FOREGROUND, 0, 0, N_("remain in foreground"), GRP+1}, 1210 {"foreground", OPT_FOREGROUND, 0, 0, N_("remain in foreground"), GRP + 1},
1018 { "stderr", OPT_STDERR, NULL, 0, N_("log to stderr"), }, 1211 {"stderr", OPT_STDERR, NULL, 0, N_("log to stderr"),},
1019 { "syslog", OPT_SYSLOG, NULL, 0, N_("log to syslog"), }, 1212 {"syslog", OPT_SYSLOG, NULL, 0, N_("log to syslog"),},
1020 { "log-tag", OPT_LOG_TAG, N_("STRING"), 0, 1213 {"log-tag", OPT_LOG_TAG, N_("STRING"), 0,
1021 N_("set the identifier used in syslog messages to STRING"), GRP+1 }, 1214 N_("set the identifier used in syslog messages to STRING"), GRP + 1},
1022 { "debug", 'x', N_("LEVEL"), 0, 1215 {"debug", 'x', N_("LEVEL"), 0,
1023 N_("set debug verbosity level"), GRP+1 }, 1216 N_("set debug verbosity level"), GRP + 1},
1024 { "force", OPT_FORCE, NULL, 0, 1217 {"source-info", OPT_SOURCE_INFO, NULL, 0,
1025 N_("force startup even if another instance may be running"), GRP+1 }, 1218 N_("show source info with debugging messages"), GRP + 1},
1219 {"force", OPT_FORCE, NULL, 0,
1220 N_("force startup even if another instance may be running"), GRP + 1},
1221 {"lint", 't', NULL, 0,
1222 N_("parse configuration file and exit"), GRP + 1},
1223 {NULL, 'E', NULL, 0,
1224 N_("preprocess config and exit"), GRP + 1},
1225 {"config-file", 'c', N_("FILE"), 0,
1226 N_("use FILE instead of the default configuration"), GRP + 1},
1227 {"config-help", OPT_CONFIG_HELP, NULL, 0,
1228 N_("show configuration file summary"), GRP + 1},
1026#undef GRP 1229#undef GRP
1027 1230
1028#define GRP 10 1231#define GRP 10
1029 { "restart-component", OPT_RESTART, NULL, 0, 1232 {"restart-component", OPT_RESTART, NULL, 0,
1030 N_("restart components named in the command line"), GRP+1 }, 1233 N_("restart components named in the command line"), GRP + 1},
1031 { "reload", OPT_RELOAD, NULL, 0, 1234 {"reload", OPT_RELOAD, NULL, 0,
1032 N_("reload the running instance of pies "), GRP+1 }, 1235 N_("reload the running instance of pies "), GRP + 1},
1033 { "hup", 0, NULL, OPTION_ALIAS }, 1236 {"hup", 0, NULL, OPTION_ALIAS},
1034 { "status", OPT_STATUS, NULL, 0, 1237 {"status", OPT_STATUS, NULL, 0,
1035 N_("display info about the running instance "), GRP+1 }, 1238 N_("display info about the running instance "), GRP + 1},
1036 { "stop", OPT_STOP, NULL, 0, 1239 {"stop", OPT_STOP, NULL, 0,
1037 N_("stop the running instance "), GRP+1 }, 1240 N_("stop the running instance "), GRP + 1},
1038#undef GRP 1241#undef GRP
1039 1242
1040#define GRP 20 1243#define GRP 20
1041 { "dump-prereq", OPT_DUMP_PREREQ, NULL, 0, 1244 {"dump-prereq", OPT_DUMP_PREREQ, NULL, 0,
1042 N_("dump prerequisite charts"), GRP+1 }, 1245 N_("dump prerequisite charts"), GRP + 1},
1043 { "dump-depmap", OPT_DUMP_DEPMAP, NULL, 0, 1246 {"dump-depmap", OPT_DUMP_DEPMAP, NULL, 0,
1044 N_("dump dependency map"), GRP+1 }, 1247 N_("dump dependency map"), GRP + 1},
1045#undef GRP 1248#undef GRP
1046 { NULL } 1249 {NULL}
1047}; 1250};
1048 1251
1049static error_t 1252static error_t
1050parse_opt (int key, char *arg, struct argp_state *state) 1253parse_opt (int key, char *arg, struct argp_state *state)
1051{ 1254{
1052 static struct mu_argp_node_list lst;
1053
1054 switch (key) 1255 switch (key)
1055 { 1256 {
1257 case 't':
1258 lint_mode = 1;
1259 break;
1260
1261 case 'E':
1262 preprocess_only = 1;
1263 break;
1264
1265 case 'c':
1266 conffile = arg;
1267 break;
1268
1269 case OPT_CONFIG_HELP:
1270 config_help ();
1271 exit (0);
1272
1056 case OPT_FOREGROUND: 1273 case OPT_FOREGROUND:
1057 foreground = 1; 1274 foreground = 1;
1058 break; 1275 break;
1059 1276
1060 case OPT_RELOAD: 1277 case OPT_RELOAD:
1061 case OPT_STATUS: 1278 case OPT_STATUS:
1062 case OPT_STOP: 1279 case OPT_STOP:
1063 case OPT_RESTART: 1280 case OPT_RESTART:
1064 case OPT_DUMP_PREREQ: 1281 case OPT_DUMP_PREREQ:
1065 case OPT_DUMP_DEPMAP: 1282 case OPT_DUMP_DEPMAP:
1066 log_to_stderr = 1; 1283 log_to_stderr = 1;
@@ -1076,23 +1293,25 @@ parse_opt (int key, char *arg, struct argp_state *state)
1076 break; 1293 break;
1077 1294
1078 case 'x': 1295 case 'x':
1079 mu_argp_node_list_new (&lst, "debug", arg); 1296 debug_level = strtoul (arg, NULL, 0);
1297 break;
1298
1299 case OPT_SOURCE_INFO:
1300 source_info_option = 1;
1080 break; 1301 break;
1081 1302
1082 case OPT_FORCE: 1303 case OPT_FORCE:
1083 force_option = 1; 1304 force_option = 1;
1084 break; 1305 break;
1085 1306
1086 case OPT_LOG_TAG: 1307 case OPT_LOG_TAG:
1087 log_tag = arg; 1308 log_tag = arg;
1088 break; 1309 break;
1089 1310
1090 case ARGP_KEY_INIT: 1311 case ARGP_KEY_INIT:
1091 mu_argp_node_list_init (&lst);
1092 break; 1312 break;
1093 1313
1094 case ARGP_KEY_FINI: 1314 case ARGP_KEY_FINI:
1095 mu_argp_node_list_finish (&lst, NULL, NULL);
1096 break; 1315 break;
1097 1316
1098 default: 1317 default:
@@ -1110,8 +1329,8 @@ static struct argp argp = {
1110 NULL, 1329 NULL,
1111 NULL 1330 NULL
1112}; 1331};
1113
1114 1332
1333
1115#define ACTION_CONT 0 1334#define ACTION_CONT 0
1116#define ACTION_STOP 1 1335#define ACTION_STOP 1
1117#define ACTION_RESTART 2 1336#define ACTION_RESTART 2
@@ -1135,11 +1354,11 @@ sig_handler (int sig)
1135 case SIGINT: 1354 case SIGINT:
1136 case SIGQUIT: 1355 case SIGQUIT:
1137 action = ACTION_STOP; 1356 action = ACTION_STOP;
1138 mu_diag_output (MU_DIAG_NOTICE, "received signal %d", sig); 1357 logmsg (LOG_NOTICE, "received signal %d", sig);
1139 break; 1358 break;
1140 1359
1141 case SIGHUP: 1360 case SIGHUP:
1142 mu_diag_output (MU_DIAG_NOTICE, "received signal %d", sig); 1361 logmsg (LOG_NOTICE, "received signal %d", sig);
1143 action = ACTION_RESTART; 1362 action = ACTION_RESTART;
1144 break; 1363 break;
1145 1364
@@ -1159,7 +1378,7 @@ sig_handler (int sig)
1159} 1378}
1160 1379
1161void 1380void
1162signal_setup (RETSIGTYPE (*sf)(int)) 1381signal_setup (RETSIGTYPE (*sf) (int))
1163{ 1382{
1164 signal (SIGCHLD, sf); 1383 signal (SIGCHLD, sf);
1165 signal (SIGTERM, sf); 1384 signal (SIGTERM, sf);
@@ -1170,8 +1389,8 @@ signal_setup (RETSIGTYPE (*sf)(int))
1170 signal (SIGUSR1, sf); 1389 signal (SIGUSR1, sf);
1171 signal (SIGUSR2, sf); 1390 signal (SIGUSR2, sf);
1172} 1391}
1173
1174 1392
1393
1175pid_t 1394pid_t
1176pidfile_read (int must_exist) 1395pidfile_read (int must_exist)
1177{ 1396{
@@ -1181,10 +1400,9 @@ pidfile_read (int must_exist)
1181 if (!fp) 1400 if (!fp)
1182 { 1401 {
1183 if (must_exist && errno != ENOENT) 1402 if (must_exist && errno != ENOENT)
1184 mu_diag_output (MU_DIAG_ERR, 1403 logmsg (LOG_ERR,
1185 _("cannot open pid file `%s': %s"), 1404 _("cannot open pid file `%s': %s"),
1186 pidfile, 1405 pidfile, strerror (errno));
1187 mu_strerror (errno));
1188 return -1; 1406 return -1;
1189 } 1407 }
1190 1408
@@ -1196,44 +1414,44 @@ pidfile_read (int must_exist)
1196 break; 1414 break;
1197 else 1415 else
1198 { 1416 {
1199 mu_diag_output (MU_DIAG_ERR, 1417 logmsg (LOG_ERR,
1200 _("unexpected character %#03o in pidfile `%s'"), 1418 _("unexpected character %#03o in pidfile `%s'"),
1201 c, pidfile); 1419 c, pidfile);
1202 return -1; 1420 return -1;
1203 } 1421 }
1204 } 1422 }
1205 fclose (fp); 1423 fclose (fp);
1206 if (kill (n, 0)) 1424 if (n && kill (n, 0))
1207 { 1425 {
1208 mu_diag_output (MU_DIAG_ERR, 1426 logmsg (LOG_ERR,
1209 _("cannot signal master process %lu: %s"), 1427 _("cannot signal master process %lu: %s"),
1210 (unsigned long) n, mu_strerror (errno)); 1428 (unsigned long) n, strerror (errno));
1211 if (errno == EPERM) 1429 if (errno == EPERM)
1212 return n; /* be on the safe side */ 1430 return n; /* be on the safe side */
1213 return -1; 1431 return -1;
1214 } 1432 }
1215 return n; 1433 return n;
1216} 1434}
1217
1218 1435
1436
1219enum pies_status 1437enum pies_status
1220 { 1438{
1221 pies_status_ctr, /* clear to run */ 1439 pies_status_ctr, /* clear to run */
1222 pies_status_stale, 1440 pies_status_stale,
1223 pies_status_noresp, 1441 pies_status_noresp,
1224 pies_status_running 1442 pies_status_running
1225 }; 1443};
1226 1444
1227enum pies_status 1445enum pies_status
1228pies_check_status (pid_t *ppid) 1446pies_check_status (pid_t * ppid)
1229{ 1447{
1230 pid_t pid = pidfile_read (0); 1448 pid_t pid = pidfile_read (0);
1231 int i; 1449 int i;
1232 int rc; 1450 int rc;
1233 1451
1234 if (pid == -1) 1452 if (pid <= 0)
1235 return pies_status_ctr; 1453 return pies_status_ctr;
1236 1454
1237 *ppid = pid; 1455 *ppid = pid;
1238 1456
1239 if (kill (pid, SIGUSR2)) 1457 if (kill (pid, SIGUSR2))
@@ -1246,39 +1464,39 @@ pies_check_status (pid_t *ppid)
1246 return pies_status_noresp; 1464 return pies_status_noresp;
1247 return pies_status_running; 1465 return pies_status_running;
1248} 1466}
1249
1250 1467
1468
1251void 1469void
1252stop_components () 1470stop_components ()
1253{ 1471{
1254 FILE *fp; 1472 FILE *fp;
1255 size_t size = 0; 1473 size_t size = 0;
1256 char *buf = NULL; 1474 char *buf = NULL;
1257 1475
1258 mu_diag_output (MU_DIAG_INFO, _("stopping components")); 1476 logmsg (LOG_INFO, _("stopping components"));
1259 1477
1260 fp = fopen (ctlfile, "r"); 1478 fp = fopen (ctlfile, "r");
1261 if (!fp) 1479 if (!fp)
1262 { 1480 {
1263 mu_error (_("cannot open control file `%s': %s"), 1481 logmsg (LOG_ERR, _("cannot open control file `%s': %s"),
1264 ctlfile, mu_strerror (errno)); 1482 ctlfile, strerror (errno));
1265 return; 1483 return;
1266 } 1484 }
1267 if (unlink (ctlfile)) 1485 if (unlink (ctlfile))
1268 { 1486 {
1269 mu_error (_("cannot unlink control file `%s': %s"), 1487 logmsg (LOG_ERR, _("cannot unlink control file `%s': %s"),
1270 ctlfile, mu_strerror (errno)); 1488 ctlfile, strerror (errno));
1271 fclose (fp); 1489 fclose (fp);
1272 return; 1490 return;
1273 } 1491 }
1274 1492
1275 while (getline (&buf, &size, fp) > 0) 1493 while (getline (&buf, &size, fp) > 0)
1276 { 1494 {
1277 size_t len = strlen (buf); 1495 size_t len = strlen (buf);
1278 if (len == 0) 1496 if (len == 0)
1279 continue; 1497 continue;
1280 if (buf[len-1] == '\n') 1498 if (buf[len - 1] == '\n')
1281 buf[len-1] = 0; 1499 buf[len - 1] = 0;
1282 progman_stop_component (buf); 1500 progman_stop_component (buf);
1283 } 1501 }
1284 1502
@@ -1298,8 +1516,8 @@ request_restart_components (char **argv)
1298 fp = fopen (ctlfile, "w"); 1516 fp = fopen (ctlfile, "w");
1299 if (!fp) 1517 if (!fp)
1300 { 1518 {
1301 mu_error (_("cannot open control file `%s': %s"), 1519 logmsg (LOG_ERR, _("cannot open control file `%s': %s"),
1302 ctlfile, mu_strerror (errno)); 1520 ctlfile, strerror (errno));
1303 return 1; 1521 return 1;
1304 } 1522 }
1305 for (; *argv; argv++) 1523 for (; *argv; argv++)
@@ -1309,8 +1527,8 @@ request_restart_components (char **argv)
1309 kill (pid, SIGUSR1); 1527 kill (pid, SIGUSR1);
1310 return 0; 1528 return 0;
1311} 1529}
1312
1313 1530
1531
1314int 1532int
1315pies_reload () 1533pies_reload ()
1316{ 1534{
@@ -1318,12 +1536,11 @@ pies_reload ()
1318 1536
1319 if (pid == -1) 1537 if (pid == -1)
1320 { 1538 {
1321 mu_diag_output (MU_DIAG_CRIT, _("pies is not running")); 1539 logmsg (LOG_CRIT, _("pies is not running"));
1322 return 1; 1540 return 1;
1323 } 1541 }
1324 1542
1325 mu_diag_output (MU_DIAG_INFO, _("reloading pies at PID %lu"), 1543 logmsg (LOG_INFO, _("reloading pies at PID %lu"), (unsigned long) pid);
1326 (unsigned long) pid);
1327 return kill (pid, SIGHUP) ? EX_SOFTWARE : 0; 1544 return kill (pid, SIGHUP) ? EX_SOFTWARE : 0;
1328} 1545}
1329 1546
@@ -1332,51 +1549,50 @@ pies_status ()
1332{ 1549{
1333 pid_t pid; 1550 pid_t pid;
1334 FILE *fp; 1551 FILE *fp;
1335 1552
1336 if (unlink (statfile) && errno != ENOENT) 1553 if (unlink (statfile) && errno != ENOENT)
1337 mu_diag_output (MU_DIAG_ERR, _("cannot unlink statfile `%s': %s"), 1554 logmsg (LOG_ERR, _("cannot unlink statfile `%s': %s"),
1338 statfile, mu_strerror (errno)); 1555 statfile, strerror (errno));
1339 switch (pies_check_status (&pid)) 1556 switch (pies_check_status (&pid))
1340 { 1557 {
1341 case pies_status_ctr: 1558 case pies_status_ctr:
1342 mu_diag_output (MU_DIAG_INFO, _("pies is not running")); 1559 logmsg (LOG_INFO, _("pies is not running"));
1343 break; 1560 break;
1344 1561
1345 case pies_status_stale: 1562 case pies_status_stale:
1346 mu_diag_output (MU_DIAG_INFO, 1563 logmsg (LOG_INFO,
1347 _("pies is not running, but a pidfile " 1564 _("pies is not running, but a pidfile "
1348 "is found (pid %lu)"), 1565 "is found (pid %lu)"), (unsigned long) pid);
1349 (unsigned long) pid); 1566 return 1; /* FIXME: hm? */
1350 return 1; /* FIXME: hm? */
1351 1567
1352 case pies_status_noresp: 1568 case pies_status_noresp:
1353 mu_diag_output (MU_DIAG_INFO, 1569 logmsg (LOG_INFO,
1354 _("pies seems to run with pid %lu, but is not responding"), 1570 _("pies seems to run with pid %lu, but is not responding"),
1355 (unsigned long) pid); 1571 (unsigned long) pid);
1356 if (unlink (statfile)) 1572 if (unlink (statfile))
1357 mu_diag_output (MU_DIAG_ERR, _("cannot unlink statfile `%s': %s"), 1573 logmsg (LOG_ERR, _("cannot unlink statfile `%s': %s"),
1358 statfile, mu_strerror (errno)); 1574 statfile, strerror (errno));
1359 return 2; 1575 return 2;
1360 1576
1361 case pies_status_running: 1577 case pies_status_running:
1362 fp = fopen (statfile, "r"); 1578 fp = fopen (statfile, "r");
1363 if (!fp) 1579 if (!fp)
1364 mu_diag_output (MU_DIAG_ERR, _("cannot open statfile `%s': %s"), 1580 logmsg (LOG_ERR, _("cannot open statfile `%s': %s"),
1365 statfile, mu_strerror (errno)); 1581 statfile, strerror (errno));
1366 else 1582 else
1367 { 1583 {
1368 char c; 1584 char c;
1369 1585
1370 if (unlink (statfile)) 1586 if (unlink (statfile))
1371 mu_diag_output (MU_DIAG_ERR, _("cannot unlink statfile `%s': %s"), 1587 logmsg (LOG_ERR, _("cannot unlink statfile `%s': %s"),
1372 statfile, mu_strerror (errno)); 1588 statfile, strerror (errno));
1373 while ((c = fgetc (fp)) != EOF) 1589 while ((c = fgetc (fp)) != EOF)
1374 fputc (c, stdout); 1590 fputc (c, stdout);
1375 fclose (fp); 1591 fclose (fp);
1376 } 1592 }
1377 } 1593 }
1378 return 0; 1594 return 0;
1379} 1595}
1380 1596
1381int 1597int
1382pies_stop () 1598pies_stop ()
@@ -1385,54 +1601,113 @@ pies_stop ()
1385 1601
1386 if (pid == -1) 1602 if (pid == -1)
1387 { 1603 {
1388 mu_diag_output (MU_DIAG_CRIT, _("pies is not running")); 1604 logmsg (LOG_CRIT, _("pies is not running"));
1389 return EX_USAGE; 1605 return EX_USAGE;
1390 } 1606 }
1391 1607
1392 mu_diag_output (MU_DIAG_INFO, 1608 logmsg (LOG_INFO, _("stopping pies at PID %lu"), (unsigned long) pid);
1393 _("stopping pies at PID %lu"), (unsigned long) pid);
1394 return kill (pid, SIGTERM) ? EX_SOFTWARE : 0; 1609 return kill (pid, SIGTERM) ? EX_SOFTWARE : 0;
1395} 1610}
1396 1611
1397 1612
1398static int 1613/* Pidfile */
1399pies_cfg_verifier () 1614/* Check whether pidfile NAME exists and if so, whether its PID is still
1615 active. Exit if it is. */
1616void
1617check_pidfile (char *name)
1618{
1619 unsigned long pid;
1620 FILE *fp = fopen (name, "r");
1621 if (!fp)
1622 {
1623 if (errno == ENOENT)
1624 return;
1625 logmsg (LOG_ERR, _("cannot open pidfile `%s': %s"),
1626 name, strerror (errno));
1627 exit (EX_TEMPFAIL);
1628 }
1629 if (fscanf (fp, "%lu", &pid) != 1)
1630 {
1631 logmsg (LOG_ERR, ("cannot get pid from pidfile `%s'"), name);
1632 }
1633 else
1634 {
1635 if (kill (pid, 0) == 0)
1636 {
1637 logmsg (LOG_ERR,
1638 _
1639 ("%s appears to run with pid %lu. If it does not, remove `%s' and retry."),
1640 program_name, pid, name);
1641 exit (EX_USAGE);
1642 }
1643 }
1644 fclose (fp);
1645 if (unlink (pidfile))
1646 {
1647 logmsg (LOG_ERR, _("cannot unlink pidfile `%s': %s"),
1648 name, strerror (errno));
1649 exit (EX_USAGE);
1650 }
1651}
1652
1653void
1654create_pidfile (char *name)
1400{ 1655{
1401 return progman_build_depmap (); 1656 FILE *fp = fopen (name, "w");
1657 if (!fp)
1658 {
1659 logmsg (LOG_ERR, _("cannot create pidfile `%s': %s"),
1660 name, strerror (errno));
1661 exit (EX_TEMPFAIL);
1662 }
1663 fprintf (fp, "%lu", (unsigned long) getpid ());
1664 fclose (fp);
1402} 1665}
1403 1666
1667void
1668remove_pidfile (char *name)
1669{
1670 if (unlink (name))
1671 logmsg (LOG_ERR, _("cannot unlink pidfile `%s': %s"),
1672 name, strerror (errno));
1673}
1404 1674
1675
1405int 1676int
1406main (int argc, char **argv) 1677main (int argc, char **argv)
1407{ 1678{
1408 int rc;
1409 int index; 1679 int index;
1410 pid_t pid; 1680 pid_t pid;
1411 extern char **environ; 1681 extern char **environ;
1412 extern char *program_invocation_short_name; /* FIXME */ 1682
1413 1683 set_program_name (argv[0]);
1414 mf_init_nls (); 1684 mf_init_nls ();
1415 mf_proctitle_init (argc, argv, environ); 1685 mf_proctitle_init (argc, argv, environ);
1416 if (!program_invocation_short_name)
1417 program_invocation_short_name = argv[0];
1418 1686
1419 /* Set default logging */ 1687 /* Set default logging */
1420 log_setup (!stderr_closed_p ()); 1688 log_setup (!stderr_closed_p ());
1421 mu_acl_cfg_init (); 1689 config_init ();
1422 return_code_cfg_init (); 1690 if (argp_parse (&argp, argc, argv, 0, &index, NULL))
1423 component_cfg_init (); 1691 exit (EX_USAGE);
1424 mu_app_cfg_verifier = pies_cfg_verifier; 1692
1425 mu_argp_init (program_version, package_bugreport); 1693 if (preprocess_only)
1426 mu_register_all_mailer_formats (); 1694 exit (grecs_preproc_run (conffile, grecs_preprocessor) ? EX_CONFIG : 0);
1427 rc = mu_app_init (&argp, capa, pies_cfg_param, argc, argv, 0, &index, NULL); 1695
1428 if (rc) 1696 if (grecs_parse (conffile))
1429 exit (EX_CONFIG); 1697 exit (EX_CONFIG);
1430 1698
1699 if (lint_mode)
1700 {
1701 progman_build_depmap ();
1702 exit (0);
1703 }
1704
1705 /* Re-setup logging: it might have been reset in the config file */
1431 log_setup (log_to_stderr); 1706 log_setup (log_to_stderr);
1432 1707
1433 if (argc != index && command != 'R') 1708 if (argc != index && command != 'R')
1434 { 1709 {
1435 mu_error ("extra command line arguments"); 1710 logmsg (LOG_ERR, "extra command line arguments");
1436 exit (EX_CONFIG); 1711 exit (EX_CONFIG);
1437 } 1712 }
1438 1713
@@ -1440,7 +1715,7 @@ main (int argc, char **argv)
1440 switch (command) 1715 switch (command)
1441 { 1716 {
1442 case OPT_RESTART: 1717 case OPT_RESTART:
1443 mf_priv_setup (&pies_privs); 1718 pies_priv_setup (&pies_privs);
1444 if (pies_umask) 1719 if (pies_umask)
1445 umask (pies_umask); 1720 umask (pies_umask);
1446 exit (request_restart_components (argv + index)); 1721 exit (request_restart_components (argv + index));
@@ -1461,9 +1736,9 @@ main (int argc, char **argv)
1461 case OPT_DUMP_DEPMAP: 1736 case OPT_DUMP_DEPMAP:
1462 progman_dump_depmap (); 1737 progman_dump_depmap ();
1463 exit (0); 1738 exit (0);
1464 1739
1465 default: 1740 default:
1466 mf_priv_setup (&pies_privs); 1741 pies_priv_setup (&pies_privs);
1467 if (pies_umask) 1742 if (pies_umask)
1468 umask (pies_umask); 1743 umask (pies_umask);
1469 } 1744 }
@@ -1476,37 +1751,36 @@ main (int argc, char **argv)
1476 case pies_status_noresp: 1751 case pies_status_noresp:
1477 if (!force_option) 1752 if (!force_option)
1478 { 1753 {
1479 mu_error (_("another pies instance may be running (pid %lu), " 1754 logmsg (LOG_ERR,
1480 "use --force to override"), 1755 _("another pies instance may be running (pid %lu), "
1481 (unsigned long) pid); 1756 "use --force to override"), (unsigned long) pid);
1482 exit (EX_USAGE); 1757 exit (EX_USAGE);
1483 } 1758 }
1484 break; 1759 break;
1485 1760
1486 case pies_status_running: 1761 case pies_status_running:
1487 mu_error (_("another pies instance already running (pid %lu)"), 1762 logmsg (LOG_ERR, _("another pies instance already running (pid %lu)"),
1488 (unsigned long) pid); 1763 (unsigned long) pid);
1489 exit (EX_USAGE); 1764 exit (EX_USAGE);
1490 } 1765 }
1491 1766
1492 mu_diag_output (MU_DIAG_INFO, _("%s starting"), program_version);