From: Karsten Horsmann
[apps/madmutt.git] / system.c
1 /*
2  * Copyright notice from original mutt:
3  * Copyright (C) 1996-2000 Michael R. Elkins <me@mutt.org>
4  *
5  * This file is part of mutt-ng, see http://www.muttng.org/.
6  * It's licensed under the GNU General Public License,
7  * please see the file GPL in the top level source directory.
8  */
9
10 #if HAVE_CONFIG_H
11 # include "config.h"
12 #endif
13
14 #include "mutt.h"
15 #ifdef USE_IMAP
16 # include "imap.h"
17 # include <errno.h>
18 #endif
19
20 #include <stdlib.h>
21 #include <signal.h>
22 #include <string.h>
23 #include <sys/wait.h>
24 #include <unistd.h>
25
26 int _mutt_system (const char *cmd, int flags)
27 {
28   int rc = -1;
29   struct sigaction act;
30   struct sigaction oldtstp;
31   struct sigaction oldcont;
32   sigset_t set;
33   pid_t thepid;
34
35   if (!cmd || !*cmd)
36     return (0);
37
38   /* must ignore SIGINT and SIGQUIT */
39
40   mutt_block_signals_system ();
41
42   /* also don't want to be stopped right now */
43   if (flags & M_DETACH_PROCESS) {
44     sigemptyset (&set);
45     sigaddset (&set, SIGTSTP);
46     sigprocmask (SIG_BLOCK, &set, NULL);
47   }
48   else {
49     act.sa_handler = SIG_DFL;
50     /* we want to restart the waitpid() below */
51 #ifdef SA_RESTART
52     act.sa_flags = SA_RESTART;
53 #endif
54     sigemptyset (&act.sa_mask);
55     sigaction (SIGTSTP, &act, &oldtstp);
56     sigaction (SIGCONT, &act, &oldcont);
57   }
58
59   if ((thepid = fork ()) == 0) {
60     act.sa_flags = 0;
61
62     if (flags & M_DETACH_PROCESS) {
63       int fd;
64
65       /* give up controlling terminal */
66       setsid ();
67
68       switch (fork ()) {
69       case 0:
70 #if defined(OPEN_MAX)
71         for (fd = 0; fd < OPEN_MAX; fd++)
72           close (fd);
73 #elif defined(_POSIX_OPEN_MAX)
74         for (fd = 0; fd < _POSIX_OPEN_MAX; fd++)
75           close (fd);
76 #else
77         close (0);
78         close (1);
79         close (2);
80 #endif
81         chdir ("/");
82         act.sa_handler = SIG_DFL;
83         sigaction (SIGCHLD, &act, NULL);
84         break;
85
86       case -1:
87         _exit (127);
88
89       default:
90         _exit (0);
91       }
92     }
93
94     /* reset signals for the child; not really needed, but... */
95     mutt_unblock_signals_system (0);
96     act.sa_handler = SIG_DFL;
97     act.sa_flags = 0;
98     sigemptyset (&act.sa_mask);
99     sigaction (SIGTERM, &act, NULL);
100     sigaction (SIGTSTP, &act, NULL);
101     sigaction (SIGCONT, &act, NULL);
102
103     execl (EXECSHELL, "sh", "-c", cmd, NULL);
104     _exit (127);                /* execl error */
105   }
106   else if (thepid != -1) {
107 #ifndef USE_IMAP
108     /* wait for the (first) child process to finish */
109     waitpid (thepid, &rc, 0);
110 #else
111     rc = imap_wait_keepalive (thepid);
112 #endif
113   }
114
115   sigaction (SIGCONT, &oldcont, NULL);
116   sigaction (SIGTSTP, &oldtstp, NULL);
117
118   /* reset SIGINT, SIGQUIT and SIGCHLD */
119   mutt_unblock_signals_system (1);
120   if (flags & M_DETACH_PROCESS)
121     sigprocmask (SIG_UNBLOCK, &set, NULL);
122
123   rc = (thepid != -1) ? (WIFEXITED (rc) ? WEXITSTATUS (rc) : -1) : -1;
124
125   return (rc);
126 }