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