diff options
Diffstat (limited to 'src/progman.c')
-rw-r--r-- | src/progman.c | 557 |
1 files changed, 296 insertions, 261 deletions
diff --git a/src/progman.c b/src/progman.c index 9383aae..cee6775 100644 --- a/src/progman.c +++ b/src/progman.c @@ -1,21 +1,21 @@ -/* This file is part of Mailfromd. +/* This file is part of Pies. Copyright (C) 2007, 2008, 2009 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 of the License, or (at your - option) any later version. + Pies is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. - This program is distributed in the hope that it will be useful, + Pies is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License along - with this program. If not, see <http://www.gnu.org/licenses/>. */ + You should have received a copy of the GNU General Public License + along with Pies. If not, see <http://www.gnu.org/licenses/>. */ #include "pies.h" #define TYPE_COMPONENT 0 #define TYPE_RETR 1 @@ -169,19 +169,17 @@ destroy_prog (struct prog **pp) } static char * redir_tag (struct prog *master, int type) { static char *redirstr[2] = { "stdout", "stderr" }; - char *str = NULL; - if (type < MU_ARRAY_SIZE(redirstr)) - asprintf (&str, "%s/%s", master->tag, redirstr[type]); + char *str; + if (type < ARRAY_SIZE(redirstr)) + str = xasprintf ("%s/%s", master->tag, redirstr[type]); else - asprintf (&str, "%s/%d", master->tag, type); - if (!str) - xalloc_die (); + str = xasprintf ("%s/%d", master->tag, type); return str; } static struct prog * register_redir (int type, struct prog *master) { @@ -258,26 +256,28 @@ prog_rebuild_prerequisites (struct prog *prog) struct prog *p; int dep_all = 0; size_t depc = 0; if (comp->prereq) { - mu_list_count (comp->prereq, &depc); + depc = gl_list_size (comp->prereq); if (depc == 1) { - char *item; - mu_list_get (comp->prereq, 0, (void**)&item); + const char *item = gl_list_get_at (comp->prereq, 0); if (strcmp (item, "all") == 0) { dep_all = 1; for (p = proghead; p; p = p->next) if (p->type == TYPE_COMPONENT) depc++; } else if (strcmp (item, "none") == 0) - mu_list_destroy (&comp->prereq); + { + gl_list_free (comp->prereq); + comp->prereq = NULL; + } } } if (depc == 0) return; @@ -291,22 +291,19 @@ prog_rebuild_prerequisites (struct prog *prog) for (p = proghead; p; p = p->next) if (p->type == TYPE_COMPONENT) prog->prereq[depc++] = p->tag; } else { - mu_iterator_t itr = NULL; - mu_list_get_iterator (comp->prereq, &itr); - for (mu_iterator_first (itr), depc = 0; - !mu_iterator_is_done (itr); mu_iterator_next (itr), depc++) + const void *p; + gl_list_iterator_t itr = gl_list_iterator (comp->prereq); + while (gl_list_iterator_next (&itr, &p, NULL)) { - char *str; - mu_iterator_current (itr, (void**)&str); - prog->prereq[depc] = str; + prog->prereq[depc++] = (char*) p; } - mu_iterator_destroy (&itr); + gl_list_iterator_free (&itr); } } prog->prereq[depc] = NULL; } void @@ -338,15 +335,15 @@ redirect_to_file (struct prog *master, int stream) { struct passwd *pw; int fd = open (master->v.p.comp->redir[stream].v.file, O_RDWR|O_CREAT, 0644 & ~master->v.p.comp->umask); if (fd == -1) { - mu_error (_("cannot open output file %s: %s"), + logmsg (LOG_ERR, _("cannot open output file %s: %s"), master->v.p.comp->redir[stream].v.file, - mu_strerror (errno)); + strerror (errno)); return -1; } /* Fix file ownership */ pw = getpwnam (master->v.p.comp->privs.user); if (pw) chown (master->v.p.comp->redir[stream].v.file, pw->pw_uid, pw->pw_gid); @@ -402,15 +399,15 @@ open_redirector (struct prog *master, int stream) prio = master->v.p.comp->redir[stream].v.prio; while (getline (&buf, &size, fp) > 0) syslog (prio, "%s", buf); _exit (0); case -1: - mu_diag_output (MU_DIAG_CRIT, + logmsg (LOG_CRIT, _("cannot run redirector `%s': fork failed: %s"), - master->tag, mu_strerror (errno)); + master->tag, strerror (errno)); return -1; default: update_redir (stream, master, pid); close (p[0]); return p[1]; @@ -589,13 +586,13 @@ prog_start (struct prog *prog) prog->v.p.count = 0; prog->v.p.timestamp = now; } if (prog->v.p.count > MAXSPAWN) { - mu_error (ngettext ( + logmsg (LOG_NOTICE, ngettext ( "%s is respawning too fast, disabled for %d minute", "%s is respawning too fast, disabled for %d minutes", SLEEPTIME / 60), prog->tag, SLEEPTIME / 60); prog->v.p.timestamp = now; prog->v.p.status = status_sleeping; @@ -606,18 +603,18 @@ prog_start (struct prog *prog) switch (prog->v.p.comp->mode) { case pies_comp_exec: break; case pies_comp_pass_fd: - MU_DEBUG1 (pies_debug, MU_DEBUG_TRACE1, _("unlinking %s\n"), - prog->v.p.comp->pass_fd_socket); + debug (1, (_("unlinking %s"), prog->v.p.comp->pass_fd_socket)); if (unlink (prog->v.p.comp->pass_fd_socket) && errno != ENOENT) { - mu_error (_("cannot unlink %s: %s"), prog->v.p.comp->pass_fd_socket, - mu_strerror (errno)); + logmsg (LOG_ERR, _("cannot unlink %s: %s"), + prog->v.p.comp->pass_fd_socket, + strerror (errno)); return; } /* fall through */ case pies_comp_accept: prog->v.p.socket = create_socket (prog->v.p.comp->socket_url, @@ -627,13 +624,13 @@ prog_start (struct prog *prog) { prog->v.p.status = status_disabled; return; } if (listen (prog->v.p.socket, 8)) { - mu_error ("listen: %s", mu_strerror (errno)); + logmsg (LOG_ERR, "listen: %s", strerror (errno)); close (prog->v.p.socket); prog->v.p.socket = -1; prog->v.p.status = status_disabled; return; } break; @@ -641,66 +638,65 @@ prog_start (struct prog *prog) case pies_comp_inetd: /* Wait until an incoming connection is requested */ if (prog->v.p.socket == -1) return; } - MU_DEBUG1 (pies_debug, MU_DEBUG_TRACE1, _("starting %s\n"), prog->tag); + debug (1, (_("starting %s"), prog->tag)); if (prog->v.p.comp->rmfile) { - MU_DEBUG1 (pies_debug, MU_DEBUG_TRACE1, _("unlinking %s\n"), - prog->v.p.comp->rmfile); + debug (1, (_("unlinking %s"), prog->v.p.comp->rmfile)); if (unlink (prog->v.p.comp->rmfile) && errno != ENOENT) - mu_error (_("%s: cannot remove file `%s': %s"), - prog->tag, prog->v.p.comp->rmfile, mu_strerror (errno)); + logmsg (LOG_ERR, _("%s: cannot remove file `%s': %s"), + prog->tag, prog->v.p.comp->rmfile, strerror (errno)); } redir[RETR_OUT] = open_redirector (prog, RETR_OUT); redir[RETR_ERR] = open_redirector (prog, RETR_ERR); switch (pid = fork ()) { /* The child branch. */ case 0: signal_setup (SIG_DFL); if (prog->v.p.comp->dir) { - MU_DEBUG1 (pies_debug, MU_DEBUG_TRACE1, _("chdir %s\n"), - prog->v.p.comp->dir); + debug (1, (_("chdir %s"), prog->v.p.comp->dir)); if (chdir (prog->v.p.comp->dir)) - mu_error (_("%s: cannot change to directory %s: %s"), - prog->tag, prog->v.p.comp->dir, mu_strerror (errno)); + logmsg (LOG_ERR, _("%s: cannot change to directory %s: %s"), + prog->tag, prog->v.p.comp->dir, strerror (errno)); } environ = env_setup (prog->v.p.comp->env); - if (mu_debug_check_level (pies_debug, MU_DEBUG_TRACE4)) + if (debug_level >= 4) { int i; for (i = 0; environ[i]; i++) - __MU_DEBUG1 (pies_debug, MU_DEBUG_TRACE4, "%s ", environ[i]); - mu_debug_printf (pies_debug, MU_DEBUG_TRACE4, "\n"); + logmsg_printf (LOG_DEBUG, "%s ", environ[i]); + logmsg_printf (LOG_DEBUG, "\n"); } - mf_priv_setup (&prog->v.p.comp->privs); + + pies_priv_setup (&prog->v.p.comp->privs); if (prog->v.p.comp->umask) umask (prog->v.p.comp->umask); set_limits (prog->tag, prog->v.p.comp->limits ? prog->v.p.comp->limits : pies_limits); - if (mu_debug_check_level (pies_debug, MU_DEBUG_TRACE1)) + if (debug_level >= 1) { - char *cmdline; - if (mu_argcv_string (prog->v.p.argc, prog->v.p.comp->argv, - &cmdline) == 0) + int i; + logmsg_printf (LOG_DEBUG, "executing"); + for (i = 0; i < prog->v.p.argc; i++) { - __MU_DEBUG1 (pies_debug, MU_DEBUG_TRACE1, - "executing %s\n", cmdline); - free (cmdline); + /* FIXME: quote */ + logmsg_printf (LOG_DEBUG, " %s", prog->v.p.comp->argv[i]); } + logmsg_printf (LOG_DEBUG, "\n"); } switch (prog->v.p.comp->mode) { case pies_comp_pass_fd: case pies_comp_exec: @@ -743,21 +739,21 @@ prog_start (struct prog *prog) close (i); } execvp (prog->v.p.comp->program ? prog->v.p.comp->program : prog->v.p.comp->argv[0], prog->v.p.comp->argv); - openlog (MU_LOG_TAG (), LOG_PID, mu_log_facility); + openlog (log_tag, LOG_PID, prog->v.p.comp->facility); syslog (LOG_CRIT, _("cannot start `%s': %s"), prog->tag, - mu_strerror (errno)); + strerror (errno)); _exit (EX_SOFTWARE); case -1: - mu_diag_output (MU_DIAG_CRIT, + logmsg (LOG_CRIT, _("cannot run `%s': fork failed: %s"), - prog->tag, mu_strerror (errno)); + prog->tag, strerror (errno)); break; default: if (prog->v.p.comp->mode == pies_comp_pass_fd) { sleep(1); @@ -768,54 +764,35 @@ prog_start (struct prog *prog) close (prog->v.p.socket); prog->pid = pid; prog->v.p.status = status_enabled; } } -int -pies_check_acl (mu_acl_t acl, struct sockaddr *s, int salen) +static int +check_acl (pies_acl_t acl, struct sockaddr *s, int salen) { - mu_acl_result_t res; + struct acl_input input; int rc; if (!acl) return 0; - rc = mu_acl_check_sockaddr (acl, s, salen, &res); - if (rc) + input.addr = s; + input.addrlen = salen; + input.user = NULL; + input.groups = NULL; + + rc = pies_acl_check (acl, &input, 1); + if (rc == 0) { - char *p = mu_sockaddr_to_astr (s, salen); - mu_error (_("access from %s blocked: cannot check ACLs: %s"), - p, mu_strerror (rc)); + char *p = sockaddr_to_astr (s, salen); + logmsg (LOG_ERR, _("access from %s blocked"), p); free (p); return 1; } - switch (res) - { - case mu_acl_result_undefined: - { - char *p = mu_sockaddr_to_astr (s, salen); - mu_diag_output (MU_DIAG_INFO, - _("%s: undefined ACL result; access allowed"), - p); - free (p); - } - break; - - case mu_acl_result_accept: - break; - - case mu_acl_result_deny: - { - char *p = mu_sockaddr_to_astr (s, salen); - mu_error (_("Access from %s blocked."), p); - free (p); - return 1; - } - } return 0; } int progman_accept (int socket) { @@ -828,84 +805,85 @@ progman_accept (int socket) } addr; socklen_t addrlen = sizeof addr; fd = accept (socket, (struct sockaddr*) &addr, &addrlen); if (fd == -1) { - mu_error (_("accept failed: %s"), mu_strerror (errno)); + logmsg (LOG_ERR, _("accept failed: %s"), strerror (errno)); return 1; } p = prog_lookup_by_socket (socket); if (!p) { - mu_error (_("INTERNAL ERROR: no matching prog for fd %d"), socket); + logmsg (LOG_EMERG, + _("INTERNAL ERROR: no matching prog for fd %d"), socket); close (fd); return 1; } - if (mu_debug_check_level (pies_debug, MU_DEBUG_TRACE1)) + if (debug_level >= 1) { - char *s = mu_sockaddr_to_astr ((struct sockaddr *)&addr, addrlen); - __MU_DEBUG2 (pies_debug, MU_DEBUG_TRACE1, "%s wants %s\n", s, p->tag); + char *s = sockaddr_to_astr ((struct sockaddr *)&addr, addrlen); + logmsg (LOG_DEBUG, "%s wants %s", s, p->tag); free (s); } - - if (pies_check_acl (p->v.p.comp->acl, (struct sockaddr *)&addr, addrlen) - || pies_check_acl (pies_acl, (struct sockaddr *)&addr, addrlen)) + + if (check_acl (p->v.p.comp->acl, (struct sockaddr *)&addr, addrlen) + || check_acl (pies_acl, (struct sockaddr *)&addr, addrlen)) { close (fd); return 1; } - + p = register_prog0 (p->v.p.comp, -1); p->v.p.socket = fd; prog_start (p); close (fd); p->v.p.socket = -1; return 0; } void component_fixup_depend (struct component *comp) { - mu_iterator_t itr; + const void *p; + gl_list_iterator_t itr; if (comp->depend == NULL) return; - mu_list_get_iterator (comp->depend, &itr); - for (mu_iterator_first (itr); - !mu_iterator_is_done (itr); mu_iterator_next (itr)) + itr = gl_list_iterator (comp->depend); + while (gl_list_iterator_next (&itr, &p, NULL)) { - char *tag; + const char *tag = p; struct component *tgt; - mu_iterator_current (itr, (void**)&tag); tgt = progman_lookup_component (tag); if (!tgt) { - mu_error (_("component %s declares dependency target %s, " - "which is not declared"), - comp->tag, tag); + logmsg (LOG_ERR, + _("component %s declares dependency target %s, " + "which is not declared"), + comp->tag, tag); continue; } if (!tgt->prereq) { - int rc = mu_list_create (&tgt->prereq); - if (rc) - { - mu_error (_("cannot create list: %s"), mu_strerror (rc)); - continue; - } + tgt->prereq = gl_list_create_empty(&gl_linked_list_implementation, + NULL, + NULL, + NULL, + false); } /* FIXME: memory allocation */ - mu_list_append (tgt->prereq, xstrdup (comp->tag)); + gl_list_add_last (tgt->prereq, xstrdup (comp->tag)); } - mu_list_destroy (&comp->depend); + gl_list_free (comp->depend); + comp->depend = NULL; } void fixup_prerequisites () { struct prog *prog; @@ -927,21 +905,21 @@ rebuild_prerequisites () void print_dep (struct prog *prog) { pies_depmap_pos_t pos; unsigned n; - mu_diag_printf (MU_DIAG_NOTICE, "%s -> ", prog->tag); + logmsg_printf (LOG_NOTICE, "%s -> ", prog->tag); for (n = depmap_first (depmap, depmap_col, prog->idx, &pos); n != (unsigned)-1; n = depmap_next (depmap, pos)) { struct prog *dp = prog_lookup_by_idx (n); - mu_diag_printf (MU_DIAG_NOTICE, "%s -> ", dp->tag); + logmsg_printf (LOG_NOTICE, "%s -> ", dp->tag); } - mu_diag_printf (MU_DIAG_NOTICE, "%s\n", prog->tag); + logmsg_printf (LOG_NOTICE, "%s\n", prog->tag); } void progman_dump_prereq () { struct prog *prog; @@ -1000,13 +978,13 @@ progman_build_depmap () for (i = 0; prog->prereq[i]; i++) { struct prog *dep = prog_lookup_by_tag (prog->prereq[i]); if (!dep) { prog->v.p.status = status_disabled; - mu_error (_("component %s depends on %s, " + logmsg (LOG_ERR, _("component %s depends on %s, " "which is not declared"), prog->tag, prog->prereq[i]); rc++; } else depmap_set (depmap, prog->idx, dep->idx); @@ -1015,13 +993,13 @@ progman_build_depmap () dp = depmap_copy (depmap); depmap_tc (dp); for (i = 0; i < numprog; i++) if (depmap_isset (dp, i, i)) { prog = prog_lookup_by_idx (i); - mu_error (_("component %s depends on itself"), prog->tag); + logmsg (LOG_ERR, _("component %s depends on itself"), prog->tag); print_dep (prog); prog->v.p.status = status_disabled; rc++; } free (dp); return rc; @@ -1062,13 +1040,13 @@ progman_recompute_alarm () { struct prog *prog; time_t now = time (NULL); time_t alarm_time = 0, x; recompute_alarm = 0; - MU_DEBUG (pies_debug, MU_DEBUG_TRACE2, "Recomputing alarm settings\n"); + debug (2, ("Recomputing alarm settings")); for (prog = proghead; prog; prog = prog->next) if (IS_PROG (prog)) { switch (prog->v.p.status) { case status_sleeping: @@ -1084,27 +1062,26 @@ progman_recompute_alarm () break; default: break; } } - MU_DEBUG1 (pies_debug, MU_DEBUG_TRACE2, "alarm=%lu\n", - (unsigned long)alarm_time); + debug (2, ("alarm=%lu", (unsigned long)alarm_time)); if (alarm_time) alarm (alarm_time); } void progman_start () { struct prog *prog; recompute_alarm = 0; - MU_DEBUG (pies_debug, MU_DEBUG_TRACE1, "Starting components\n"); + debug (1, ("Starting components")); for (prog = proghead; prog; prog = prog->next) if (IS_PROG (prog) && ((prog->v.p.status == status_enabled && prog->pid == 0) || prog->v.p.status == status_sleeping)) prog_start (prog); } @@ -1112,14 +1089,15 @@ progman_start () static void check_stopping (struct prog *prog, time_t now) { if (now - prog->v.p.timestamp >= shutdown_timeout) { if (prog->pid == 0) - mu_error (_("INTERNAL ERROR: attempting to kill unexisting process %s"), - prog->tag); + logmsg (LOG_EMERG, + _("INTERNAL ERROR: attempting to kill unexisting process %s"), + prog->tag); else kill (prog->pid, SIGKILL); } else recompute_alarm = 1; } @@ -1127,14 +1105,13 @@ check_stopping (struct prog *prog, time_t now) void progman_wake_sleeping () { struct prog *prog; time_t now = time (NULL); - MU_DEBUG (pies_debug, MU_DEBUG_TRACE1, - "Managing sleeping/stopping components\n"); + debug (1, ("Managing sleeping/stopping components")); for (prog = proghead; prog; prog = prog->next) if (IS_PROG (prog)) { switch (prog->v.p.status) { @@ -1171,14 +1148,13 @@ prog_start_prerequisites (struct prog *prog) int i; int ret; unsigned settle_timeout = 0; if (!prog->prereq) return 0; /* Ok to startup */ - MU_DEBUG1 (pies_debug, MU_DEBUG_TRACE1, "Starting prerequisites of %s\n", - prog->tag); + debug (1, ("Starting prerequisites of %s", prog->tag)); ret = 0; for (i = 0; prog->prereq[i]; i++) { struct prog *dp = prog_lookup_by_tag (prog->prereq[i]); if (!IS_PROG (dp)) /* Skip redirectors */ continue; @@ -1241,15 +1217,13 @@ prog_stop_dependents (struct prog *prog) { struct prog *dp = prog_lookup_by_idx (n); if (!dp) /* should not happen */ continue; if (!warned && dp->pid) { - MU_DEBUG1 (pies_debug, MU_DEBUG_TRACE1, - "Stopping dependencies of %s\n", - prog->tag); + debug (1, ("Stopping dependencies of %s", prog->tag)); warned = 1; } prog_stop (dp, SIGTERM); } free (pos); } @@ -1265,25 +1239,22 @@ prog_stop (struct prog *prog, int sig) { prog->v.p.status = status_stopping; prog->v.p.timestamp = time (NULL); recompute_alarm = 1; } } - MU_DEBUG2 (pies_debug, MU_DEBUG_TRACE1, - "Stopping %s (%lu)\n", - prog->tag, (unsigned long) prog->pid); + debug (1, ("Stopping %s (%lu)", prog->tag, (unsigned long) prog->pid)); kill (prog->pid, sig); } static void prog_stop_all (int sig) { struct prog *prog; - MU_DEBUG1 (pies_debug, MU_DEBUG_TRACE1, - "Stopping all components (signal %d)\n", sig); + debug (1, ("Stopping all components (signal %d)", sig)); for (prog = progtail; prog; prog = prog->prev) if (IS_PROG (prog) && (prog->v.p.status == status_enabled || prog->v.p.status == status_stopping)) prog_stop (prog, sig); } @@ -1307,158 +1278,235 @@ progman_stop () static void print_status (char *tag, pid_t pid, int status, int expect_term) { if (WIFEXITED (status)) { if (WEXITSTATUS (status) == 0) - MU_DEBUG2 (pies_debug, MU_DEBUG_TRACE1, - _("%s (%lu) exited successfully\n"), - tag, (unsigned long) pid); + debug (1, (_("%s (%lu) exited successfully"), + tag, (unsigned long) pid)); else - mu_diag_output (MU_DIAG_ERR, + logmsg (LOG_ERR, _("%s (%lu) failed with status %d"), tag, (unsigned long) pid, WEXITSTATUS (status)); } else if (WIFSIGNALED (status)) { int prio; if (expect_term && WTERMSIG (status) == SIGTERM) - prio = MU_DIAG_DEBUG; + prio = LOG_DEBUG; else - prio = MU_DIAG_ERR; + prio = LOG_ERR; - mu_diag_output (prio, + logmsg (prio, _("%s (%lu) terminated on signal %d"), tag, (unsigned long) pid, WTERMSIG (status)); } else if (WIFSTOPPED (status)) - mu_diag_output (MU_DIAG_ERR, + logmsg (LOG_ERR, _("%s (%lu) stopped on signal %d"), tag, (unsigned long) pid, WSTOPSIG (status)); #ifdef WCOREDUMP else if (WCOREDUMP (status)) - mu_diag_output (MU_DIAG_ERR, + logmsg (LOG_ERR, _("%s (%lu) dumped core"), tag, (unsigned long) pid); #endif else - mu_diag_output (MU_DIAG_ERR, + logmsg (LOG_ERR, _("%s (%lu) terminated with unrecognized status"), tag, (unsigned long) pid); } -static void -send_msg (mu_address_t rcpt, mu_message_t msg) +static int +wait_for_child (pid_t pid) { - mu_mailer_t mailer; - int rc; - const char *s; + int rc = 127; + int wait_status; - mu_address_sget_email (rcpt, 1, &s); - MU_DEBUG1 (pies_debug, MU_DEBUG_TRACE1, "Sending email to %s\n", s); + while (waitpid (pid, &wait_status, 0) == -1) + if (errno != EINTR) + { + logmsg (LOG_ERR, _("waitpid failed: %s"), strerror (errno)); + return EX_OSERR; + } - rc = mu_mailer_create (&mailer, NULL); - if (rc) + if (WIFSIGNALED (wait_status)) { - const char *mailer_url; - mu_mailer_get_url_default (&mailer_url); + int sig = WTERMSIG (wait_status); + logmsg (LOG_ERR, _("child died with signal %d"), sig); + } + else if (WIFEXITED (wait_status)) + { + rc = WEXITSTATUS (wait_status); + if (rc != 0) + logmsg (LOG_ERR, _("child returned status %d"), rc); + } + return rc; +} - mu_error (_("Cannot create mailer `%s': %s"), - mailer_url, mu_strerror (rc)); +void +send_msg (char *rcpts, const char *msg_text) +{ + int i; + pid_t pid; + struct wordsplit ws; + int p[2]; + size_t size; + + ws.ws_offs = 3; /* sendmail -oi -t */ + ws.ws_delim = ","; + if (wordsplit (rcpts, &ws, + WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_DELIM | WRDSF_DOOFFS)) + { + logmsg (LOG_ERR, + _("cannot parse recipient address list (%s)"), + rcpts); return; } - - /* FIXME: mailer flags? */ - rc = mu_mailer_open (mailer, 0); - if (rc) + + ws.ws_wordv[0] = "/usr/sbin/sendmail"; /* FIXME: path */ + ws.ws_wordv[1] = "-oi"; + ws.ws_wordv[2] = "-t"; + for (i = 0; i < ws.ws_wordc; i++) + { + char *arg = ws.ws_wordv[3 + i]; + size_t len; + + while (*arg && c_isblank (*arg)) + arg++; + len = strlen (arg); + if (len > 0) + { + while (len > 0 && c_isblank(arg[len - 1])) + len--; + } + if (len == 0) + continue; //FIXME + if (arg[0] == '<' && arg[len-1] == '>') + { + arg++; + len -= 2; + } + if (len == 0) + continue; //FIXME + memmove (ws.ws_wordv[3 + i], arg, len); + ws.ws_wordv[3 + i][len] = 0; + } + + /* Fork a child: */ + pid = fork (); + if (pid <= 0) + wordsplit_free (&ws); + + if (pid < 0) { - const char *mailer_url; - mu_mailer_get_url_default (&mailer_url); + logmsg (LOG_ERR, + _("cannot send mail: fork failed: %s"), strerror (errno)); + return; + } + + if (pid == 0) + //FIXME: SIGCHLD Handler? */ + return; - mu_mailer_destroy(&mailer); - mu_error (_("opening mailer `%s' failed: %s"), - mailer_url, mu_strerror (rc)); + /* Child process */ + /* ============= */ + signal (SIGCHLD, SIG_DFL); + signal (SIGPIPE, SIG_DFL); + + if (pipe (p)) + { + logmsg (LOG_ERR, _("cannot send mail: pipe failed: %s"), + strerror (errno)); + wordsplit_free (&ws); + exit (EX_OSERR); + } + + pid = fork (); + if (pid <= 0) + wordsplit_free (&ws); + + if (pid < 0) + { + logmsg (LOG_ERR, + _("cannot send mail: fork failed: %s"), strerror (errno)); return; } - - rc = mu_mailer_send_message (mailer, msg, NULL, rcpt); - mu_mailer_destroy (&mailer); - if (rc) - mu_error (_("cannot send message: %s"), mu_strerror (rc)); + + if (pid) + { + /* Grand-child */ + /* =========== */ + if (p[0] != 0 && p[1] != 0) + close (0); + close (p[1]); + dup2 (p[0], 0); + execv (ws.ws_wordv[0], ws.ws_wordv); + exit (127); + } + + /* Child again */ + close (p[0]); + + size = strlen (msg_text); + while (size) + { + ssize_t rc = write (p[1], msg_text, size); + if (rc <= 0) + { + logmsg (LOG_ERR, _("cannot write to pipe: %s"), + rc == 0 ? "EOF" : strerror (errno)); + break; + } + size -= rc; + msg_text += rc; + } + close (p[1]); + + exit (wait_for_child (pid)); } static const char default_termination_message[] = "From: <>\n" "X-Agent: ${canonical-program-name} (${package} ${version})\n" "Subject: Component ${component} terminated with code ${retcode}.\n" "\n"; static void -vartab_define_project (mu_vartab_t vtab) -{ - static struct { - char *name; - char *value; - } ptab[] = { - { "canonical-program-name", "pies" }, - { "package", PACKAGE }, - { "version", PACKAGE_VERSION }, - { "mu-version", MAILUTILS_VERSION }, - { NULL } - }; - int i; - - for (i = 0; ptab[i].name; i++) - mu_vartab_define (vtab, ptab[i].name, ptab[i].value, 1); -} - - -static void notify (const char *tag, int status, struct action *act) { - mu_vartab_t vtab; + struct metadef mdef[] = + { + { "canonical-program-name", "pies" }, + { "package", PACKAGE }, + { "version", PACKAGE_VERSION }, +#define COMPONENT_IDX 3 + { "component", NULL }, +#define RETCODE_IDX 4 + { "retcode", NULL }, +#define PROGRAM_NAME_IDX 5 + { "program-name", NULL }, + { NULL } + }; + char *msg_text = NULL; - mu_message_t msg = NULL; - mu_stream_t stream = NULL; - int rc; char buf[INT_BUFSIZE_BOUND (uintmax_t)]; - mu_vartab_create (&vtab); - mu_vartab_define (vtab, "component", tag, 1); - mu_vartab_define (vtab, "retcode", umaxtostr (status, buf), 1); - mu_vartab_define (vtab, "program-name", mu_program_name, 1); - vartab_define_project (vtab); - rc = mu_vartab_expand (vtab, - act->message ? - act->message : default_termination_message, - &msg_text); - mu_vartab_destroy (&vtab); - if (rc) - { - mu_error (_("cannot expand message body: %s"), mu_strerror (rc)); - /* FIXME: Notify anyway? */ - return; - } + mdef[COMPONENT_IDX].value = (char*) tag; + mdef[RETCODE_IDX].value = umaxtostr (status, buf); + mdef[PROGRAM_NAME_IDX].value = (char*) program_name; + msg_text = meta_expand_string (act->message ? + act->message : default_termination_message, + mdef, NULL); - rc = mu_message_create (&msg, NULL); - if (rc) - { - mu_error (_("cannot create message: %s"), mu_strerror (rc)); - free (msg_text); - } - - mu_message_get_stream (msg, &stream); - mu_stream_write (stream, msg_text, strlen (msg_text), 0, NULL); + send_msg (act->addr, msg_text); free (msg_text); - - send_msg (act->addr, msg); - mu_message_destroy (&msg, mu_message_get_owner (msg)); } static int status_matches_p (struct action *act, unsigned status) { int i; @@ -1484,22 +1532,21 @@ run_command (struct action *act, struct prog *prog, unsigned retcode, saved_handler = signal (SIGPIPE, SIG_IGN); pid = fork (); if (pid == (pid_t) -1) { - mu_error ("fork: %s", mu_strerror (errno)); + logmsg (LOG_ERR, "fork: %s", strerror (errno)); return; } if (pid == 0) { int i; - MU_DEBUG1 (pies_debug, MU_DEBUG_TRACE1, - _("executing %s\n"), act->command); + debug (1, (_("executing %s"), act->command)); /* Child */ setenv ("PIES_VERSION", PACKAGE_VERSION, 1); setenv ("PIES_COMPONENT", prog->tag, 1); setenv ("PIES_PID", umaxtostr (child_pid, buf), 1); if (retcode & STATUS_SIG_BIT) setenv ("PIES_SIGNAL", umaxtostr (STATUS_CODE (retcode), buf), 1); @@ -1519,13 +1566,13 @@ run_command (struct action *act, struct prog *prog, unsigned retcode, } /* Master */ while (waitpid (pid, &status, 0) == -1) if (errno != EINTR) { - mu_error ("waitpid: %s", mu_strerror (errno)); + logmsg (LOG_ERR, "waitpid: %s", strerror (errno)); break; } signal (SIGPIPE, saved_handler); print_status (act->command, pid, status, 1); } @@ -1537,13 +1584,13 @@ progman_cleanup (int expect_term) int status; while ((pid = waitpid (-1, &status, WNOHANG)) > 0) { struct prog *prog = prog_lookup_by_pid (pid); if (!prog) { - mu_diag_output (MU_DIAG_NOTICE, + logmsg (LOG_NOTICE, _("subprocess %lu finished"), (unsigned long) pid); continue; } print_status (prog->tag, prog->pid, status, expect_term); prog->pid = 0; @@ -1589,13 +1636,13 @@ progman_cleanup (int expect_term) { case action_restart: prog_start (prog); break; case action_disable: - mu_diag_output (MU_DIAG_NOTICE, + logmsg (LOG_NOTICE, _("disabling component %s: " "exited with code %d"), prog->tag, status); prog->v.p.status = status_disabled; } if (act->addr) @@ -1610,14 +1657,13 @@ progman_cleanup (int expect_term) } } } else { /* It was a redirector of an already finished inetd process. */ - MU_DEBUG1 (pies_debug, MU_DEBUG_TRACE1, - _("removing inetd redirector %s\n"), prog->tag); + debug (1, (_("removing inetd redirector %s"), prog->tag)); destroy_prog (&prog); } } if (!expect_term) /* This will also recompute alarm settings, if necessary */ @@ -1626,13 +1672,13 @@ progman_cleanup (int expect_term) void progman_stop_component (const char *name) { struct prog *prog; - mu_diag_output (MU_DIAG_INFO, _("stopping component `%s'"), name); + logmsg (LOG_INFO, _("stopping component `%s'"), name); for (prog = proghead; prog; prog = prog->next) if (IS_PROG (prog) && strcmp (prog->tag, name) == 0) { switch (prog->v.p.status) { case status_enabled: @@ -1643,46 +1689,46 @@ progman_stop_component (const char *name) case status_disabled: if (!prog->v.p.comp->disabled) prog->v.p.status = status_enabled; break; default: - mu_diag_output (MU_DIAG_INFO, + logmsg (LOG_INFO, _("stopping component `%s': " "component not started"), name); } } } void progman_dump_stats (const char *filename) { FILE *fp; struct prog *prog; - char *s; - int rc; char *tmpfile = NULL; asprintf (&tmpfile, "%s.%lu", filename, (unsigned long) getpid ()); if (!tmpfile) { - mu_error ("%s", mu_strerror (ENOMEM)); + logmsg (LOG_ERR, "%s", strerror (ENOMEM)); return; } - mu_diag_output (MU_DIAG_INFO, _("dumping statistics to `%s'"), tmpfile); + logmsg (LOG_INFO, _("dumping statistics to `%s'"), tmpfile); fp = fopen (tmpfile, "w"); if (!fp) { - mu_error (_("cannot open file `%s' for writing: %s"), - tmpfile, mu_strerror (errno)); + logmsg (LOG_ERR, _("cannot open file `%s' for writing: %s"), + tmpfile, strerror (errno)); return; } for (prog = proghead; prog; prog = prog->next) { + int i; + switch (prog->type) { case TYPE_COMPONENT: fprintf (fp, "component %s ", prog->tag); if (prog->pid) { @@ -1701,21 +1747,16 @@ progman_dump_stats (const char *filename) else if (prog->v.p.status == status_disabled) fprintf (fp, _("[disabled]")); else if (prog->v.p.status == status_listener) fprintf (fp, _("[listener]")); else fprintf (fp, _("[not running]")); - if (rc = mu_argcv_string (prog->v.p.argc, prog->v.p.comp->argv, &s)) - { - mu_error (_("cannot convert argument list: %s"), - mu_strerror (rc)); - } - else + for (i = 0; i < prog->v.p.argc; i++) { - fprintf (fp, " %s", s); - free (s); + /* FIXME: quote as appropriate */ + fprintf (fp, " %s |