aboutsummaryrefslogtreecommitdiff
path: root/pies/pies.c
diff options
context:
space:
mode:
Diffstat (limited to 'pies/pies.c')
-rw-r--r--pies/pies.c1010
1 files changed, 1010 insertions, 0 deletions
diff --git a/pies/pies.c b/pies/pies.c
new file mode 100644
index 0000000..bdca2a4
--- /dev/null
+++ b/pies/pies.c
@@ -0,0 +1,1010 @@
+/* This file is part of Mailfromd.
+ Copyright (C) 2008 Sergey Poznyakoff
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "pies.h"
+
+int log_to_stderr; /* Use stderr for logging */
+char *log_tag; /* override mu_log_tag */
+mu_log_level_t debug_level;
+mu_debug_t pmult_debug;
+struct pies_privs_data pies_user;
+int foreground;
+int command;
+char *pidfile = STATEDIR "/pies.pid";
+char *ctlfile = STATEDIR "/pies.ctl";
+char *statfile = STATEDIR "/pies.stat";
+mode_t pies_umask = 0;
+unsigned long shutdown_timeout = 5;
+
+
+/* Logging */
+void
+log_setup (int want_stderr)
+{
+ mu_debug_t debug;
+
+ mu_diag_get_debug (&debug);
+
+ if (log_tag)
+ mu_log_tag = log_tag;
+
+ if (!want_stderr)
+ {
+ openlog (MU_LOG_TAG (), LOG_PID, mu_log_facility);
+ mu_debug_set_print (debug, mu_diag_syslog_printer, NULL);
+ mu_debug_default_printer = mu_debug_syslog_printer;
+ }
+ else
+ mu_debug_default_printer = mu_debug_stderr_printer;
+}
+
+static int
+stderr_closed_p()
+{
+ int fd = dup (0);
+ if (fd < 0)
+ return 1;
+ close (fd);
+ return fd <= 2;
+}
+
+
+static int
+_cb_action (mu_debug_t debug, void *data, char *arg)
+{
+ enum return_action *pact = data;
+ static struct mu_kwd actab[] = {
+ { "disable", action_disable },
+ { "restart", action_restart },
+ { NULL }
+ };
+ int res;
+
+ if (mu_kwd_xlat_name (actab, arg, &res))
+ {
+ mu_cfg_format_error (debug, MU_DEBUG_ERROR,
+ _("unknown action code: %s"), arg);
+ return 0;
+ }
+ *pact = res;
+ return 0;
+}
+
+static int
+_cb_notify_addr (mu_debug_t debug, void *data, char *arg)
+{
+ mu_address_t *paddr = data;
+ mu_address_t addr;
+ int rc;
+
+ rc = mu_address_create (&addr, arg);
+ if (rc)
+ mu_cfg_format_error (debug, MU_DEBUG_ERROR,
+ _("%s: invalid e-mail address: %s"),
+ arg, mu_strerror (rc));
+ if (*paddr)
+ {
+ mu_address_union (paddr, addr);
+ mu_address_destroy (&addr);
+ }
+ else
+ *paddr = addr;
+ return 0;
+}
+
+struct mu_cfg_param return_code_cfg_param[] = {
+ { "action", mu_cfg_callback, NULL,
+ mu_offsetof (struct action, act), _cb_action,
+ N_("Specifies action to take when a component finishes with this "
+ "return code."),
+ N_("arg: {disable | restart}") },
+ { "notify", mu_cfg_callback, NULL,
+ mu_offsetof (struct action, addr), _cb_notify_addr,
+ N_("Notify this address when then component terminates."),
+ N_("arg: email-list") },
+ { "message", mu_cfg_string, NULL,
+ mu_offsetof (struct action, message), NULL,
+ N_("Notification message text (with headers).") },
+ { NULL }
+};
+
+static struct mu_kwd ex_kwtab[] = {
+#define S(s) { #s, s }
+ S (EX_OK),
+ S (EX_USAGE),
+ S (EX_DATAERR),
+ S (EX_NOINPUT),
+ S (EX_NOUSER),
+ S (EX_NOHOST),
+ S (EX_UNAVAILABLE),
+ S (EX_SOFTWARE),
+ S (EX_OSERR),
+ S (EX_OSFILE),
+ S (EX_CANTCREAT),
+ S (EX_IOERR),
+ S (EX_TEMPFAIL),
+ S (EX_PROTOCOL),
+ S (EX_NOPERM),
+ S (EX_CONFIG),
+ { NULL }
+};
+
+static int
+return_code_section_parser (enum mu_cfg_section_stage stage,
+ const mu_cfg_node_t *node,
+ const char *section_label, void **section_data,
+ void *call_data,
+ mu_cfg_tree_t *tree)
+{
+ struct component *comp = *section_data;
+ struct action *act;
+ int argc, i;
+ char **argv;
+ int *retv;
+ int retc = 0;
+ int allflag = 0;
+ int rc;
+
+ switch (stage)
+ {
+ case mu_cfg_section_start:
+ rc = mu_argcv_get (node->tag_label, NULL, NULL, &argc, &argv);
+ if (rc)
+ {
+ mu_cfg_format_error (tree->debug, MU_DEBUG_ERROR,
+ _("cannot parse return codes: %s"),
+ mu_strerror (rc));
+ return 1;
+ }
+ retv = xcalloc (argc, sizeof *retv);
+ if (argc == 0 || (argc == 1 && strcmp (argv[0], "*") == 0))
+ allflag = 1;
+ else
+ {
+ for (i = 0; i < argc; i++)
+ {
+ int n;
+
+ if (isdigit (argv[i][0]))
+ {
+ char *p;
+ n = strtoul (argv[i], &p, 0);
+ if (*p)
+ {
+ mu_cfg_format_error (tree->debug, MU_DEBUG_ERROR,
+ _("%s: not a number"), p);
+ continue;
+ }
+ }
+ else if (mu_kwd_xlat_name_ci (ex_kwtab, argv[i], &n))
+ {
+ mu_cfg_format_error (tree->debug, MU_DEBUG_ERROR,
+ _("%s: not a return code"), argv[i]);
+ continue;
+ }
+
+ if (n > MAX_RETURN_CODE)
+ mu_cfg_format_error (tree->debug, MU_DEBUG_ERROR,
+ _("%s: invalid return code"), argv[i]);
+ else
+ {
+ /* Alles in ordnung */
+ retv[retc++] = n;
+ }
+ }
+ }
+
+ mu_argcv_free (argc, argv);
+ if (retc == 0 && !allflag)
+ {
+ free (retv);
+ return 1;
+ }
+
+ act = xzalloc (sizeof *act);
+ if (allflag)
+ {
+ for (i = 0; i <= MAX_RETURN_CODE; i++)
+ if (comp->act[i] == NULL)
+ comp->act[i] = act;
+ }
+ else
+ for (i = 0; i < retc; i++)
+ comp->act[retv[i]] = act;
+ *section_data = act;
+ break;
+
+ case mu_cfg_section_end:
+ break;
+ }
+ return 0;
+}
+
+void
+return_code_cfg_init ()
+{
+ struct mu_cfg_section *section;
+
+ if (mu_create_canned_section ("return-code", &section))
+ exit (EX_SOFTWARE);
+ section->parser = return_code_section_parser;
+ section->label = N_("<tag: exit-code-list>");
+ mu_cfg_section_add_params (section, return_code_cfg_param);
+}
+
+
+static int
+_cb_group (mu_debug_t debug, void *data, char *arg)
+{
+ int argc, i;
+ char **argv;
+ mu_list_t *plist = data, list;
+ int rc;
+
+ rc = mu_argcv_get_np (arg, strlen (arg), ",", NULL, 0, &argc, &argv, NULL);
+ if (rc)
+ {
+ mu_cfg_format_error (debug, MU_DEBUG_ERROR,
+ "mu_argcv_get: %s", mu_strerror (rc));
+ return 1;
+ }
+ if (*plist)
+ list = *plist;
+ else
+ {
+ mu_list_create (&list);
+ *plist = list;
+ }
+ for (i = 0; i < argc; i++)
+ {
+ struct group *group = getgrnam (argv[i]);
+ if (!group)
+ {
+ mu_cfg_format_error (debug, MU_DEBUG_ERROR, _("Unknown group: %s"),
+ argv[i]);
+ continue;
+ }
+ mu_list_append (list, (void*)group->gr_gid);
+ }
+ mu_argcv_free (argc, argv);
+ return 0;
+}
+
+
+static int
+_cb_command (mu_debug_t debug, void *data, char *arg)
+{
+ int argc;
+ char **argv, ***pargv = data;
+ int rc;
+
+ rc = mu_argcv_get (arg, "", NULL, &argc, &argv);
+ if (rc)
+ {
+ mu_cfg_format_error (debug, MU_DEBUG_ERROR,
+ "mu_argcv_get: %s", mu_strerror (rc));
+ return 1;
+ }
+ *pargv = argv;
+ return 0;
+}
+
+static int
+_cb_depend (mu_debug_t debug, void *data, char *arg)
+{
+ int argc;
+ char **argv, ***pargv = data;
+ int rc;
+
+ rc = mu_argcv_get_np (arg, strlen (arg), ",", NULL, 0, &argc, &argv, NULL);
+ if (rc)
+ {
+ mu_cfg_format_error (debug, MU_DEBUG_ERROR,
+ "mu_argcv_get: %s", mu_strerror (rc));
+ return 1;
+ }
+ *pargv = argv;
+ return 0;
+}
+
+static int
+_cb_umask (mu_debug_t debug, void *data, char *arg)
+{
+ mode_t *pmode = data;
+ char *p;
+ unsigned long n = strtoul (arg, &p, 8);
+ if (*p)
+ {
+ mu_cfg_format_error (debug, MU_DEBUG_ERROR,
+ _("Invalid octal number"));
+ return 1;
+ }
+ *pmode = n;
+ return 0;
+}
+
+static int
+_cb_env (mu_debug_t debug, void *data, char *arg)
+{
+ int rc;
+ int argc;
+ char **argv;
+ char ***penv = data;
+
+ rc = mu_argcv_get_np (arg, strlen (arg), "", NULL, 0, &argc, &argv, NULL);
+ if (rc)
+ {
+ mu_cfg_format_error (debug, MU_DEBUG_ERROR,
+ "mu_argcv_get: %s", mu_strerror (rc));
+ return 1;
+ }
+ *penv = argv;
+ return 0;
+}
+
+static int
+_cb_retr (mu_debug_t debug, void *data, char *arg)
+{
+ if (mu_string_to_syslog_priority (arg, data))
+ {
+ mu_cfg_format_error (debug, MU_DEBUG_ERROR,
+ _("Unknown syslog facility `%s'"),
+ arg);
+ return 1;
+ }
+ return 0;
+}
+
+struct mu_cfg_param component_cfg_param[] = {
+ { "command", mu_cfg_callback, NULL,
+ mu_offsetof (struct component, argv), _cb_command,
+ N_("Command line.") },
+ { "depend", mu_cfg_callback, NULL,
+ mu_offsetof (struct component, depend), _cb_depend,
+ N_("List of dependenices (whitespace separated)"),
+ N_("list") },
+ { "disable", mu_cfg_bool, NULL,
+ mu_offsetof (struct component, disabled), NULL,
+ N_("Disable this entry.") },
+ { "remove-file", mu_cfg_string, NULL,
+ mu_offsetof (struct component, rmfile), NULL,
+ N_("Remove file before starting the component.")
+ N_("file") },
+ { "stdout", mu_cfg_callback, NULL,
+ mu_offsetof (struct component, retr[RETR_OUT]), _cb_retr,
+ N_("Redirect program's standard output to the given syslog priority."),
+ N_("prio: {emerg | alert | crit | err | warning | notice | info | debug}")
+ },
+ { "stderr", mu_cfg_callback, NULL,
+ mu_offsetof (struct component, retr[RETR_ERR]), _cb_retr,
+ N_("Redirect program's standard output to the given syslog priority."),
+ N_("prio: {emerg | alert | crit | err | warning | notice | info | debug}")
+ },
+ { "user", mu_cfg_string, NULL,
+ mu_offsetof (struct component, privs.user), NULL,
+ N_("Run with this user privileges.") },
+ { "group", mu_cfg_callback, NULL,
+ mu_offsetof (struct component, privs.groups), _cb_group,
+ N_("Retain supplementary group.") },
+ { "umask", mu_cfg_callback, NULL,
+ mu_offsetof (struct component, umask), _cb_umask,
+ N_("Force this umask."),
+ N_("arg: number") },
+ { "env", mu_cfg_callback, NULL,
+ mu_offsetof (struct component, env), _cb_env,
+ N_("Set program environment. Argument is a list of assignments "
+ "separated by white space."),
+ N_("arg: list") },
+ { "chdir", mu_cfg_string, NULL,
+ mu_offsetof (struct component, dir), NULL,
+ N_("Change to this directory before executing the component."),
+ N_("dir") },
+ { "return-code", mu_cfg_section },
+ { NULL }
+};
+
+static int
+component_section_parser (enum mu_cfg_section_stage stage,
+ const mu_cfg_node_t *node,
+ const char *section_label, void **section_data,
+ void *call_data,
+ mu_cfg_tree_t *tree)
+{
+ static struct component comp;
+ switch (stage)
+ {
+ case mu_cfg_section_start:
+ memset (&comp, 0, sizeof comp);
+ comp.retr[RETR_OUT] = comp.retr[RETR_ERR] = -1;
+ comp.tag = node->tag_label ? xstrdup (node->tag_label) : NULL;
+ *section_data = &comp;
+ break;
+
+ case mu_cfg_section_end:
+ register_prog (&comp);
+ }
+ return 0;
+}
+
+void
+component_cfg_init ()
+{
+ struct mu_cfg_section *section;
+
+ if (mu_create_canned_section ("component", &section))
+ exit (EX_SOFTWARE);
+ section->parser = component_section_parser;
+ section->label = N_("<tag: string>");
+ mu_cfg_section_add_params (section, component_cfg_param);
+}
+
+
+
+struct component default_component;
+
+static int
+_cb_debug (mu_debug_t debug, void *data, char *arg)
+{
+ int rc;
+
+ rc = mu_debug_level_from_string (arg, &debug_level, debug);
+ if (rc)
+ return 0;
+ if (!pmult_debug)
+ mu_debug_create (&pmult_debug, NULL);
+ mu_debug_set_level (pmult_debug, debug_level);
+ return 0;
+}
+
+struct mu_cfg_param pies_cfg_param[] = {
+ { "component", mu_cfg_section },
+ { "debug", mu_cfg_callback, NULL, 0, _cb_debug,
+ N_("Set debug verbosity level.") },
+ { "pidfile", mu_cfg_string, &pidfile, 0, NULL,
+ N_("Write PID to this file.") },
+ { "control-file", mu_cfg_string, &ctlfile, 0, NULL,
+ N_("Set location of the control file.") },
+ { "stat-file", mu_cfg_string, &statfile, 0, NULL,
+ N_("Set location of the statistics output file.") },
+ { "user", mu_cfg_string, &pies_user.user, 0, NULL,
+ N_("Run with this user privileges.") },
+ { "group", mu_cfg_callback, &pies_user.groups, 0, _cb_group,
+ N_("Retain supplementary group.") },
+ { "umask", mu_cfg_callback, &pies_umask, 0, _cb_umask,
+ N_("Force this umask."),
+ N_("arg: number") },
+ { "shutdown-timeout", mu_cfg_uint, &shutdown_timeout, 0, NULL,
+ N_("Wait <n> seconds for all children to shut down."),
+ "n" },
+ { "return-code", mu_cfg_section, &default_component },
+ { NULL }
+};
+
+
+const char *program_version = "pies (" PACKAGE_STRING ")";
+const char *package_bugreport = "<" PACKAGE_BUGREPORT ">";
+static char doc[] = N_("pies -- process inspector and execution supervisor");
+static char args_doc[] = "";
+
+static const char *capa[] = {
+ "common",
+ "logging",
+ "mailer",
+ "debug",
+ NULL
+};
+
+enum {
+ OPT_FOREGROUND=256,
+ OPTION_LOG_TAG,
+ OPT_SYSLOG,
+ OPT_STDERR
+};
+
+#define OPT_RESTART 'R'
+#define OPT_RELOAD 'r'
+#define OPT_STATUS 's'
+#define OPT_STOP 'S'
+
+static struct argp_option options[] = {
+#define GRP 0
+ { "foreground", OPT_FOREGROUND, 0, 0, N_("Remain in foreground."), GRP+1},
+ { "stderr", OPT_STDERR, NULL, 0, N_("Log to stderr"), },
+ { "syslog", OPT_SYSLOG, NULL, 0, N_("Log to syslog"), },
+ { "log-tag", OPTION_LOG_TAG, N_("STRING"), 0,
+ N_("Set the identifier used in syslog messages to STRING"), GRP+1 },
+ { "debug", 'x', N_("LEVEL"), 0,
+ N_("Set debug verbosity level."), GRP+1 },
+#undef GRP
+
+#define GRP 10
+ { "restart-component", OPT_RESTART, NULL, 0,
+ N_("Restart components named in the command line."), GRP+1 },
+ { "reload", OPT_RELOAD, NULL, 0,
+ N_("Reload the running instance of pies."), GRP+1 },
+ { "hup", 0, NULL, OPTION_ALIAS },
+ { "status", OPT_STATUS, NULL, 0,
+ N_("Display info about the running instance."), GRP+1 },
+ { "stop", OPT_STOP, NULL, 0,
+ N_("Stop the running instance."), GRP+1 },
+#undef GRP
+ { NULL }
+};
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ static struct mu_argp_node_list lst;
+
+ switch (key)
+ {
+ case OPT_FOREGROUND:
+ foreground = 1;
+ break;
+
+ case OPT_RELOAD:
+ case OPT_STATUS:
+ case OPT_STOP:
+ case OPT_RESTART:
+ log_to_stderr = 1;
+ command = key;
+ break;
+
+ case OPT_SYSLOG:
+ log_to_stderr = 0;
+ break;
+
+ case OPT_STDERR:
+ log_to_stderr = 1;
+ break;
+
+ case 'x':
+ mu_argp_node_list_new (&lst, "debug", arg);
+ break;
+
+ case OPTION_LOG_TAG:
+ log_tag = arg;
+ break;
+
+ case ARGP_KEY_INIT:
+ mu_argp_node_list_init (&lst);
+ break;
+
+ case ARGP_KEY_FINI:
+ mu_argp_node_list_finish (&lst, NULL, NULL);
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static struct argp argp = {
+ options,
+ parse_opt,
+ args_doc,
+ doc,
+ NULL,
+ NULL,
+ NULL
+};
+
+
+static void
+version (FILE *stream, struct argp_state *state)
+{
+ mailfromd_version ("pies", stream);
+}
+
+
+void
+priv_setup (struct pies_privs_data *pr)
+{
+ if (pr->user)
+ {
+ struct passwd *pw = getpwnam (pr->user);
+ if (!pw)
+ {
+ mu_error (_("No such user: %s"), pr->user);
+ exit (EX_CONFIG);
+ }
+ if (pw && switch_to_privs (pw->pw_uid, pw->pw_gid, pr->groups))
+ exit (EX_SOFTWARE);
+ }
+}
+
+
+#define ACTION_CONT 0
+#define ACTION_STOP 1
+#define ACTION_RESTART 2
+#define ACTION_COMPRELOAD 3
+#define ACTION_DUMPSTATS 4
+
+int action = ACTION_CONT;
+int children_cleanup = 0;
+int got_alarm = 0;
+
+RETSIGTYPE
+sig_handler (int sig)
+{
+ switch (sig)
+ {
+ case SIGCHLD:
+ children_cleanup = 1;
+ break;
+
+ case SIGTERM:
+ case SIGINT:
+ case SIGQUIT:
+ action = ACTION_STOP;
+ mu_diag_output (MU_DIAG_NOTICE, "received signal %d", sig);
+ break;
+
+ case SIGHUP:
+ mu_diag_output (MU_DIAG_NOTICE, "received signal %d", sig);
+ action = ACTION_RESTART;
+ break;
+
+ case SIGALRM:
+ got_alarm = 1;
+ break;
+
+ case SIGUSR1:
+ action = ACTION_COMPRELOAD;
+ break;
+
+ case SIGUSR2:
+ action = ACTION_DUMPSTATS;
+ break;
+ }
+ signal (sig, sig_handler);
+}
+
+void
+signal_setup (RETSIGTYPE (*sf)(int))
+{
+ signal (SIGCHLD, sf);
+ signal (SIGTERM, sf);
+ signal (SIGQUIT, sf);
+ signal (SIGINT, sf);
+ signal (SIGHUP, sf);
+ signal (SIGALRM, sf);
+ signal (SIGUSR1, sf);
+ signal (SIGUSR2, sf);
+}
+
+
+pid_t
+pidfile_read (int must_exist)
+{
+ int c;
+ pid_t n = 0;
+ FILE *fp = fopen (pidfile, "r");
+ if (!fp)
+ {
+ if (must_exist && errno != ENOENT)
+ mu_diag_output (MU_DIAG_ERR,
+ _("cannot open pid file `%s': %s"),
+ pidfile,
+ mu_strerror (errno));
+ return -1;
+ }
+
+ while ((c = fgetc (fp)) != EOF)
+ {
+ if (isdigit (c))
+ n = n * 10 + c - '0';
+ else if (c == '\n')
+ break;
+ else
+ {
+ mu_diag_output (MU_DIAG_ERR,
+ _("unexpected character %#03o in pidfile `%s'"),
+ c, pidfile);
+ return -1;
+ }
+ }
+ fclose (fp);
+ if (kill (n, 0))
+ {
+ mu_diag_output (MU_DIAG_ERR,
+ _("cannot signal master process %lu: %s"),
+ (unsigned long) n, mu_strerror (errno));
+ if (errno == EPERM)
+ return n; /* be on the safe side */
+ return -1;
+ }
+ return n;
+}
+
+
+void
+stop_components ()
+{
+ FILE *fp;
+ size_t size = 0;
+ char *buf = NULL;
+
+ mu_diag_output (MU_DIAG_INFO, _("stopping components"));
+
+ fp = fopen (ctlfile, "r");
+ if (!fp)
+ {
+ mu_error (_("cannot open control file `%s': %s"),
+ ctlfile, mu_strerror (errno));
+ return;
+ }
+ if (unlink (ctlfile))
+ {
+ mu_error (_("cannot unlink control file `%s': %s"),
+ ctlfile, mu_strerror (errno));
+ fclose (fp);
+ return;
+ }
+
+ while (getline (&buf, &size, fp) > 0)
+ {
+ size_t len = strlen (buf);
+ if (len == 0)
+ continue;
+ if (buf[len-1] == '\n')
+ buf[len-1] = 0;
+ progman_stop_component (buf);
+ }
+
+ free (buf);
+ fclose (fp);
+}
+
+int
+request_restart_components (char **argv)
+{
+ FILE *fp;
+ pid_t pid = pidfile_read (1);
+
+ if (pid == -1)
+ return 1;
+
+ fp = fopen (ctlfile, "w");
+ if (!fp)
+ {
+ mu_error (_("cannot open control file `%s': %s"),
+ ctlfile, mu_strerror (errno));
+ return 1;
+ }
+ for (; *argv; argv++)
+ fprintf (fp, "%s\n", *argv);
+ fclose (fp);
+
+ kill (pid, SIGUSR1);
+ return 0;
+}
+
+
+int
+pies_reload ()
+{
+ pid_t pid = pidfile_read (1);
+
+ if (pid == -1)
+ {
+ mu_diag_output (MU_DIAG_CRIT, _("pies is not running"));
+ return 1;
+ }
+
+ mu_diag_output (MU_DIAG_INFO, _("reloading pies at PID %lu"),
+ (unsigned long) pid);
+ return kill (pid, SIGHUP) ? EX_SOFTWARE : 0;
+}
+
+int
+pies_status ()
+{
+ FILE *fp;
+ pid_t pid = pidfile_read (0);
+ int i;
+
+ if (pid == -1)
+ {
+ mu_diag_output (MU_DIAG_INFO, _("pies is not running"));
+ return EX_USAGE;
+ }
+
+ if (kill (pid, SIGUSR2))
+ {
+ mu_diag_output (MU_DIAG_INFO,
+ _("pies is not running, but a pidfile "
+ "is found (pid %lu)"),
+ (unsigned long) pid);
+ return EX_USAGE;
+ }
+
+ mu_diag_output (MU_DIAG_INFO,
+ _("pies is running; PID %lu"),
+ (unsigned long) pid);
+
+ for (i = 0; i < 4 && access (statfile, R_OK); i++)
+ sleep (1);
+
+ fp = fopen (statfile, "r");
+ if (!fp)
+ mu_diag_output (MU_DIAG_ERR, _("cannot open statfile `%s': %s"),
+ statfile, mu_strerror (errno));
+ else
+ {
+ char c;
+
+ if (unlink (statfile))
+ mu_diag_output (MU_DIAG_ERR, _("cannot unlink statfile `%s': %s"),
+ statfile, mu_strerror (errno));
+ while ((c = fgetc (fp)) != EOF)
+ fputc (c, stdout);
+ fclose (fp);
+ }
+ return 0;
+}
+
+int
+pies_stop ()
+{
+ pid_t pid = pidfile_read (1);
+
+ if (pid == -1)
+ {
+ mu_diag_output (MU_DIAG_CRIT, _("pies is not running"));
+ return EX_USAGE;
+ }
+
+ mu_diag_output (MU_DIAG_INFO,
+ _("stopping pies at PID %lu"), (unsigned long) pid);
+ return kill (pid, SIGTERM) ? EX_SOFTWARE : 0;
+}
+
+
+int
+main (int argc, char **argv)
+{
+ int rc;
+ int index;
+
+ mf_init_nls ();
+ if (!program_invocation_short_name)
+ program_invocation_short_name = argv[0];
+ argp_program_version_hook = version;
+ /* Set default logging */
+ log_setup (!stderr_closed_p ());
+ return_code_cfg_init ();
+ component_cfg_init ();
+ mu_argp_init (program_version, package_bugreport);
+ mu_register_all_mailer_formats ();
+ rc = mu_app_init (&argp, capa, pies_cfg_param, argc, argv, 0, &index, NULL);
+ if (rc)
+ exit (EX_CONFIG);
+
+ log_setup (log_to_stderr);
+
+ if (argc != index && command != 'R')
+ {
+ mu_error ("extra command line arguments");
+ exit (EX_CONFIG);
+ }
+
+ switch (command)
+ {
+ case OPT_RESTART:
+ priv_setup (&pies_user);
+ if (pies_umask)
+ umask (pies_umask);
+ exit (request_restart_components (argv + index));
+
+ case OPT_RELOAD:
+ exit (pies_reload ());
+
+ case OPT_STATUS:
+ exit (pies_status ());
+
+ case OPT_STOP:
+ exit (pies_stop ());
+
+ default:
+ priv_setup (&pies_user);
+ if (pies_umask)
+ umask (pies_umask);
+ }
+
+ mu_diag_output (MU_DIAG_INFO, _("%s starting"), program_version);
+
+ if (!foreground && daemon (0, 0) == -1)
+ {
+ mu_error (_("cannot become a daemon: %s"),
+ mu_strerror (errno));
+ exit (EX_SOFTWARE);
+ }
+
+ rc = mu_daemon_create_pidfile (pidfile);
+ if (rc)
+ mu_error (_("Cannot create PID file `%s': %s"),
+ pidfile, mu_strerror (rc));
+
+ if (argv[0][0] != '/')
+ mu_diag_output (MU_DIAG_NOTICE,
+ N_("not started as an absolute pathname; "
+ "SIGHUP will not work"));
+
+ signal_setup (sig_handler);
+
+ progman_start ();
+
+ while (action == ACTION_CONT)
+ {
+ if (!children_cleanup)
+ pause ();
+ if (children_cleanup)
+ {
+ children_cleanup = 0;
+ progman_cleanup (0);
+ }
+ if (got_alarm)
+ {
+ got_alarm = 0;
+ progman_wake_sleeping ();
+ }
+ switch (action)
+ {
+ case ACTION_COMPRELOAD:
+ stop_components ();
+ action = ACTION_CONT;
+ break;
+
+ case ACTION_DUMPSTATS:
+ progman_dump_stats (statfile);
+ action = ACTION_CONT;
+ break;
+ }
+ }
+ progman_stop ();
+
+ if (action == ACTION_RESTART && argv[0][0] == '/')
+ {
+ int i;
+
+ for (i = getmaxfd (); i > 0; i--)
+ close (i);
+
+ mu_daemon_remove_pidfile ();
+ signal_setup (SIG_DFL);
+
+ execv (argv[0], argv);
+ }
+
+ mu_diag_output (MU_DIAG_INFO, _("%s terminated"), program_version);
+ exit (EX_OK);
+}
+
+void
+xalloc_die ()
+{
+ mu_error ("not enough memory");
+ abort ();
+}
+
+/*
+ Local Variables:
+ c-file-style: "gnu"
+ End:
+*/
+/* EOF */

Return to:

Send suggestions and report system problems to the System administrator.