diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2021-06-16 17:22:20 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2021-06-16 17:26:01 +0300 |
commit | ec3c578709f1a25af5fc1b3e9ee50583e1fc4b05 (patch) | |
tree | 2fba0a0c2a9f541dc59a51c2522901aa87f7d8bc /mockmta.c | |
parent | 30437b7361c5763309639b1bf0aa015e2ad057ed (diff) | |
download | mockmta-ec3c578709f1a25af5fc1b3e9ee50583e1fc4b05.tar.gz mockmta-ec3c578709f1a25af5fc1b3e9ee50583e1fc4b05.tar.bz2 |
Version 1.0v1.0
* mockmta.c: Implement logging. Write pidfile, if requested.
New options: -P, -?, -v.
Various bugfixes.
* .gitignore: Update
* COPYING: New file.
* Makefile.am: Distribute COPYING; install mockmail.1
* README: New file.
* configure.ac: Organizational changes.
* mockmta.1: New file.
Diffstat (limited to 'mockmta.c')
-rw-r--r-- | mockmta.c | 536 |
1 files changed, 375 insertions, 161 deletions
@@ -1,75 +1,18 @@ -/* - NAME - mockmta - mock MTA server for use in test suites - - SYNOPSIS - mockmta [-d] [-c CERT] [-a CA] [-k KEY] [-p PORT] [-t SEC] MAILBOX - - DESCRIPTION - Starts a mock MTA, which behaves almost identically to the real one, - except that it listens on localhost only and delivers all messages - to the given MAILBOX file. - - No attempts are made to interpret the data supplied during the STMP - transaction, such as domain names, email addresses, etc, neither is - the material supplied in the DATA command verified to be a valid - email message. Except for being written to MAILBOX, these data are - ignored. - - Mockmta can work both as a foreground process and as a standalone - daemon. The foreground mode can be used with GNU pies as follows: - - component sm { - mode inetd; - socket inet://0.0.0.0:25; - command "/usr/bin/mockmta /var/spool/mail/dropmail"; - } - - When run as a daemon, mockmta starts listening on localhost port - PORT (default 25). - - To support TLS, the program must be compiled with the GnuTLS library. - - To enable the STARTTLS ESMTP command, supply the names of the certificate - (-c CERT) and certificate key (-k KEY) files. - - OPTIONS - -a CA Name of certificate authority file. - -c CERT Name of the certificate file. - -d Daemon mode. - -f Remain in foreground (implies -d). - -k KEY Name of the certificate key file. - -p PORT Listen on this port. - -t SEC Set SMTP timeout. - - EXIT CODES - 0 Success. - 1 Failure (see stderr for details). - 2 Timed out waiting for I/O. - 3 Command line usage error. - - BUGS - At most 32 RCPT commands are allowed. - - AUTHOR - Sergey Poznyakoff <gray@gnu.org> - - LICENSE - Copyright (C) 2020-2021 Free Software Foundation, Inc. - - Mockmta 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. - - Mockmta is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. - +/* mockmta - mock MTA server for use in test suites + * Copyright (C) 2020-2021 Sergey Poznyakoff + * + * Mockmta 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. + * + * Mockmta is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */ #ifdef HAVE_CONFIG_H # include <config.h> @@ -88,20 +31,20 @@ #include <netinet/in.h> #include <pthread.h> #include <signal.h> -#include <paths.h> +#ifdef HAVE_PATHS_H +# include <paths.h> +#endif +#ifndef _PATH_DEVNULL +# define _PATH_DEVNULL "/dev/null" +#endif char *progname; char *mailbox_name; int daemon_opt; int smtp_timeout = 5*60; int port = 25; - -int msgid = 1; -pthread_mutex_t msgid_mutex = PTHREAD_MUTEX_INITIALIZER; - -#ifndef _PATH_DEVNULL -# define _PATH_DEVNULL "/dev/null" -#endif +int log_level = LOG_INFO; +char *pidfile; enum { @@ -120,72 +63,193 @@ enum EX_USAGE }; + +#define SID_ABC "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" +#define SID_ABC_LEN (sizeof (SID_ABC) - 1) +#define SID_ABC_LEN_SQR (SID_ABC_LEN * SID_ABC_LEN) + +#define SID_BUF_LEN 9 + +/* + * Generate (almost) unique session ID. The idea borrowed from Sendmail + * queue ID. + */ +int +generate_sid (char *sidbuf) +{ + static int init; + static unsigned int seqno = 0; + static pthread_mutex_t sid_mutex = PTHREAD_MUTEX_INITIALIZER; + static char abc[] = SID_ABC; + + struct timeval t; + struct tm *tm; + unsigned int n; + char *p; + + gettimeofday (&t, NULL); + + pthread_mutex_lock (&sid_mutex); + if (!init) + { + seqno = getpid () + t.tv_sec + t.tv_usec; + init = 1; + } + + n = seqno++ % SID_ABC_LEN_SQR; + pthread_mutex_unlock (&sid_mutex); + + tm = gmtime (&t.tv_sec); + sidbuf[0] = abc[tm->tm_year % SID_ABC_LEN]; + sidbuf[1] = abc[tm->tm_mon]; + sidbuf[2] = abc[tm->tm_mday]; + sidbuf[3] = abc[tm->tm_hour]; + sidbuf[4] = abc[tm->tm_min % SID_ABC_LEN]; + sidbuf[5] = abc[tm->tm_sec % SID_ABC_LEN]; + sidbuf[6] = abc[n / SID_ABC_LEN]; + sidbuf[7] = abc[n % SID_ABC_LEN]; + sidbuf[8] = 0; + + p = strdup (sidbuf); + if (!p) + return errno; + return 0; +} + +static void (*logger) (int, char const *fmt, ...); + +static pthread_key_t sdat_key; +static pthread_once_t sdat_key_once = PTHREAD_ONCE_INIT; + +struct session_data +{ + char sid[SID_BUF_LEN]; + int nomem; + char *fmtbuf; + size_t fmtsize; +}; + +static void +sdat_free (void *f) +{ + free (f); +} + +static void +make_sdat_key (void) +{ + pthread_key_create (&sdat_key, sdat_free); +} + +static struct session_data * +priv_get_session_data (void) +{ + struct session_data *sdat; + pthread_once (&sdat_key_once, make_sdat_key); + if ((sdat = pthread_getspecific (sdat_key)) == NULL) + { + sdat = calloc (1, sizeof(*sdat)); + if (sdat == NULL) + logger (LOG_CRIT, "out of memory"); + pthread_setspecific (sdat_key, sdat); + } + return sdat; +} + +static void nomemory (void); + static void -terror_stderr (char const *fmt, ...) +log_stderr (int prio, char const *fmt, ...) { va_list ap; int m; - static char *fmtbuf = NULL; - static size_t fmtsize = 0; int ec = errno; char const *es = NULL; size_t len; + struct session_data *sd = priv_get_session_data (); - for (m = 0; fmt[m += strcspn (fmt + m, "%")]; ) - { - m++; - if (fmt[m] == 'm') - break; - } - - len = strlen (fmt) + 1; - if (fmt[m]) - { - es = strerror (ec); - len += strlen (es) - 2; - } - if (len > fmtsize) + if (prio > log_level) + return; + + if (!sd->nomem) { - fmtsize = len; - fmtbuf = realloc (fmtbuf, fmtsize); - if (!fmtbuf) + for (m = 0; fmt[m += strcspn (fmt + m, "%")]; ) { - perror ("realloc"); - exit (EX_FAILURE); + m++; + if (fmt[m] == 'm') + break; + } + + len = strlen (fmt) + 1; + if (fmt[m]) + { + es = strerror (ec); + len += strlen (es) - 2; } - } - if (es) - { - memcpy (fmtbuf, fmt, m - 1); - memcpy (fmtbuf + m - 1, es, strlen (es) + 1); - strcat (fmtbuf, fmt + m + 1); - } - else - strcpy (fmtbuf, fmt); + if (es) + { + if (len > sd->fmtsize) + { + sd->fmtsize = len; + sd->fmtbuf = realloc (sd->fmtbuf, sd->fmtsize); + if (!sd->fmtbuf) + nomemory (); + } + + memcpy (sd->fmtbuf, fmt, m - 1); + memcpy (sd->fmtbuf + m - 1, es, strlen (es) + 1); + strcat (sd->fmtbuf, fmt + m + 1); + fmt = sd->fmtbuf; + } + } + va_start (ap, fmt); fprintf (stderr, "%s: ", progname); - vfprintf (stderr, fmtbuf, ap); + if (sd->sid[0]) + fprintf (stderr, "%s: ", sd->sid); + vfprintf (stderr, fmt, ap); fputc ('\n', stderr); va_end (ap); } static void -terror_syslog (char const *fmt, ...) +log_syslog (int prio, char const *fmt, ...) { va_list ap; + struct session_data *sd = priv_get_session_data (); + + if (prio > log_level) + return; + + if (!sd->nomem && sd->sid[0]) + { + size_t len = strlen (sd->sid) + 2 + strlen (fmt) + 1; + if (len > sd->fmtsize) + { + sd->fmtsize = len; + sd->fmtbuf = realloc (sd->fmtbuf, sd->fmtsize); + if (!sd->fmtbuf) + nomemory (); + } + snprintf (sd->fmtbuf, sd->fmtsize, "%s: %s", sd->sid, fmt); + fmt = sd->fmtbuf; + } + va_start (ap, fmt); - vsyslog (LOG_ERR, fmt, ap); + vsyslog (prio, fmt, ap); va_end (ap); } -static void (*terror) (char const *fmt, ...) = terror_stderr; - +static void (*logger) (int, char const *fmt, ...) = log_stderr; + static void nomemory (void) { - terror ("out of memory"); + struct session_data *sd = priv_get_session_data (); + sd->nomem = 1; + logger (LOG_CRIT, "out of memory"); exit (EX_FAILURE); } @@ -682,7 +746,7 @@ tls_init (void) GNUTLS_X509_FMT_PEM); if (rc < 0) { - terror ("%s: %s", tls_cafile, gnutls_strerror (rc)); + logger (LOG_ERR, "%s: %s", tls_cafile, gnutls_strerror (rc)); return -1; } } @@ -692,7 +756,8 @@ tls_init (void) GNUTLS_X509_FMT_PEM); if (rc < 0) { - terror ("error reading certificate files: %s", gnutls_strerror (rc)); + logger (LOG_ERR, "error reading certificate files: %s", + gnutls_strerror (rc)); return -1; } @@ -761,7 +826,8 @@ iotls_create (int in, int out) } #else static inline int set_tls_opt (int c) { - terror ("option -%c not supported: program compiled without support for TLS", + logger (LOG_ERR, + "option -%c not supported: program compiled without support for TLS", c); return 1; } @@ -854,11 +920,21 @@ enum smtp_state #define MAX_RCPT 32 +static char *state_str[] = { + [STATE_ERR] = "error", + [STATE_INIT] = "init", + [STATE_EHLO] = "ehlo", + [STATE_MAIL] = "mail", + [STATE_RCPT] = "rcpt", + [STATE_DATA] = "data", + [STATE_QUIT] = "quit" +}; + struct smtp { enum smtp_state state; struct iobase *iob; - unsigned sid; + char sid[SID_BUF_LEN]; char buf[IOBUFSIZE]; char *arg; int capa_mask; @@ -866,7 +942,7 @@ struct smtp char *sender; char *rcpt[MAX_RCPT]; int nrcpt; - int tempfd; + int delivered; }; enum @@ -884,8 +960,6 @@ static char const *capa_str[] = { }; #define CAPA_MASK(n) (1<<(n)) - - struct smtp * smtp_create (int ifd, int ofd) @@ -902,11 +976,7 @@ smtp_create (int ifd, int ofd) smtp->helo = NULL; smtp->sender = NULL; smtp->nrcpt = 0; - - pthread_mutex_lock (&msgid_mutex); - smtp->sid = msgid++; - pthread_mutex_unlock (&msgid_mutex); - + generate_sid (smtp->sid); return smtp; } @@ -937,10 +1007,11 @@ smtp_io_send (struct smtp *smtp, int code, char *fmt, ...) smtp_timer_enqueue (pthread_self (), SMTP_OUT); if (iobase_writeln (smtp->iob, buf, n) < 0) { - terror ("iobase_writeln: %s", iobase_strerror (smtp->iob)); + logger (LOG_ERR, "iobase_writeln: %s", iobase_strerror (smtp->iob)); pthread_exit (NULL); } smtp_timer_dequeue (pthread_self ()); + logger (LOG_DEBUG, "S: %.*s", n-2, buf); } static void @@ -958,10 +1029,11 @@ smtp_io_mlsend (struct smtp *smtp, int code, char const **av) smtp_timer_enqueue (pthread_self (), SMTP_OUT); if (iobase_writeln (smtp->iob, buf, n) < 0) { - terror ("iobase_writeln: %s", iobase_strerror (smtp->iob)); + logger (LOG_ERR, "iobase_writeln: %s", iobase_strerror (smtp->iob)); pthread_exit (NULL); } smtp_timer_dequeue (pthread_self ()); + logger (LOG_DEBUG, "S: %.*s", n-2, buf); } } @@ -996,7 +1068,6 @@ void smtp_end (struct smtp *smtp) { smtp_io_send (smtp, 221, "Bye"); - smtp_reset (smtp, STATE_INIT); } void @@ -1237,7 +1308,7 @@ mailbox_append (FILE *tf) fd = open (mailbox_name, O_CREAT|O_WRONLY|O_APPEND, 0600); if (fd == -1) { - terror ("can't open %s: %s", mailbox_name, strerror (errno)); + logger (LOG_ERR, "can't open %s: %s", mailbox_name, strerror (errno)); return -1; } lk.l_type = F_WRLCK; @@ -1246,7 +1317,7 @@ mailbox_append (FILE *tf) lk.l_len = 0; if (fcntl (fd, F_SETLKW, &lk)) /* FIXME: ttl */ { - terror ("can't lock %s: %s", mailbox_name, strerror (errno)); + logger (LOG_ERR, "can't lock %s: %s", mailbox_name, strerror (errno)); close (fd); return -1; } @@ -1256,7 +1327,7 @@ mailbox_append (FILE *tf) fp = fdopen (fd, "a"); if (!fp) { - terror ("fdopen: %s", strerror (errno)); + logger (LOG_ERR, "fdopen: %s", strerror (errno)); close (fd); return -1; } @@ -1276,7 +1347,7 @@ mailbox_append (FILE *tf) lk.l_start = 0; lk.l_len = 0; if (fcntl (fd, F_SETLK, &lk)) - terror ("can't unlock %s: %m", mailbox_name); + logger (LOG_ERR, "can't unlock %s: %m", mailbox_name); fclose (fp); return res; @@ -1302,7 +1373,7 @@ smtp_data (struct smtp *smtp) fd = mkstemp (template); if (fd == -1) { - terror ("can't create temporary: %m"); + logger (LOG_ERR, "can't create temporary: %m"); smtp_io_send (smtp, 451, "Local filesystem error"); return -1; } @@ -1310,7 +1381,7 @@ smtp_data (struct smtp *smtp) fp = fdopen (fd, "w+"); if (!fp) { - terror ("fdopen: %m"); + logger (LOG_ERR, "fdopen: %m"); smtp_io_send (smtp, 451, "Local filesystem error"); close (fd); return -1; @@ -1335,9 +1406,10 @@ smtp_data (struct smtp *smtp) { smtp->state = STATE_QUIT; if (smtp->iob->iob_eof) - terror ("unexpected end of file"); + logger (LOG_ERR, "unexpected end of file"); else - terror ("read error: %s", strerror (smtp->iob->iob_errno)); + logger (LOG_ERR, "read error: %s", + strerror (smtp->iob->iob_errno)); res = 1; break; } @@ -1353,7 +1425,7 @@ smtp_data (struct smtp *smtp) } else { - terror ("line too long"); + logger (LOG_ERR, "line too long"); break; } @@ -1388,10 +1460,18 @@ smtp_data (struct smtp *smtp) pthread_cleanup_pop (1); + if (smtp->nrcpt > 1) + logger (LOG_INFO, "%s => %s (%d recipients) delivered", + smtp->sender, smtp->rcpt[0], smtp->nrcpt); + else + logger (LOG_INFO, "%s => %s delivered", + smtp->sender, smtp->rcpt[0]); + if (res) smtp_io_send (smtp, 451, "Local filesystem error"); else - smtp_io_send (smtp, 250, "%x Message accepted for delivery", smtp->sid); + smtp_io_send (smtp, 250, "%s Message accepted for delivery", smtp->sid); + smtp->delivered++; return res; } @@ -1453,6 +1533,7 @@ do_smtp (struct smtp *smtp) { struct smtp_transition *trans; + logger (LOG_DEBUG, "session started"); smtp_io_send (smtp, 220, "Ready"); while (smtp->state != STATE_QUIT) { @@ -1463,6 +1544,7 @@ do_smtp (struct smtp *smtp) if (n <= 0) break; smtp->buf[--n] = 0; + logger (LOG_DEBUG, "C: %s", smtp->buf); i = strcspn (smtp->buf, " \t"); if (smtp->buf[i]) { @@ -1497,6 +1579,9 @@ do_smtp (struct smtp *smtp) smtp->state = new_state; } + if (!smtp->delivered) + logger (LOG_NOTICE, "session ended without delivery"); + logger (LOG_DEBUG, "session finished"); smtp_end (smtp); } @@ -1611,14 +1696,17 @@ thr_watcher (void *ptr) default: /* Should not happen */ - terror ("unexpected error from pthread_cond_timedwait: %m"); + logger (LOG_ERR, "unexpected error from pthread_cond_timedwait: %m"); exit (EX_FAILURE); } - /* Thread I/O timed out. Terminate the thread. */ - pthread_cancel (timer->tid); - smtp_timer_unlink (timer); - free (timer); + if (timer == smtp_timer_head) + { + /* Thread I/O timed out. Terminate the thread. */ + pthread_cancel (timer->tid); + smtp_timer_unlink (timer); + free (timer); + } } pthread_mutex_unlock (&smtp_timer_mutex); return NULL; @@ -1634,7 +1722,7 @@ mta_open (int port) fd = socket (PF_INET, SOCK_STREAM, 0); if (fd < 0) { - terror ("socket: %m"); + logger (LOG_ERR, "socket: %m"); exit (EX_FAILURE); } @@ -1648,7 +1736,7 @@ mta_open (int port) if (bind (fd, (struct sockaddr *) &address, sizeof (address)) < 0) { close (fd); - terror ("bind: %m"); + logger (LOG_ERR, "bind: %m"); exit (EX_FAILURE); } @@ -1661,12 +1749,17 @@ static void smtp_cleanup (void *ptr) { struct smtp *smtp = ptr; + if (smtp->state != STATE_QUIT) + logger (LOG_NOTICE, "session timed out (%s)", state_str[smtp->state]); smtp_free (smtp); } void * thr_smtp (void *ptr) { + struct smtp *smtp = ptr; + struct session_data *sd = priv_get_session_data (); + memcpy (sd->sid, smtp->sid, sizeof (sd->sid)); pthread_cleanup_push (smtp_cleanup, ptr); do_smtp (ptr); pthread_cleanup_pop (1); @@ -1689,6 +1782,8 @@ thr_smtp_stdio (void *ptr) return NULL; } +#define MAX_HOST_NAME 256 + void * thr_mta_listener (void *ptr) { @@ -1708,7 +1803,7 @@ thr_mta_listener (void *ptr) if ((sfd = accept (fd, (struct sockaddr *) &remote_addr, &len)) < 0) { - terror ("accept: %m"); + logger (LOG_ERR, "accept: %m"); exit (EX_FAILURE); } @@ -1731,6 +1826,86 @@ signull(int sig) { } +static void +set_log_level (char const *arg) +{ + static char *logstr[] = { + [LOG_EMERG] = "emerg", + [LOG_ALERT] = "alert", + [LOG_CRIT] = "crit", + [LOG_ERR] = "err", + [LOG_WARNING] = "warning", + [LOG_NOTICE] = "notice", + [LOG_INFO] = "info", + [LOG_DEBUG] = "debug", + NULL + }; + int i; + + for (i = 0; logstr[i]; i++) + if (strcmp (logstr[i], arg) == 0) + { + log_level = i; + return; + } + + logger (LOG_CRIT, "invalid log level: %s", arg); + exit (EX_USAGE); +} + +static char usage_help[] = "Usage: mockmta [OPTIONS] MAILBOX"; +static char prog_descr[] = "Simple MTA for testing purposes"; +static char *opthelp[] = { +#ifdef WITH_TLS + "-a CA name of certificate authority file", + "-c CERT name of the certificate file", +#endif + "-d daemon mode", + "-f remain in foreground (implies -d)", +#ifdef WITH_TLS + "-k KEY name of the certificate key file", +#endif + "-l LEVEL log events at the specified, or more important, loglevels", + "-P FILE write PID to FILE (with -d or -f)", + "-p PORT listen on this port", + "-t SEC set SMTP timeout", + "-v print program version and exit", + "-? print this help summary and exit", + NULL +}; + +static void +usage (FILE *fp) +{ + int i; + + fprintf (fp, "%s\n", usage_help); + fprintf (fp, "%s\n", prog_descr); + fprintf (fp, "\nOPTIONS are:\n\n"); + for (i = 0; opthelp[i]; i++) + fprintf (fp, " %s\n", opthelp[i]); + fputc ('\n', fp); + fprintf (fp, "Report bugs to <%s>\n", PACKAGE_BUGREPORT); + fprintf (fp, "%s home page: <%s>\n", PACKAGE_NAME, PACKAGE_URL); +} + +static int copyright_year = 2021; + +static void +version (void) +{ + printf ("%s (%s) %s\n", progname, PACKAGE_NAME, PACKAGE_VERSION); + printf ("Copyright (C) %d Sergey Poznyakoff\n", copyright_year); + printf ("\ +License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\nThis is free software: you are free to change and redistribute it.\n\ +There is NO WARRANTY, to the extent permitted by law.\n\ +"); +#ifdef WITH_TLS + printf ("\n"); + printf ("Using GnuTLS %s\n", gnutls_check_version (NULL)); +#endif +} + int main (int argc, char **argv) { @@ -1744,7 +1919,7 @@ main (int argc, char **argv) progname = argv[0]; - while ((c = getopt (argc, argv, "a:dc:fk:p:t:")) != EOF) + while ((c = getopt (argc, argv, "a:dc:fk:l:P:p:t:v?")) != EOF) { switch (c) { @@ -1756,6 +1931,14 @@ main (int argc, char **argv) daemon_opt = 1; foreground = 1; break; + + case 'l': + set_log_level (optarg); + break; + + case 'P': + pidfile = optarg; + break; case 'p': port = atoi (optarg); @@ -1765,14 +1948,26 @@ main (int argc, char **argv) smtp_timeout = atoi (optarg); if (smtp_timeout <= 0) { - terror ("invalid timeout value"); + logger (LOG_ERR, "invalid timeout value"); exit (EX_USAGE); } break; + + case 'v': + version (); + exit (EX_OK); default: - if (set_tls_opt (c)) - exit (EX_USAGE); + if (optopt == '?') + { + usage (stdout); + exit (EX_OK); + } + else if (set_tls_opt (c)) + { + usage (stderr); + exit (EX_USAGE); + } } } @@ -1781,7 +1976,7 @@ main (int argc, char **argv) if (argc != 1) { - terror ("bad number of arguments"); + usage (stderr); exit (EX_USAGE); } @@ -1809,8 +2004,6 @@ main (int argc, char **argv) sigaddset (&sigs, SIGCHLD); pthread_sigmask (SIG_BLOCK, &sigs, NULL); - pthread_create (&tid, NULL, thr_watcher, NULL); - if (daemon_opt) { fd = mta_open (port); @@ -1820,7 +2013,7 @@ main (int argc, char **argv) switch (fork ()) { case -1: - terror ("daemon: %m"); + logger (LOG_ERR, "daemon: %m"); exit (EX_FAILURE); case 0: @@ -1832,7 +2025,7 @@ main (int argc, char **argv) if (setsid () == -1) { - terror ("setsid: %m"); + logger (LOG_ERR, "setsid: %m"); exit (EX_FAILURE); } @@ -1847,13 +2040,31 @@ main (int argc, char **argv) /* Set up logging */ openlog (progname, LOG_PID, LOG_MAIL); - terror = terror_syslog; + logger = log_syslog; + + if (pidfile) + { + FILE *fp = fopen (pidfile, "w"); + if (fp) + { + fprintf (fp, "%lu\n", (unsigned long) getpid()); + fclose (fp); + } + else + { + logger (LOG_ERR, "can't open pidfile %s for writing: %m", + pidfile); + pidfile = NULL; + } + } } + pthread_create (&tid, NULL, thr_watcher, NULL); pthread_create (&tid, NULL, thr_mta_listener, &fd); } else { + pthread_create (&tid, NULL, thr_watcher, NULL); pthread_create (&tid, NULL, thr_smtp_stdio, smtp_create (0, 1)); pthread_detach (tid); } @@ -1867,6 +2078,9 @@ main (int argc, char **argv) /* Wait for signal to arrive */ sigwait (&sigs, &i); - + + if (pidfile) + unlink (pidfile); + exit (EX_OK); } |