Download | Plain Text | Line Numbers


#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
 
// gcc -std=c99
 
static char *sendmail = "/var/qmail/bin/sendmail";
 
int fd_copy(int to, int from)
{
  if (to == from)
    return 0;
  if (fcntl(from, F_GETFL, 0) == -1)
    return -1;
  close(to);
  if (fcntl(from, F_DUPFD, to) == -1)
    return -1;
  return 0;
}
 
void sig_catch(int sig, void (*f)())
{
#ifdef HASSIGACTION
  struct sigaction sa;
  sa.sa_handler = f;
  sa.sa_flags = 0;
  sigemptyset(&sa.sa_mask);
  sigaction(sig, &sa, (struct sigaction *)0);
#else
  signal(sig, f);
#endif
}
 
int wait_pid(int *wstat, int pid)
{
  int r;
  do
    r = waitpid(pid, wstat, 0);
  while (r == -1 && errno == EINTR);
  return r;
}
 
int main(int argc, char *argv[])
{
  for(int i = 0; i < argc; i++)
  {
    if (!strcmp(argv[i], "<>"))
      argv[i][0] = '\0';
  }
  argv[0] = sendmail;
 
  int pi[2], pid;
  if (pipe(pi) == -1)
  {
    fprintf(stderr, "sendmail: unable to open pipe\n");
    exit(100);
  }
 
  switch(pid = fork())
  {
    case -1:
      fprintf(stderr, "sendmail: unable to fork\n");
      exit(100);
    case 0:
      close(pi[1]);
      if (fd_copy(0, pi[0]) == -1)
      {
        fprintf(stderr, "sendmail: unable to copy pipe to stdin\n");
        exit(100);
      }
      sig_catch(SIGPIPE, SIG_DFL);
      execv(argv[0], argv);
      fprintf(stderr, "sendmail: unable to run sendmail\n");
      exit(111);
  }
  close(pi[0]);
 
  char *r, buf[255];
  while(r = fgets(buf, sizeof(buf), stdin))
  {
    if (ferror(stdin))
    {
      fprintf(stderr, "sendmail: error while readin stdin: %s\n",
          strerror(fileno(stdin)));
      exit(111);
    }
 
    int len = strlen(buf);
    if (len >= 2 && buf[len - 2] == '\r' && buf[len - 1] == '\n')
    {
      buf[len - 2] = buf[len - 1];
      buf[len - 1] = '\0';
      len--;
    }
    write(pi[1], buf, len);
    if (feof(stdin))
      break;
  }
  close(pi[1]);
 
  int wstat;
  if (wait_pid(&wstat, pid) == -1)
    exit(111);
  exit(wstat >> 8);
}