exit system.c, mutt_system goes into lib-sys/
[apps/madmutt.git] / lib-sys / unix.c
index 372ff06..f2141c0 100644 (file)
@@ -8,13 +8,20 @@
  * please see the file GPL in the top level source directory.
  */
 
+#include <errno.h>
 #include <stdlib.h>
+#include <sys/wait.h>
+#include <unistd.h>
 
 #include <lib-lib/macros.h>
 #include <lib-lib/mem.h>
 #include <lib-lib/str.h>
 
 #include "unix.h"
+#include "mutt_signal.h"
+
+#include <imap/imap.h> /* for imap_wait_keepalive EEEEK */
+
 
 /* Extract the real name from /etc/passwd's GECOS field.
  * When set, honor the regular expression in rx,
@@ -61,3 +68,91 @@ ssize_t mutt_gecos_name(char *dst, ssize_t n, struct passwd *pw, rx_t *rx)
 
     return len;
 }
+
+int _mutt_system(const char *cmd, int flags)
+{
+    int rc = -1;
+    struct sigaction act;
+    struct sigaction oldtstp;
+    struct sigaction oldcont;
+    sigset_t set;
+    pid_t pid;
+
+    if (m_strisempty(cmd))
+        return 0;
+
+    /* must ignore SIGINT and SIGQUIT */
+    mutt_block_signals_system();
+
+    /* also don't want to be stopped right now */
+    if (flags & M_DETACH_PROCESS) {
+        sigemptyset(&set);
+        sigaddset(&set, SIGTSTP);
+        sigprocmask(SIG_BLOCK, &set, NULL);
+    } else {
+        act.sa_handler = SIG_DFL;
+        /* we want to restart the waitpid() below */
+#ifdef SA_RESTART
+        act.sa_flags = SA_RESTART;
+#endif
+        sigemptyset(&act.sa_mask);
+        sigaction(SIGTSTP, &act, &oldtstp);
+        sigaction(SIGCONT, &act, &oldcont);
+    }
+
+    pid = fork ();
+    if (pid == 0) {
+        act.sa_flags = 0;
+
+        if (flags & M_DETACH_PROCESS) {
+            /* give up controlling terminal */
+            setsid();
+
+            switch (fork()) {
+                int fd, nb_fds;
+
+              case 0:
+                nb_fds = getdtablesize();
+                for (fd = 0; fd < nb_fds; fd++) {
+                    close(fd);
+                }
+                chdir ("/");
+                act.sa_handler = SIG_DFL;
+                sigaction(SIGCHLD, &act, NULL);
+                break;
+
+              case -1:
+                _exit(127);
+
+              default:
+                _exit(0);
+            }
+        }
+
+        /* reset signals for the child; not really needed, but... */
+        mutt_unblock_signals_system(0);
+        act.sa_handler = SIG_DFL;
+        act.sa_flags = 0;
+        sigemptyset(&act.sa_mask);
+        sigaction(SIGTERM, &act, NULL);
+        sigaction(SIGTSTP, &act, NULL);
+        sigaction(SIGCONT, &act, NULL);
+
+        execl("/bin/sh", "sh", "-c", cmd, NULL);
+        _exit(127);                /* execl error */
+    } else
+    if (pid != -1) {
+        rc = imap_wait_keepalive(pid);
+    }
+
+    sigaction(SIGCONT, &oldcont, NULL);
+    sigaction(SIGTSTP, &oldtstp, NULL);
+
+    /* reset SIGINT, SIGQUIT and SIGCHLD */
+    mutt_unblock_signals_system(1);
+    if (flags & M_DETACH_PROCESS) {
+        sigprocmask (SIG_UNBLOCK, &set, NULL);
+    }
+
+    return (pid > 0 && WIFEXITED(rc)) ? WEXITSTATUS(rc) : -1;
+}