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
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}