aboutsummaryrefslogtreecommitdiffstats
path: root/camel/camel-process.c
diff options
context:
space:
mode:
Diffstat (limited to 'camel/camel-process.c')
-rw-r--r--camel/camel-process.c153
1 files changed, 153 insertions, 0 deletions
diff --git a/camel/camel-process.c b/camel/camel-process.c
new file mode 100644
index 0000000000..01c1e3be3d
--- /dev/null
+++ b/camel/camel-process.c
@@ -0,0 +1,153 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Authors: Jeffrey Stedfast <fejj@ximian.com>
+ *
+ * Copyright 2003 Ximian, Inc. (www.ximian.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "camel-process.h"
+
+
+pid_t
+camel_process_fork (const char *path, char **argv, int *infd, int *outfd, int *errfd, CamelException *ex)
+{
+ int errnosav, fd[6], i;
+ pid_t pid;
+
+ for (i = 0; i < 6; i++)
+ fds[i] = -1;
+
+ for (i = 0; i < 6; i += 2) {
+ if (pipe (fd + i) == -1) {
+ errnosav = errno;
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to create pipe to '%s': %s"),
+ argv[0], strerror (errno));
+
+ for (i = 0; i < 6; i++) {
+ if (fd[i] == -1)
+ break;
+ close (fd[i]);
+ }
+
+ errno = errnosav;
+
+ return -1;
+ }
+ }
+
+ if (!(pid = fork ())) {
+ /* child process */
+ int maxfd, nullfd = -1;
+
+ if (!outfd || !errfd)
+ nullfd = open ("/dev/null", O_WRONLY);
+
+ if (dup2 (fd[0], STDIN_FILENO) == -1)
+ _exit (255);
+
+ if (dup2 (outfd ? fd[3] : nullfd, STDOUT_FILENO) == -1)
+ _exit (255);
+
+ if (dup2 (errfd ? fd[5] : nullfd, STDERR_FILENO) == -1)
+ _exit (255);
+
+ setsid ();
+
+ if ((maxfd = sysconf (_SC_OPEN_MAX)) > 0) {
+ for (i = 0; i < maxfd; i++) {
+ if (i != STDIN_FILENO && i != STDOUT_FILENO && i != STDERR_FILENO)
+ close (i);
+ }
+ }
+
+ execv (path, argv);
+ _exit (255);
+ } else if (pid == -1) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
+ _("Failed to create create child process '%s': %s"),
+ argv[0], strerror (errno));
+ return -1;
+ }
+
+ /* parent process */
+ close (fd[0]);
+ close (fd[3]);
+ close (fd[5]);
+
+ if (infd)
+ *infd = fd[1];
+ else
+ close (fd[1]);
+
+ if (outfd)
+ *outfd = fd[2];
+ else
+ close (fd[2]);
+
+ if (errfd)
+ *errfd = fd[4];
+ else
+ close (fd[4]);
+
+ return pid;
+}
+
+
+int
+camel_process_wait (pid_t pid)
+{
+ sigset_t mask, omask;
+ int status;
+ pid_t r;
+
+ sigemptyset (&mask);
+ sigaddset (&mask, SIGALRM);
+ sigprocmask (SIG_BLOCK, &mask, &omask);
+ alarm (1);
+
+ r = waitpid (pid, &status, 0);
+
+ alarm (0);
+ sigprocmask (SIG_SETMASK, &omask, NULL);
+
+ if (r == (pid_t) -1 && errno == EINTR) {
+ kill (pid, SIGTERM);
+ sleep (1);
+ r = waitpid (pid, &status, WNOHANG);
+ if (r == (pid_t) 0) {
+ kill (pid, SIGKILL);
+ sleep (1);
+ r = waitpid (pid, &status, WNOHANG);
+ }
+ }
+
+ if (r != (pid_t) -1 && WIFEXITED (status))
+ return WEXITSTATUS (status);
+ else
+ return -1;
+}