Rocco Rutte:
[apps/madmutt.git] / system.c
1 /*
2  * Copyright (C) 1996-2000 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., 59 Temple Place - Suite 330, Boston, MA  02111, 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
35 int _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 & M_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 & M_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     execl (EXECSHELL, "sh", "-c", cmd, NULL);
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 & M_DETACH_PROCESS)
136     sigprocmask (SIG_UNBLOCK, &set, NULL);
137
138   rc = (thepid != -1) ? (WIFEXITED (rc) ? WEXITSTATUS (rc) : -1) : -1;
139
140   return (rc);
141 }