mutt stable branch with some hacks
at jcs 141 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 35int _mutt_system (const char *cmd, int flags) 36{ 37 int rc = -1; 38 struct sigaction act; 39 struct sigaction oldtstp; 40 struct sigaction oldcont; 41 sigset_t set; 42 pid_t thepid; 43 44 if (!cmd || !*cmd) 45 return (0); 46 47 /* must ignore SIGINT and SIGQUIT */ 48 49 mutt_block_signals_system (); 50 51 /* also don't want to be stopped right now */ 52 if (flags & MUTT_DETACH_PROCESS) 53 { 54 sigemptyset (&set); 55 sigaddset (&set, SIGTSTP); 56 sigprocmask (SIG_BLOCK, &set, NULL); 57 } 58 else 59 { 60 act.sa_handler = SIG_DFL; 61 /* we want to restart the waitpid() below */ 62#ifdef SA_RESTART 63 act.sa_flags = SA_RESTART; 64#endif 65 sigemptyset (&act.sa_mask); 66 sigaction (SIGTSTP, &act, &oldtstp); 67 sigaction (SIGCONT, &act, &oldcont); 68 } 69 70 if ((thepid = fork ()) == 0) 71 { 72 act.sa_flags = 0; 73 74 if (flags & MUTT_DETACH_PROCESS) 75 { 76 int fd; 77 78 /* give up controlling terminal */ 79 setsid (); 80 81 switch (fork ()) 82 { 83 case 0: 84#if defined(OPEN_MAX) 85 for (fd = 0; fd < OPEN_MAX; fd++) 86 close (fd); 87#elif defined(_POSIX_OPEN_MAX) 88 for (fd = 0; fd < _POSIX_OPEN_MAX; fd++) 89 close (fd); 90#else 91 close (0); 92 close (1); 93 close (2); 94#endif 95 chdir ("/"); 96 act.sa_handler = SIG_DFL; 97 sigaction (SIGCHLD, &act, NULL); 98 break; 99 100 case -1: 101 _exit (127); 102 103 default: 104 _exit (0); 105 } 106 } 107 108 /* reset signals for the child; not really needed, but... */ 109 mutt_unblock_signals_system (0); 110 act.sa_handler = SIG_DFL; 111 act.sa_flags = 0; 112 sigemptyset (&act.sa_mask); 113 sigaction (SIGTERM, &act, NULL); 114 sigaction (SIGTSTP, &act, NULL); 115 sigaction (SIGCONT, &act, NULL); 116 117 execle (EXECSHELL, "sh", "-c", cmd, NULL, mutt_envlist ()); 118 _exit (127); /* execl error */ 119 } 120 else if (thepid != -1) 121 { 122#ifndef USE_IMAP 123 /* wait for the (first) child process to finish */ 124 waitpid (thepid, &rc, 0); 125#else 126 rc = imap_wait_keepalive (thepid); 127#endif 128 } 129 130 sigaction (SIGCONT, &oldcont, NULL); 131 sigaction (SIGTSTP, &oldtstp, NULL); 132 133 /* reset SIGINT, SIGQUIT and SIGCHLD */ 134 mutt_unblock_signals_system (1); 135 if (flags & MUTT_DETACH_PROCESS) 136 sigprocmask (SIG_UNBLOCK, &set, NULL); 137 138 rc = (thepid != -1) ? (WIFEXITED (rc) ? WEXITSTATUS (rc) : -1) : -1; 139 140 return (rc); 141}