mutt stable branch with some hacks
at master 143 lines 3.3 kB view raw
1/* 2 * Copyright (C) 1996-2000,2013 Michael R. Elkins <me@mutt.org> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 */ 18 19#if HAVE_CONFIG_H 20# include "config.h" 21#endif 22 23#include "mutt.h" 24#ifdef USE_IMAP 25# include "imap.h" 26# include <errno.h> 27#endif 28 29#include <stdlib.h> 30#include <signal.h> 31#include <string.h> 32#include <sys/wait.h> 33#include <unistd.h> 34 35extern char **envlist; 36 37int _mutt_system (const char *cmd, int flags) 38{ 39 int rc = -1; 40 struct sigaction act; 41 struct sigaction oldtstp; 42 struct sigaction oldcont; 43 sigset_t set; 44 pid_t thepid; 45 46 if (!cmd || !*cmd) 47 return (0); 48 49 /* must ignore SIGINT and SIGQUIT */ 50 51 mutt_block_signals_system (); 52 53 /* also don't want to be stopped right now */ 54 if (flags & MUTT_DETACH_PROCESS) 55 { 56 sigemptyset (&set); 57 sigaddset (&set, SIGTSTP); 58 sigprocmask (SIG_BLOCK, &set, NULL); 59 } 60 else 61 { 62 act.sa_handler = SIG_DFL; 63 /* we want to restart the waitpid() below */ 64#ifdef SA_RESTART 65 act.sa_flags = SA_RESTART; 66#endif 67 sigemptyset (&act.sa_mask); 68 sigaction (SIGTSTP, &act, &oldtstp); 69 sigaction (SIGCONT, &act, &oldcont); 70 } 71 72 if ((thepid = fork ()) == 0) 73 { 74 act.sa_flags = 0; 75 76 if (flags & MUTT_DETACH_PROCESS) 77 { 78 int fd; 79 80 /* give up controlling terminal */ 81 setsid (); 82 83 switch (fork ()) 84 { 85 case 0: 86#if defined(OPEN_MAX) 87 for (fd = 0; fd < OPEN_MAX; fd++) 88 close (fd); 89#elif defined(_POSIX_OPEN_MAX) 90 for (fd = 0; fd < _POSIX_OPEN_MAX; fd++) 91 close (fd); 92#else 93 close (0); 94 close (1); 95 close (2); 96#endif 97 chdir ("/"); 98 act.sa_handler = SIG_DFL; 99 sigaction (SIGCHLD, &act, NULL); 100 break; 101 102 case -1: 103 _exit (127); 104 105 default: 106 _exit (0); 107 } 108 } 109 110 /* reset signals for the child; not really needed, but... */ 111 mutt_unblock_signals_system (0); 112 act.sa_handler = SIG_DFL; 113 act.sa_flags = 0; 114 sigemptyset (&act.sa_mask); 115 sigaction (SIGTERM, &act, NULL); 116 sigaction (SIGTSTP, &act, NULL); 117 sigaction (SIGCONT, &act, NULL); 118 119 execle (EXECSHELL, "sh", "-c", cmd, NULL, envlist); 120 _exit (127); /* execl error */ 121 } 122 else if (thepid != -1) 123 { 124#ifndef USE_IMAP 125 /* wait for the (first) child process to finish */ 126 waitpid (thepid, &rc, 0); 127#else 128 rc = imap_wait_keepalive (thepid); 129#endif 130 } 131 132 sigaction (SIGCONT, &oldcont, NULL); 133 sigaction (SIGTSTP, &oldtstp, NULL); 134 135 /* reset SIGINT, SIGQUIT and SIGCHLD */ 136 mutt_unblock_signals_system (1); 137 if (flags & MUTT_DETACH_PROCESS) 138 sigprocmask (SIG_UNBLOCK, &set, NULL); 139 140 rc = (thepid != -1) ? (WIFEXITED (rc) ? WEXITSTATUS (rc) : -1) : -1; 141 142 return (rc); 143}