I ran into a problem with my systemd units for MIMEDefang. There is a race condition between mimedefang-multiplexor creating the socket and mimedefang trying to access it. If the multiplexor doesn't create the socket in time, mimedefang fails on startup.
This is happening because Type=simple services are assumed to be running immediately. This is documented in systemd.service(5), which says, "In this mode, if the process offers functionality to other processes on the system, its communication channels should be installed before the daemon is started up (e.g. sockets set up by systemd, via socket activation), as systemd will immediately proceed starting follow-up units." I have attached updated versions to correct this. These change to Type=forking and drop the -D flag. With the change to Type=forking, I have also brought back pid files. Since systemd requires the pid file path to be hardcoded (as the argument to PIDFile), I put it in /run rather than the $SPOOLDIR (which the administrator can change). It can't be directly in /run, as the daemon writes the pidfile after dropping privileges, so we have to create a /run/mimedefang subdirectory owned by $MX_USER. This requires some indirection, as $MX_USER can also be customized by the administrator. I only create this directory for mimedefang-multiplexor.service (and not mimedefang.service), as mimedefang.service is already ordered after mimedefang-multiplexor.service. Long term, the ideal answer is to use systemd's socket activation. This would allow the services to startup in parallel. Another alternative would be to use Type=notify. Either requires changes to the mimedefang C code. -- Richard
[Unit] Description=MIMEDefang E-mail Filter Documentation=man:mimedefang(8) Before=multi-user.target Before=postfix.service Before=sendmail.service After=remote-fs.target After=systemd-journald-dev-log.socket BindsTo=mimedefang-multiplexor.service After=mimedefang-multiplexor.service PropagatesReloadTo=mimedefang-multiplexor.service [Service] Type=forking PIDFile=/run/mimedefang/mimedefang.pid Restart=on-failure TimeoutStopSec=30s # LC_ALL=C may not be necessary for mimedefang, but it is for # mimedefang-multiplexor, so upstream prefers it here also to be consistent. Environment=LC_ALL=C MX_SOCKET=/var/spool/MIMEDefang/mimedefang-multiplexor.sock MX_USER=defang SOCKET=/var/spool/MIMEDefang/mimedefang.sock EnvironmentFile=-/etc/default/mimedefang ExecStartPre=/bin/rm -f $SOCKET ExecStart=/bin/sh -c 'exec /usr/bin/mimedefang \ `[ -n "$LOOPBACK_RESERVED_CONNECTIONS" ] && echo "-R $LOOPBACK_RESERVED_CONNECTIONS"` \ -m $MX_SOCKET \ `[ -n "$SPOOLDIR" ] && echo "-z $SPOOLDIR"` \ `[ -n "$MX_USER" ] && echo "-U $MX_USER"` \ `[ -n "$SYSLOG_FACILITY" ] && echo "-S $SYSLOG_FACILITY"` \ `[ "$MX_RELAY_CHECK" = "yes" ] && echo "-r"` \ `[ "$MX_HELO_CHECK" = "yes" ] && echo "-H"` \ `[ "$MX_SENDER_CHECK" = "yes" ] && echo "-s"` \ `[ "$MX_RECIPIENT_CHECK" = "yes" ] && echo "-t"` \ `[ "$KEEP_FAILED_DIRECTORIES" = "yes" ] && echo "-k"` \ `[ "$MD_EXTRA" != "" ] && echo $MD_EXTRA` \ `[ "$MD_SKIP_BAD_RCPTS" = "yes" ] && echo "-N"` \ "`[ -n "$X_SCANNED_BY" ] && \ ( [ "$X_SCANNED_BY" = "-" ] && \ echo "-X" || echo "-x$X_SCANNED_BY" )`" \ `[ "$MD_ALLOW_GROUP_ACCESS" = "yes" ] && echo "-G"` \ `[ "$ALLOW_NEW_CONNECTIONS_TO_QUEUE" = "yes" ] && echo "-q"` \ -p $SOCKET -P /run/mimedefang/mimedefang.pid' ExecStopPost=/bin/rm -f $SOCKET # Make this service eligible for a reload, so we can propagate it to # mimedefang-multiplexor.service. ExecReload=/bin/true [Install] WantedBy=multi-user.target
[Unit] Description=MIMEDefang E-mail Filter (Multiplexor) Documentation=man:mimedefang-multiplexor(8) After=remote-fs.target After=systemd-journald-dev-log.socket PartOf=mimedefang.service [Service] Type=forking PIDFile=/run/mimedefang/mimedefang-multiplexor.pid Restart=on-failure TimeoutStopSec=30s KillMode=mixed # Locale should be set to "C" for generating valid date headers Environment=LC_ALL=C MX_BUSY=600 MX_LOG=yes MX_MAXIMUM=10 MX_MINIMUM=2 MX_SOCKET=/var/spool/MIMEDefang/mimedefang-multiplexor.sock MX_USER=defang EnvironmentFile=-/etc/default/mimedefang # This can be removed with MIMEDefang 2.82: SuccessExitStatus=1 ExecStartPre=/bin/rm -f $MX_SOCKET ExecStartPre=/bin/sh -c '/usr/bin/install -d \ `[ -n "$MX_USER" ] && echo "-o $MX_USER"` \ /run/mimedefang' ExecStart=/bin/sh -c 'HOME=${SPOOLDIR:=/var/spool/MIMEDefang} \ exec /usr/bin/mimedefang-multiplexor \ `[ "$MX_EMBED_PERL" = "yes" ] && echo "-E"` \ `[ -n "$SPOOLDIR" ] && echo "-z $SPOOLDIR"` \ `[ -n "$FILTER" ] && echo "-f $FILTER"` \ `[ -n "$SYSLOG_FACILITY" ] && echo "-S $SYSLOG_FACILITY"` \ `[ -n "$SUBFILTER" ] && echo "-F $SUBFILTER"` \ `[ -n "$MX_MINIMUM" ] && echo "-m $MX_MINIMUM"` \ `[ -n "$MX_MAXIMUM" ] && echo "-x $MX_MAXIMUM"` \ `[ -n "$MX_MAP_SOCKET" ] && echo "-N $MX_MAP_SOCKET"` \ `[ -n "$MX_LOG_SLAVE_STATUS_INTERVAL" ] && echo "-L $MX_LOG_SLAVE_STATUS_INTERVAL"` \ `[ -n "$MX_USER" ] && echo "-U $MX_USER"` \ `[ -n "$MX_IDLE" ] && echo "-i $MX_IDLE"` \ `[ -n "$MX_BUSY" ] && echo "-b $MX_BUSY"` \ `[ -n "$MX_REQUESTS" ] && echo "-r $MX_REQUESTS"` \ `[ -n "$MX_SLAVE_DELAY" ] && echo "-w $MX_SLAVE_DELAY"` \ `[ -n "$MX_MIN_SLAVE_DELAY" ] && echo "-W $MX_MIN_SLAVE_DELAY"` \ `[ -n "$MX_MAX_RSS" ] && echo "-R $MX_MAX_RSS"` \ `[ -n "$MX_MAX_AS" ] && echo "-M $MX_MAX_AS"` \ `[ "$MX_LOG" = "yes" ] && echo "-l"` \ `[ "$MX_STATS" = "yes" ] && echo "-t /var/log/mimedefang/stats"` \ `[ "$MX_STATS" = "yes" -a "$MX_FLUSH_STATS" = "yes" ] && echo "-u"` \ `[ "$MX_STATS_SYSLOG" = "yes" ] && echo "-T"` \ `[ "$MD_ALLOW_GROUP_ACCESS" = "yes" ] && echo "-G"` \ `[ "$MX_STATUS_UPDATES" = "yes" ] && echo "-Z"` \ `[ -n "$MX_QUEUE_SIZE" ] && echo "-q $MX_QUEUE_SIZE"` \ `[ -n "$MX_QUEUE_TIMEOUT" ] && echo "-Q $MX_QUEUE_TIMEOUT"` \ `[ -n "$MX_NOTIFIER" ] && echo "-O $MX_NOTIFIER"` \ `[ -n "$MX_RECIPOK_PERDOMAIN_LIMIT" ] && echo "-y $MX_RECIPOK_PERDOMAIN_LIMIT"` \ -s $MX_SOCKET -p /run/mimedefang/mimedefang-multiplexor.pid' ExecStopPost=/bin/rm -f $MX_SOCKET ExecReload=/bin/kill -INT $MAINPID