Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / camel / camel-process.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  *  Authors: Jeffrey Stedfast <fejj@ximian.com>
4  *
5  *  Copyright 2003 Ximian, Inc. (www.ximian.com)
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU Lesser General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31
32 #include "camel-process.h"
33
34
35 pid_t
36 camel_process_fork (const char *path, char **argv, int *infd, int *outfd, int *errfd, CamelException *ex)
37 {
38         int errnosav, fd[6], i;
39         pid_t pid;
40         
41         for (i = 0; i < 6; i++)
42                 fds[i] = -1;
43         
44         for (i = 0; i < 6; i += 2) {
45                 if (pipe (fd + i) == -1) {
46                         errnosav = errno;
47                         camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
48                                               _("Failed to create pipe to '%s': %s"),
49                                               argv[0], strerror (errno));
50                         
51                         for (i = 0; i < 6; i++) {
52                                 if (fd[i] == -1)
53                                         break;
54                                 close (fd[i]);
55                         }
56                         
57                         errno = errnosav;
58                         
59                         return -1;
60                 }
61         }
62         
63         if (!(pid = fork ())) {
64                 /* child process */
65                 int maxfd, nullfd = -1;
66                 
67                 if (!outfd || !errfd)
68                         nullfd = open ("/dev/null", O_WRONLY);
69                 
70                 if (dup2 (fd[0], STDIN_FILENO) == -1)
71                         _exit (255);
72                 
73                 if (dup2 (outfd ? fd[3] : nullfd, STDOUT_FILENO) == -1)
74                         _exit (255);
75                 
76                 if (dup2 (errfd ? fd[5] : nullfd, STDERR_FILENO) == -1)
77                         _exit (255);
78                 
79                 setsid ();
80                 
81                 if ((maxfd = sysconf (_SC_OPEN_MAX)) > 0) {
82                         for (i = 3; i < maxfd; i++)
83                                 fcntl (i, F_SETFD, FD_CLOEXEC);
84                 }
85                 
86                 execv (path, argv);
87                 _exit (255);
88         } else if (pid == -1) {
89                 camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
90                                       _("Failed to create child process '%s': %s"),
91                                       argv[0], strerror (errno));
92                 for (i = 0; i < 6; i++) 
93                         close (fd[i]);
94                 return -1;
95         }
96         
97         /* parent process */
98         close (fd[0]);
99         close (fd[3]);
100         close (fd[5]);
101         
102         if (infd)
103                 *infd = fd[1];
104         else
105                 close (fd[1]);
106         
107         if (outfd)
108                 *outfd = fd[2];
109         else
110                 close (fd[2]);
111         
112         if (errfd)
113                 *errfd = fd[4];
114         else
115                 close (fd[4]);
116         
117         return pid;
118 }
119
120
121 int
122 camel_process_wait (pid_t pid)
123 {
124         sigset_t mask, omask;
125         int status;
126         pid_t r;
127         
128         sigemptyset (&mask);
129         sigaddset (&mask, SIGALRM);
130         sigprocmask (SIG_BLOCK, &mask, &omask);
131         alarm (1);
132         
133         r = waitpid (pid, &status, 0);
134         
135         alarm (0);
136         sigprocmask (SIG_SETMASK, &omask, NULL);
137         
138         if (r == (pid_t) -1 && errno == EINTR) {
139                 kill (pid, SIGTERM);
140                 sleep (1);
141                 r = waitpid (pid, &status, WNOHANG);
142                 if (r == (pid_t) 0) {
143                         kill (pid, SIGKILL);
144                         sleep (1);
145                         r = waitpid (pid, &status, WNOHANG);
146                 }
147         }
148         
149         if (r != (pid_t) -1 && WIFEXITED (status))
150                 return WEXITSTATUS (status);
151         else
152                 return -1;
153 }