diff options
author | Thomas Roessler <roessler@does-not-exist.org> | 1999-02-10 21:19:34 +0000 |
---|---|---|
committer | Thomas Roessler <roessler@does-not-exist.org> | 1999-02-10 21:19:34 +0000 |
commit | 15739ddd2345d227a16d18a3abfb740ae7c2ec0f (patch) | |
tree | bd608a8b9771d60c785a9cc84e297748960fe33d | |
parent | 25a768b966efe0f5570d6b6356b9752add6efb49 (diff) |
patch.mutt-0.95.1i.ld.signals.1: A major redesign of how child
processes are invoked. From Liviu.
-rw-r--r-- | TODO | 4 | ||||
-rw-r--r-- | attach.c | 11 | ||||
-rw-r--r-- | commands.c | 10 | ||||
-rw-r--r-- | compose.c | 6 | ||||
-rw-r--r-- | curs_lib.c | 12 | ||||
-rw-r--r-- | globals.h | 3 | ||||
-rw-r--r-- | mutt.h | 12 | ||||
-rw-r--r-- | protos.h | 1 | ||||
-rw-r--r-- | send.c | 9 | ||||
-rw-r--r-- | sendlib.c | 270 | ||||
-rw-r--r-- | signal.c | 147 | ||||
-rw-r--r-- | system.c | 86 |
12 files changed, 302 insertions, 269 deletions
@@ -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 @@ -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); } } } @@ -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); @@ -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: @@ -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; @@ -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; @@ -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 { @@ -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); @@ -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) { @@ -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); } @@ -22,20 +22,19 @@ #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); } } @@ -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); } |