move signal.c into lib/sys
[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 <errno.h>
15 #include <stdlib.h>
16 #include <signal.h>
17 #include <string.h>
18 #include <sys/wait.h>
19 #include <unistd.h>
20
21 #include <lib-sys/mutt_signal.h>
22
23 #include "mutt.h"
24 #include <imap/imap.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 ("/bin/sh", "sh", "-c", cmd, NULL);
104     _exit (127);                /* execl error */
105   }
106   else if (thepid != -1) {
107     rc = imap_wait_keepalive (thepid);
108   }
109
110   sigaction (SIGCONT, &oldcont, NULL);
111   sigaction (SIGTSTP, &oldtstp, NULL);
112
113   /* reset SIGINT, SIGQUIT and SIGCHLD */
114   mutt_unblock_signals_system (1);
115   if (flags & M_DETACH_PROCESS)
116     sigprocmask (SIG_UNBLOCK, &set, NULL);
117
118   rc = (thepid != -1) ? (WIFEXITED (rc) ? WEXITSTATUS (rc) : -1) : -1;
119
120   return (rc);
121 }