Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* awkwrapper: minimal accept-and-fork loop for smtpd.awk when it's not
- * run directly through systemd (with StandardInput=socket & Accept=true) or
- * inetd, but using socket activation
- */
- // only really needed for strdupa()
- #define _GNU_SOURCE
- #include <string.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/uio.h>
- #include <unistd.h>
- #include <fcntl.h>
- #define LISTEN_FD 3
- static const char SCRIPT_NAME[] = "/usr/local/bin/smtpd.awk";
- static int punt(const char *) __attribute__ ((noreturn));
- static int punt(const char *msg) {
- struct iovec vec[] = {
- // surely writev doesn't write to the segment
- { (char *) msg, strlen(msg) },
- { "\n", 1 }
- };
- writev(2, vec, 2);
- exit(1);
- }
- static void setup_socket_activation() {
- char buf[20];
- char *expected;
- pid_t how_long_is_this = getpid();
- if (!getenv("LISTEN_FDS")) punt("No socket activation");
- if ((expected = getenv("LISTEN_PID")) != NULL) {
- buf[19] = 0;
- int i;
- for (i = 18; i >= 0; --i) {
- buf[i] = '0' + how_long_is_this % 10;
- how_long_is_this /= 10;
- if (!how_long_is_this) break;
- }
- if (strcmp(expected, &buf[i]) != 0) punt("Wrong process");
- } else {
- punt("No socket activation");
- }
- unsetenv("LISTEN_FDS");
- unsetenv("LISTEN_FDNAMES");
- unsetenv("LISTEN_PID");
- unsetenv("LISTEN_PIDFDID");
- }
- static int fork_connection(int fd) {
- switch (fork()) {
- case -1:
- return -1;
- case 0:
- if ((dup2(fd, 0) == -1) || (dup2(fd, 1) == -1)) punt("child: dup2 failed");
- close(fd);
- char *argv[] = { strdupa(SCRIPT_NAME), (char *) NULL };
- execv(SCRIPT_NAME, argv);
- punt("child: execv failed");
- default:
- close(fd);
- return 0;
- }
- }
- int main() {
- struct sigaction ignore_child = { .sa_handler = SIG_IGN, .sa_flags = SA_NOCLDSTOP };
- setup_socket_activation();
- if (sigaction(SIGCHLD, &ignore_child, NULL) == -1) punt("sigaction failed");
- if (fcntl(LISTEN_FD, F_SETFD, FD_CLOEXEC) == -1) punt("close-on-exec failed, probably not a socket");
- while (1) {
- int fd = accept(LISTEN_FD, NULL, NULL);
- if (fd == -1) {
- if (errno != EINTR) punt("accept failed");
- else continue;
- }
- if (fork_connection(fd) == -1) {
- punt("fork failed, better exit before something terrible happens");
- }
- }
- // just in case we somehow break out of the loop
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment