]> granicus.if.org Git - neomutt/commitdiff
patch.mutt-0.95.1i.ld.signals.1: A major redesign of how child
authorThomas Roessler <roessler@does-not-exist.org>
Wed, 10 Feb 1999 21:19:34 +0000 (21:19 +0000)
committerThomas Roessler <roessler@does-not-exist.org>
Wed, 10 Feb 1999 21:19:34 +0000 (21:19 +0000)
processes are invoked.  From Liviu.

12 files changed:
TODO
attach.c
commands.c
compose.c
curs_lib.c
globals.h
mutt.h
protos.h
send.c
sendlib.c
signal.c
system.c

diff --git a/TODO b/TODO
index 3f93e3a4bb4974d702ce886943b191ddf893571f..72f428fcfc8ca146b4476d3b01fbaad76331b912 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,5 +1,9 @@
 Problems are listed in approximate order of priority.
 
+- Fix postponing: Headers should be RFC2047 en- and de-coded.
+- character set support: We should have a global cache of
+  character to file name mappings.
+
 - Help formatting could be revamped a bit.
 
 - re-add support for .mh_sequences files
index da283f2402422c3d35dc8dd40288fb73b57a1194..41311b8ea83920ba93faf9a5f3767d12a6d10cec 100644 (file)
--- a/attach.c
+++ b/attach.c
@@ -124,9 +124,13 @@ int mutt_compose_attachment (BODY *a)
       }
       else
       {
+       int r;
+
        endwin ();
-       mutt_system (command);
-       if (entry->composetypecommand)
+       if ((r = mutt_system (command)) == -1)
+         mutt_error (_("Error running \"%s\"!"), command);
+       
+       if (r != -1 && entry->composetypecommand)
        {
          BODY *b;
          FILE *fp, *tfp;
@@ -248,7 +252,8 @@ int mutt_edit_attachment (BODY *a)
       else
       {
        endwin ();
-       mutt_system (command);
+       if (mutt_system (command) == -1)
+         mutt_error (_("Error running \"%s\"!"), command);
       }
     }
   }
index 64dd3f43e39eb953fe976f9f9783dc4bb6422567..9929fee3bb8b350bd50bf0fd04e339473515b97b 100644 (file)
@@ -147,13 +147,17 @@ int mutt_display_message (HEADER *cur)
   }
   else
   {
+    int r;
+
     endwin ();
     snprintf (buf, sizeof (buf), "%s %s", NONULL(Pager), tempfile);
-    mutt_system (buf);
+    if ((r = mutt_system (buf)) == -1)
+      mutt_error (_("Error running \"%s\"!"), buf);
     unlink (tempfile);
     keypad (stdscr, TRUE);
-    mutt_set_flag (Context, cur, M_READ, 1);
-    if (option (OPTPROMPTAFTER))
+    if (r != -1)
+      mutt_set_flag (Context, cur, M_READ, 1);
+    if (r != -1 && option (OPTPROMPTAFTER))
     {
       mutt_ungetch (mutt_any_key_to_continue _("Command: "), 0);
       rc = km_dokey (MENU_PAGER);
index ccf2849a9c533934ad57f43342a5532048b03b20..7d6b045fae2bad1c6aa1c9764cf9e921b5e10bc9 100644 (file)
--- a/compose.c
+++ b/compose.c
@@ -1166,8 +1166,10 @@ int mutt_compose_menu (HEADER *msg,   /* structure for new message */
       case OP_COMPOSE_ISPELL:
        endwin ();
        snprintf (buf, sizeof (buf), "%s -x %s", NONULL(Ispell), msg->content->filename);
-       mutt_system (buf);
-        mutt_update_encoding(msg->content);
+       if (mutt_system (buf) == -1)
+         mutt_error (_("Error running \"%s\"!"), buf);
+       else
+         mutt_update_encoding (msg->content);
        break;
 
       case OP_COMPOSE_WRITE_MESSAGE:
index 0d47e4c8ddaa0b0bf8ebd3ffa62aed5e31844a49..a35d4a559ba389e477310c2253d73ef5c480850e 100644 (file)
@@ -124,7 +124,8 @@ void mutt_edit_file (const char *editor, const char *data)
   
   endwin ();
   mutt_expand_file_fmt (cmd, sizeof (cmd), editor, data);
-  mutt_system (cmd);
+  if (mutt_system (cmd) == -1)
+    mutt_error (_("Error running \"%s\"!"), cmd);
   keypad (stdscr, TRUE);
   clearok (stdscr, TRUE);
 }
@@ -317,9 +318,14 @@ int mutt_do_pager (const char *banner,
     
     endwin ();
     mutt_expand_file_fmt (cmd, sizeof(cmd), Pager, tempfile);
-    mutt_system (cmd);
+    if (mutt_system (cmd) == -1)
+    {
+      mutt_error (_("Error running \"%s\"!"), cmd);
+      rc = -1;
+    }
+    else
+      rc = 0;
     mutt_unlink (tempfile);
-    rc = 0;
   }
 
   return rc;
index 6ccbb354ad3ac7dd562a9700b0f578c4d19af59f..836768dbacdbc67b202f98440073da997e8747f9 100644 (file)
--- a/globals.h
+++ b/globals.h
@@ -118,7 +118,8 @@ WHERE short Timeout;
 WHERE short WriteInc;
 
 /* vector to store received signals */
-WHERE short Signals INITVAL (0);
+/* hopefully it's an integer type... */
+WHERE volatile sig_atomic_t Signals INITVAL (0);
 
 WHERE int CurrentMenu;
 
diff --git a/mutt.h b/mutt.h
index 44c61e51f05186784b1876d4d87c85b41853b11e..190375b50941a11e71d8055046f2087821289ee5 100644 (file)
--- a/mutt.h
+++ b/mutt.h
@@ -27,6 +27,7 @@
 #include <time.h>
 #include <limits.h>
 #include <stdarg.h>
+#include <signal.h>
 
 #ifndef _POSIX_PATH_MAX
 #include <posix1_lim.h>
@@ -371,6 +372,7 @@ enum
   OPTMSGERR,           /* (pseudo) used by mutt_error/mutt_message */
   OPTSEARCHINVALID,    /* (pseudo) used to invalidate the search pat */
   OPTSIGNALSBLOCKED,   /* (pseudo) using by mutt_block_signals () */
+  OPTSYSSIGNALSBLOCKED,        /* (pseudo) using by mutt_block_signals_system () */
   OPTNEEDRESORT,       /* (pseudo) used to force a re-sort */
   OPTVIEWATTACH,       /* (pseudo) signals that we are viewing attachments */
   OPTFORCEREDRAWINDEX, /* (pseudo) used to force a redraw in the main index */
@@ -403,9 +405,13 @@ enum
 #define option(x) mutt_bit_isset(Options,x)
 
 /* Bit fields for ``Signals'' */
-#define S_INTERRUPT (1<<1)
-#define S_SIGWINCH  (1<<2)
-#define S_ALARM     (1<<3)
+#define S_INTERRUPT (1<<0)
+#define S_SIGWINCH  (1<<1)
+#define S_ALARM     (1<<2)
+
+/* Exit values used in send_msg() */
+#define S_ERR 127
+#define S_BKG 126
 
 typedef struct list_t
 {
index a86fc865acbe40316c83402f4b563ba8a204063e..25672655ef43aac64baae3623dce5a8e33cdb08d 100644 (file)
--- a/protos.h
+++ b/protos.h
@@ -130,7 +130,6 @@ char *mutt_substrdup (const char *, const char *);
 
 const char *mutt_fqdn(short);
 
-void mutt_add_child_pid (pid_t);
 void mutt_alias_menu (char *, size_t, ALIAS *);
 void mutt_block_signals (void);
 void mutt_block_signals_system (void);
diff --git a/send.c b/send.c
index 743ad15f9c983a4f4443459f5e5ef49e8b7939e1..9f0e301d4b1d2f72b48a7711584750610352122d 100644 (file)
--- a/send.c
+++ b/send.c
@@ -832,7 +832,7 @@ static int send_message (HEADER *msg)
 
   i = mutt_invoke_sendmail (msg->env->to, msg->env->cc, msg->env->bcc,
                       tempfile, (msg->content->encoding == ENC8BIT));
-  return (i ? -1 : 0);
+  return (i);
 }
 
 /* rfc2047 encode the content-descriptions */
@@ -1327,7 +1327,7 @@ full_fcc:
   }
 #endif /* _PGPPATH */
 
-  if (send_message (msg) == -1)
+  if ((i = send_message (msg)) == -1)
   {
     if (!(flags & SENDBATCH))
     {
@@ -1340,9 +1340,8 @@ full_fcc:
       goto cleanup;
     }
   }
-
-  if (!option (OPTNOCURSES) && ! (flags & SENDMAILX))
-    mutt_message _("Mail sent.");
+  else if (!option (OPTNOCURSES) && ! (flags & SENDMAILX))
+    mutt_message (i == 0 ? _("Mail sent.") : _("Sending in background."));
 
   if (flags & SENDREPLY)
   {
index 05d1d3b2290e680a07b1436c5bc3459790785dbd..533cf0eb8a11e0b28ba4bb26227218b16c4869da 100644 (file)
--- a/sendlib.c
+++ b/sendlib.c
@@ -23,6 +23,7 @@
 #include "mime.h"
 #include "mailbox.h"
 #include "copy.h"
+#include "pager.h"
 #include "charset.h"
 
 #include <string.h>
@@ -49,47 +50,48 @@ static struct sysexits
 sysexits_h[] = 
 {
 #ifdef EX_USAGE
-  { EX_USAGE, "The command was used incorrectly." },
+  { 0xff & EX_USAGE, "The command was used incorrectly." },
 #endif
 #ifdef EX_DATAERR
-  { EX_DATAERR, "The input data was incorrect." },
+  { 0xff & EX_DATAERR, "The input data was incorrect." },
 #endif
 #ifdef EX_NOINPUT
-  { EX_NOINPUT, "No input." },
+  { 0xff & EX_NOINPUT, "No input." },
 #endif
 #ifdef EX_NOUSER
-  { EX_NOUSER, "No such user." },
+  { 0xff & EX_NOUSER, "No such user." },
 #endif
 #ifdef EX_NOHOST
-  { EX_NOHOST, "Host not found." },
+  { 0xff & EX_NOHOST, "Host not found." },
 #endif
 #ifdef EX_UNAVAILABLE
-  { EX_UNAVAILABLE, "Service unavailable." },
+  { 0xff & EX_UNAVAILABLE, "Service unavailable." },
 #endif
 #ifdef EX_SOFTWARE
-  { EX_SOFTWARE, "Software error." },
+  { 0xff & EX_SOFTWARE, "Software error." },
 #endif
 #ifdef EX_OSERR
-  { EX_OSERR, "Operating system error." },
+  { 0xff & EX_OSERR, "Operating system error." },
 #endif
 #ifdef EX_OSFILE
-  { EX_OSFILE, "System file is missing." },
+  { 0xff & EX_OSFILE, "System file is missing." },
 #endif
 #ifdef EX_CANTCREAT
-  { EX_CANTCREAT, "Can't create output." },
+  { 0xff & EX_CANTCREAT, "Can't create output." },
 #endif
 #ifdef EX_IOERR
-  { EX_IOERR, "I/O error." },
+  { 0xff & EX_IOERR, "I/O error." },
 #endif
 #ifdef EX_TEMPFAIL
-  { EX_TEMPFAIL, "Temporary failure." },
+  { 0xff & EX_TEMPFAIL, "Temporary failure." },
 #endif
 #ifdef EX_PROTOCOL
-  { EX_PROTOCOL, "Protocol error." },
+  { 0xff & EX_PROTOCOL, "Protocol error." },
 #endif
 #ifdef EX_NOPERM
-  { EX_NOPERM, "Permission denied." },
+  { 0xff & EX_NOPERM, "Permission denied." },
 #endif
+  { S_ERR, "Exec error." },
   { -1, NULL}
 };
       
@@ -1429,17 +1431,18 @@ static RETSIGTYPE alarm_handler (int sig)
 static int
 send_msg (const char *path, char **args, const char *msg, char **tempfile)
 {
-  int fd, st, w = 0, err = 0;
+  sigset_t set;
+  int fd, st;
   pid_t pid;
-  struct sigaction act, oldint, oldquit, oldalrm;
 
-  memset (&act, 0, sizeof (struct sigaction));
-  sigemptyset (&(act.sa_mask));
-  act.sa_handler = SIG_IGN;
-  sigaction (SIGINT, &act, &oldint);
-  sigaction (SIGQUIT, &act, &oldquit);
+  mutt_block_signals_system ();
 
-  if (SendmailWait)
+  sigemptyset (&set);
+  /* we also don't want to be stopped right now */
+  sigaddset (&set, SIGTSTP);
+  sigprocmask (SIG_BLOCK, &set, NULL);
+
+  if (SendmailWait >= 0)
   {
     char tmp[_POSIX_PATH_MAX];
 
@@ -1449,135 +1452,119 @@ send_msg (const char *path, char **args, const char *msg, char **tempfile)
 
   if ((pid = fork ()) == 0)
   {
-    /* reset signals for the child */
-    act.sa_handler = SIG_DFL;
-    /* we need SA_RESTART for the open() below */
-#ifdef SA_RESTART
-    act.sa_flags = SA_NOCLDSTOP | SA_RESTART;
+    struct sigaction act, oldalrm;
+
+    /* we want the delivery to continue even after the main process dies,
+     * so we put ourselves into another session right away
+     */
+    setsid ();
+  
+    /* next we close all open files */
+#if defined(OPEN_MAX)
+    for (fd = 0; fd < OPEN_MAX; fd++)
+      close (fd);
+#elif defined(_POSIX_OPEN_MAX)
+    for (fd = 0; fd < _POSIX_OPEN_MAX; fd++)
+      close (fd);
 #else
-    act.sa_flags = SA_NOCLDSTOP;
+    close (0);
+    close (1);
+    close (2);
 #endif
-    sigaction (SIGCHLD, &act, NULL);
-    act.sa_flags = 0;
-    sigaction (SIGINT, &act, NULL);
-    sigaction (SIGQUIT, &act, NULL);
-
-    /* if it is possible that we will deliver in the background, then we have
-       to detach the child from this process group or it will die when the
-       parent process exists, causing the mail to not get delivered.  The
-       problem here is that any error messages will get lost... */
-    if (SendmailWait)
-      setsid ();
+
+    /* now the second fork() */
     if ((pid = fork ()) == 0)
     {
-      fd = open (msg, O_RDONLY, 0);
-      if (fd < 0)
-       _exit (127);
-      dup2 (fd, 0);
-      close (fd);
-      if (SendmailWait)
+      /* "msg" will be opened as stdin */
+      if (open (msg, O_RDONLY, 0) < 0)
       {
-       /* write stdout to a tempfile */
-       w = open (*tempfile, O_WRONLY | O_CREAT | O_EXCL, 0600);
-       if (w < 0)
+       unlink (msg);
+       _exit (S_ERR);
+      }
+      unlink (msg);
+
+      if (SendmailWait >= 0)
+      {
+       /* *tempfile will be opened as stdout */
+       if (open (*tempfile, O_WRONLY | O_APPEND | O_CREAT | O_EXCL, 0600) < 0)
+         _exit (errno);
+       /* redirect stderr to *tempfile too */
+       if (dup (1) < 0)
          _exit (errno);
-       dup2 (w, 1);
-       close (w);
       }
-      sigaction (SIGCHLD, &act, NULL);
+
       execv (path, args);
-      unlink (msg);
-      _exit (127);
+      _exit (S_ERR);
     }
     else if (pid == -1)
     {
       unlink (msg);
-      _exit (errno);
+      safe_free ((void **) tempfile);
+      _exit (S_ERR);
     }
 
+    /* SendmailWait > 0: interrupt waitpid() after SendmailWait seconds
+     * SendmailWait = 0: wait forever
+     * SendmailWait < 0: don't wait
+     */
+    if (SendmailWait > 0)
+    {
+      Signals &= ~S_ALARM;
+      act.sa_handler = alarm_handler;
+#ifdef SA_INTERRUPT
+      /* need to make sure waitpid() is interrupted on SIGALRM */
+      act.sa_flags = SA_INTERRUPT;
+#else
+      act.sa_flags = 0;
+#endif
+      sigemptyset (&act.sa_mask);
+      sigaddset (&act.sa_mask, SIGTSTP);
+      sigaddset (&act.sa_mask, SIGINT);
+#if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
+      sigaddset (&act.sa_mask, SIGWINCH);
+#endif
+      sigaction (SIGALRM, &act, &oldalrm);
+      alarm (SendmailWait);
+    }
+    else if (SendmailWait < 0)
+      _exit (0xff & EX_OK);
+
     if (waitpid (pid, &st, 0) > 0)
     {
-      st = WIFEXITED (st) ? WEXITSTATUS (st) : 127;
-      if (st == (EX_OK & 0xff) && SendmailWait)
+      st = WIFEXITED (st) ? WEXITSTATUS (st) : S_ERR;
+      if (SendmailWait && st == (0xff & EX_OK))
+      {
        unlink (*tempfile); /* no longer needed */
+       safe_free ((void **) tempfile);
+      }
     }
     else
     {
-      st = 127;
-      if (SendmailWait)
+      st = (SendmailWait > 0 && errno == EINTR && (Signals & S_ALARM)) ?
+             S_BKG : S_ERR;
+      if (SendmailWait > 0)
+      {
        unlink (*tempfile);
+       safe_free ((void **) tempfile);
+      }
     }
-    unlink (msg);
-    _exit (st);
-  }
-  /* SendmailWait > 0: SIGALRM will interrupt wait() after alrm seconds
-     SendmailWait = 0: wait forever
-     SendmailWait < 0: don't wait */
-  if (SendmailWait > 0)
-  {
-    Signals &= ~S_ALARM;
-    act.sa_handler = alarm_handler;
-#ifdef SA_INTERRUPT
-    /* need to make sure the waitpid() is interrupted on SIGALRM */
-    act.sa_flags = SA_INTERRUPT;
-#else
-    act.sa_flags = 0;
-#endif
-    sigaction (SIGALRM, &act, &oldalrm);
-    alarm (SendmailWait);
-  }
-  if (SendmailWait >= 0)
-  {
-    w = waitpid (pid, &st, 0);
-    err = errno; /* save error since it might be clobbered by another
-                   system call before we check the value */
-    dprint (1, (debugfile, "send_msg(): waitpid returned %d (%s)\n", w,
-           (w < 0 ? strerror (errno) : "OK")));
-  }
-  if (SendmailWait > 0)
-  {
+
+    /* reset alarm; not really needed, but... */
     alarm (0);
     sigaction (SIGALRM, &oldalrm, NULL);
+    
+    _exit (st);
   }
-  if (SendmailWait < 0 || ((Signals & S_ALARM) && w < 0 && err == EINTR))
-  {
-    /* add to list of children pids to reap */
-    mutt_add_child_pid (pid);
-    /* since there is no way for the user to be notified of error in this case,
-       remove the temp file now */
-    unlink (*tempfile);
-    FREE (tempfile);
-#ifdef DEBUG
-    if (Signals & S_ALARM)
-      dprint (1, (debugfile, "send_msg(): received SIGALRM\n"));
-    dprint (1, (debugfile, "send_msg(): putting sendmail in the background\n"));
-#endif
-    st = EX_OK & 0xff;
-  }
-  else if (w < 0)
-  {
-    /* if err==EINTR, alarm interrupt, child status unknown,
-       otherwise, there was an error invoking the child */
-    st = (err == EINTR) ? (EX_OK & 0xff) : 127;
-  }
+
+  sigprocmask (SIG_UNBLOCK, &set, NULL);
+
+  if (pid != -1 && waitpid (pid, &st, 0) > 0)
+    st = WIFEXITED (st) ? WEXITSTATUS (st) : S_ERR; /* return child status */
   else
-  {
-#ifdef DEBUG
-    if (WIFEXITED (st))
-    {
-      dprint (1, (debugfile, "send_msg(): child exited %d\n", WEXITSTATUS (st)));
-    }
-    else
-    {
-      dprint (1, (debugfile, "send_msg(): child did not exit\n"));
-    }
-#endif /* DEBUG */
-    st = WIFEXITED (st) ? WEXITSTATUS (st) : -1; /* return child status */
-  }
-  sigaction (SIGINT, &oldint, NULL);
-  sigaction (SIGQUIT, &oldquit, NULL);
-  /* restore errno so that the caller can build an error message */
-  errno = err;
+    st = S_ERR;        /* error */
+
+  mutt_unblock_signals_system (1);
+
   return (st);
 }
 
@@ -1675,26 +1662,39 @@ mutt_invoke_sendmail (ADDRESS *to, ADDRESS *cc, ADDRESS *bcc, /* recips */
   
   args[argslen++] = NULL;
 
-  if (!option (OPTNOCURSES))
-    endwin ();
   if ((i = send_msg (path, args, msg, &childout)) != (EX_OK & 0xff))
   {
-    const char *e = strsysexit(i);
-
-    fprintf (stderr, _("Error sending message, child exited %d (%s).\n"), i, NONULL (e));
-    if (childout)
-      fprintf (stderr, _("Saved output of child process to %s.\n"), childout);
-    if (!option (OPTNOCURSES))
+    if (i == S_BKG)
+      mutt_message (_("Delivery continued in background."));
+    else
     {
-      mutt_any_key_to_continue (NULL);
-      mutt_error _("Error sending message.");
+      const char *e = strsysexit (i);
+
+      e = strsysexit (i);
+      mutt_error (_("Error sending message, child exited %d (%s)."), i, NONULL (e));
+      if (childout)
+      {
+       struct stat st;
+       
+       if (stat (childout, &st) == 0 && st.st_size > 0)
+         mutt_do_pager (_("Output of the delivery process"), childout, 0, NULL);
+      }
     }
   }
+  else
+    unlink (childout);
+
   FREE (&childout);
   FREE (&path);
   FREE (&s);
   FREE (&args);
 
+  if (i == (EX_OK & 0xff))
+    i = 0;
+  else if (i == S_BKG)
+    i = 1;
+  else
+    i = -1;
   return (i);
 }
 
index dba16da38a2b1fd0af5c7e8bdff13539a525215a..739963137f6bfdde2546d8bc119d4afb0af0742e 100644 (file)
--- a/signal.c
+++ b/signal.c
 #include <signal.h>
 #include <string.h>
 #include <sys/wait.h>
+#include <errno.h>
 
 static sigset_t Sigset;
+static sigset_t SigsetSys;
 static int IsEndwin = 0;
 
-static pid_t *PidList = NULL;
-static int PidListLen = 0;
-
 /* Attempt to catch "ordinary" signals and shut down gracefully. */
-RETSIGTYPE mutt_exit_handler (int sig)
+RETSIGTYPE exit_handler (int sig)
 {
   curs_set (1);
   endwin (); /* just to be safe */
 #if SYS_SIGLIST_DECLARED
-  printf(_("Caught %s...  Exiting.\n"), sys_siglist[sig]);
+  printf(_("%s...  Exiting.\n"), sys_siglist[sig]);
 #else
 #if (__sun__ && __svr4__)
   printf(_("Caught %s...  Exiting.\n"), _sys_siglist[sig]);
@@ -46,55 +45,19 @@ RETSIGTYPE mutt_exit_handler (int sig)
   exit (0);
 }
 
-static void reap_children (void)
+RETSIGTYPE chld_handler (int sig)
 {
-  int i, flag;
-
-  /* at this point we don't know which child died */
-  for (i = 0; i < PidListLen; i++)
-  {
-    if (PidList[i])
-    {
-      /* try to reap child "i" */
-      flag = 0;
-      while (waitpid (PidList[i], NULL, WNOHANG) > 0)
-        flag = 1;
-      /* remove child from list if reaped */
-      if (flag)
-        PidList[i] = 0;
-      /* don't break here */
-    }
-  }
-}
-
-void mutt_add_child_pid (pid_t pid)
-{
-  int i;
-
-  for (i = 0; i < PidListLen; i++)
-  {
-    if (PidList[i] == 0)
-    {
-      PidList[i] = pid;
-      break;
-    }
-  }
-  if (i >= PidListLen)
-  {
-    /* quite a few children around... */
-    safe_realloc ((void **) &PidList, (PidListLen += 2) * sizeof (pid_t));
-    PidList[i++] = pid;
-    for (; i < PidListLen; i++)
-      PidList[i] = 0;
-  }
+  /* empty */
 }
 
 RETSIGTYPE sighandler (int sig)
 {
+  int save_errno = errno;
+
   switch (sig)
   {
     case SIGTSTP: /* user requested a suspend */
-      if(!option(OPTSUSPEND))
+      if (!option (OPTSUSPEND))
         break;
       IsEndwin = isendwin ();
       curs_set (1);
@@ -113,14 +76,13 @@ RETSIGTYPE sighandler (int sig)
       Signals |= S_SIGWINCH;
       break;
 #endif
+
     case SIGINT:
       Signals |= S_INTERRUPT;
       break;
 
-    case SIGCHLD:
-      reap_children ();
-      break;
   }
+  errno = save_errno;
 }
 
 #ifdef USE_SLANG_CURSES
@@ -134,40 +96,42 @@ void mutt_signal_init (void)
 {
   struct sigaction act;
 
-  memset (&act, 0, sizeof (struct sigaction));
-
+  sigemptyset (&act.sa_mask);
+  act.sa_flags = 0;
   act.sa_handler = SIG_IGN;
   sigaction (SIGPIPE, &act, NULL);
 
-  act.sa_handler = mutt_exit_handler;
+  act.sa_handler = exit_handler;
   sigaction (SIGTERM, &act, NULL);
   sigaction (SIGHUP, &act, NULL);
+  sigaction (SIGQUIT, &act, NULL);
 
-  act.sa_handler = sighandler;
-#ifdef SA_INTERRUPT
-  /* POSIX.1 uses SA_RESTART, but SunOS 4.x uses this instead */
-  act.sa_flags = SA_INTERRUPT;
+  /* we want to avoid race conditions */
+  sigaddset (&act.sa_mask, SIGTSTP);
+  sigaddset (&act.sa_mask, SIGINT);
+#if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
+  sigaddset (&act.sa_mask, SIGWINCH);
 #endif
-  sigaction (SIGCONT, &act, NULL);
-  sigaction (SIGINT, &act, NULL);
 
-  /* SIGTSTP is the one signal in which we want to restart a system call if it
-   * was interrupted in progress.  This is especially important if we are in
-   * the middle of a system() call, like if the user is editing a message.
-   * Otherwise, the system() will exit when SIGCONT is received and Mutt will
-   * resume even though the subprocess may not be finished.
-   */
+  /* we also don't want to mess with interrupted system calls */
 #ifdef SA_RESTART
   act.sa_flags = SA_RESTART;
-#else
-  act.sa_flags = 0;
 #endif
-  sigaction (SIGTSTP, &act, NULL);
 
+  act.sa_handler = sighandler;
+  sigaction (SIGCONT, &act, NULL);
+  sigaction (SIGTSTP, &act, NULL);
+  sigaction (SIGINT, &act, NULL);
 #if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
   sigaction (SIGWINCH, &act, NULL);
 #endif
 
+  /* POSIX doesn't allow us to ignore SIGCHLD,
+   * so we just install a dummy handler for it
+   */
+  act.sa_handler = chld_handler;
+  /* don't need to block any other signals here */
+  sigemptyset (&act.sa_mask);
   /* we don't want to mess with stopped children */
   act.sa_flags |= SA_NOCLDSTOP;
   sigaction (SIGCHLD, &act, NULL);
@@ -190,11 +154,13 @@ void mutt_block_signals (void)
   if (!option (OPTSIGNALSBLOCKED))
   {
     sigemptyset (&Sigset);
-    sigaddset (&Sigset, SIGINT);
-    sigaddset (&Sigset, SIGWINCH);
-    sigaddset (&Sigset, SIGHUP);
     sigaddset (&Sigset, SIGTERM);
+    sigaddset (&Sigset, SIGHUP);
     sigaddset (&Sigset, SIGTSTP);
+    sigaddset (&Sigset, SIGINT);
+#if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
+    sigaddset (&Sigset, SIGWINCH);
+#endif
     sigprocmask (SIG_BLOCK, &Sigset, 0);
     set_option (OPTSIGNALSBLOCKED);
   }
@@ -214,15 +180,17 @@ void mutt_block_signals_system (void)
 {
   struct sigaction sa;
 
-  if (! option (OPTSIGNALSBLOCKED))
+  if (! option (OPTSYSSIGNALSBLOCKED))
   {
+    /* POSIX: ignore SIGINT and SIGQUIT & block SIGCHLD  before exec */
     sa.sa_handler = SIG_IGN;
     sa.sa_flags = 0;
     sigaction (SIGINT, &sa, NULL);
     sigaction (SIGQUIT, &sa, NULL);
-    sigemptyset (&Sigset);
-    sigaddset (&Sigset, SIGCHLD);
-    sigprocmask (SIG_BLOCK, &Sigset, 0);
+
+    sigemptyset (&SigsetSys);
+    sigaddset (&SigsetSys, SIGCHLD);
+    sigprocmask (SIG_BLOCK, &SigsetSys, 0);
     set_option (OPTSIGNALSBLOCKED);
   }
 }
@@ -231,15 +199,36 @@ void mutt_unblock_signals_system (int catch)
 {
   struct sigaction sa;
 
-  if (option (OPTSIGNALSBLOCKED))
+  if (option (OPTSYSSIGNALSBLOCKED))
   {
+    sigprocmask (SIG_UNBLOCK, &SigsetSys, NULL);
+    sigemptyset (&sa.sa_mask);
     sa.sa_flags = 0;
-    sa.sa_handler = mutt_exit_handler;
-    sigaction (SIGQUIT, &sa, NULL);
     if (catch)
+    {
+      sa.sa_handler = exit_handler;
+      sigaction (SIGQUIT, &sa, NULL);
+
+      /* we want to avoid race conditions */
+      sigaddset (&sa.sa_mask, SIGTSTP);
+      sigaddset (&sa.sa_mask, SIGINT);
+#if defined (USE_SLANG_CURSES) || defined (HAVE_RESIZETERM)
+      sigaddset (&sa.sa_mask, SIGWINCH);
+#endif
+      /* we also don't want to mess with interrupted system calls */
+#ifdef SA_RESTART
+      sa.sa_flags = SA_RESTART;
+#endif
       sa.sa_handler = sighandler;
-    sigaction (SIGINT, &sa, NULL);
-    sigprocmask (SIG_UNBLOCK, &Sigset, NULL);
+      sigaction (SIGINT, &sa, NULL);
+    }
+    else
+    {
+      sa.sa_handler = SIG_DFL;
+      sigaction (SIGQUIT, &sa, NULL);
+      sigaction (SIGINT, &sa, NULL);
+    }
+
     unset_option (OPTSIGNALSBLOCKED);
   }
 }
index eb9a2aad38aac30bb4a5fc61c05c5707b6ca757f..7bd1de29ca7db7c4163cd6d90419603fbd561b1c 100644 (file)
--- a/system.c
+++ b/system.c
@@ -28,50 +28,64 @@ int _mutt_system (const char *cmd, int flags)
 {
   int rc = -1;
   struct sigaction act;
-  struct sigaction oldcont;
   struct sigaction oldtstp;
-  struct sigaction oldint;
-  struct sigaction oldquit;
-  struct sigaction oldchld;
+  struct sigaction oldcont;
   sigset_t set;
   pid_t thepid;
 
-  /* must block SIGCHLD and ignore SIGINT and SIGQUIT */
+  if (!cmd || !*cmd)
+    return (0);
+
+  /* must ignore SIGINT and SIGQUIT */
 
-  act.sa_handler = SIG_IGN;
-  act.sa_flags = 0;
-  sigemptyset (&(act.sa_mask));
-  sigaction (SIGINT, &act, &oldint);
-  sigaction (SIGQUIT, &act, &oldquit);
+  mutt_block_signals_system ();
+
+  /* also don't want to be stopped right now */
   if (flags & M_DETACH_PROCESS)
   {
-    act.sa_flags = SA_NOCLDSTOP;
-    sigaction (SIGCHLD, &act, &oldchld);
-    act.sa_flags = 0;
+    sigemptyset (&set);
+    sigaddset (&set, SIGTSTP);
+    sigprocmask (SIG_BLOCK, &set, NULL);
   }
   else
   {
-    sigemptyset (&set);
-    sigaddset (&set, SIGCHLD);
-    sigprocmask (SIG_BLOCK, &set, NULL);
+    act.sa_handler = SIG_DFL;
+    /* we want to restart the waitpid() below */
+#ifdef SA_RESTART
+    act.sa_flags = SA_RESTART;
+#endif
+    sigemptyset (&act.sa_mask);
+    sigaction (SIGTSTP, &act, &oldtstp);
+    sigaction (SIGCONT, &act, &oldcont);
   }
 
-  act.sa_handler = SIG_DFL;
-  sigaction (SIGTSTP, &act, &oldtstp);
-  sigaction (SIGCONT, &act, &oldcont);
-
   if ((thepid = fork ()) == 0)
   {
-    /* reset signals for the child */
-    sigaction (SIGINT, &act, NULL);
-    sigaction (SIGQUIT, &act, NULL);
+    act.sa_flags = 0;
 
     if (flags & M_DETACH_PROCESS)
     {
+      int fd;
+
+      /* give up controlling terminal */
       setsid ();
+
       switch (fork ())
       {
        case 0:
+#if defined(OPEN_MAX)
+         for (fd = 0; fd < OPEN_MAX; fd++)
+           close (fd);
+#elif defined(_POSIX_OPEN_MAX)
+         for (fd = 0; fd < _POSIX_OPEN_MAX; fd++)
+           close (fd);
+#else
+         close (0);
+         close (1);
+         close (2);
+#endif
+         chdir ("/");
+         act.sa_handler = SIG_DFL;
          sigaction (SIGCHLD, &act, NULL);
          break;
 
@@ -82,30 +96,34 @@ int _mutt_system (const char *cmd, int flags)
          _exit (0);
       }
     }
-    else
-      sigprocmask (SIG_UNBLOCK, &set, NULL);
+
+    /* reset signals for the child; not really needed, but... */
+    mutt_unblock_signals_system (0);
+    act.sa_handler = SIG_DFL;
+    act.sa_flags = 0;
+    sigemptyset (&act.sa_mask);
+    sigaction (SIGTERM, &act, NULL);
+    sigaction (SIGTSTP, &act, NULL);
+    sigaction (SIGCONT, &act, NULL);
 
     execl (EXECSHELL, "sh", "-c", cmd, NULL);
     _exit (127); /* execl error */
   }
   else if (thepid != -1)
   {
-    /* wait for the child process to finish */
+    /* wait for the (first) child process to finish */
     waitpid (thepid, &rc, 0);
   }
 
+  sigaction (SIGCONT, &oldcont, NULL);
+  sigaction (SIGTSTP, &oldtstp, NULL);
+
   /* reset SIGINT, SIGQUIT and SIGCHLD */
-  sigaction (SIGINT, &oldint, NULL);
-  sigaction (SIGQUIT, &oldquit, NULL);
+  mutt_unblock_signals_system (1);
   if (flags & M_DETACH_PROCESS)
-    sigaction (SIGCHLD, &oldchld, NULL);
-  else
     sigprocmask (SIG_UNBLOCK, &set, NULL);
 
-  sigaction (SIGCONT, &oldcont, NULL);
-  sigaction (SIGTSTP, &oldtstp, NULL);
-
-  rc = WIFEXITED (rc) ? WEXITSTATUS (rc) : -1;
+  rc = (thepid != -1) ? (WIFEXITED (rc) ? WEXITSTATUS (rc) : -1) : -1;
 
   return (rc);
 }