mutt stable branch with some hacks
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}