Make use of internal iospawn flags more flexible.
[gpgme.git] / src / assuan-support.c
1 #if HAVE_CONFIG_H
2 #include <config.h>
3 #endif
4
5 #include <assert.h>
6 #include <stdlib.h>
7 #include <errno.h>
8
9 #include "assuan.h"
10
11 #include "gpgme.h"
12 #include "ath.h"
13 #include "priv-io.h"
14 #include "debug.h"
15
16 \f
17 struct assuan_malloc_hooks _gpgme_assuan_malloc_hooks =
18   {
19     malloc,
20     realloc,
21     free
22   };
23
24 \f
25 int
26 _gpgme_assuan_log_cb (assuan_context_t ctx, void *hook,
27                       unsigned int cat, const char *msg)
28 {
29   if (msg == NULL)
30     return 1;
31
32   _gpgme_debug (DEBUG_ASSUAN, "%s", msg);
33   return 0;
34 }
35
36 \f
37 static void
38 my_usleep (assuan_context_t ctx, unsigned int usec)
39 {
40   /* FIXME: Add to ath.  */
41   __assuan_usleep (ctx, usec);
42 }
43
44
45 /* Create a pipe with an inheritable end.  */
46 static int
47 my_pipe (assuan_context_t ctx, assuan_fd_t fds[2], int inherit_idx)
48 {
49   int res;
50   int gfds[2];
51
52   res = _gpgme_io_pipe (gfds, inherit_idx);
53
54   /* For now... */
55   fds[0] = (assuan_fd_t) gfds[0];
56   fds[1] = (assuan_fd_t) gfds[1];
57
58   return res;
59 }
60
61
62 /* Close the given file descriptor, created with _assuan_pipe or one
63    of the socket functions.  */
64 static int
65 my_close (assuan_context_t ctx, assuan_fd_t fd)
66 {
67   return _gpgme_io_close ((int) fd);
68 }
69
70
71 static gpgme_ssize_t
72 my_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
73 {
74   return _gpgme_io_read ((int) fd, buffer, size);
75 }
76
77
78 static gpgme_ssize_t
79 my_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer, size_t size)
80 {
81   return _gpgme_io_write ((int) fd, buffer, size);
82 }
83
84
85 static int
86 my_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
87             int flags)
88 {
89 #ifdef HAVE_W32_SYSTEM
90   gpg_err_set_errno (ENOSYS);
91   return -1;
92 #else
93   return _gpgme_io_recvmsg ((int) fd, msg, flags);
94 #endif
95 }
96
97
98
99 static int
100 my_sendmsg (assuan_context_t ctx, assuan_fd_t fd, const assuan_msghdr_t msg,
101             int flags)
102 {
103 #ifdef HAVE_W32_SYSTEM
104   gpg_err_set_errno (ENOSYS);
105   return -1;
106 #else
107   return _gpgme_io_sendmsg ((int) fd, msg, flags);
108 #endif
109 }
110
111
112 /* If NAME is NULL, don't exec, just fork.  FD_CHILD_LIST is modified
113    to reflect the value of the FD in the peer process (on
114    Windows).  */
115 static int
116 my_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
117           const char **argv,
118           assuan_fd_t fd_in, assuan_fd_t fd_out,
119           assuan_fd_t *fd_child_list,
120           void (*atfork) (void *opaque, int reserved),
121           void *atforkvalue, unsigned int flags)
122 {
123   int err;
124   struct spawn_fd_item_s *fd_items;
125   int i;
126
127   assert (name);
128
129   if (! name)
130     {
131       gpg_err_set_errno (ENOSYS);
132       return -1;
133     }
134
135   i = 0;
136   if (fd_child_list)
137     {
138       while (fd_child_list[i] != ASSUAN_INVALID_FD)
139         i++;
140     }
141   /* fd_in, fd_out, terminator */
142   i += 3;
143   fd_items = calloc (i, sizeof (struct spawn_fd_item_s));
144   if (! fd_items)
145     return -1;
146   i = 0;
147   if (fd_child_list)
148     {
149       while (fd_child_list[i] != ASSUAN_INVALID_FD)
150         {
151           fd_items[i].fd = (int) fd_child_list[i];
152           fd_items[i].dup_to = -1;
153           i++;
154         }
155     }
156   if (fd_in != ASSUAN_INVALID_FD)
157     {
158       fd_items[i].fd = (int) fd_in;
159       fd_items[i].dup_to = 0;
160       i++;
161     }
162   if (fd_out != ASSUAN_INVALID_FD)
163     {
164       fd_items[i].fd = (int) fd_out;
165       fd_items[i].dup_to = 1;
166       i++;
167     }
168   fd_items[i].fd = -1;
169   fd_items[i].dup_to = -1;
170
171   err = _gpgme_io_spawn (name, (char*const*)argv,
172                          (IOSPAWN_FLAG_NOCLOSE | IOSPAWN_FLAG_DETACHED),
173                          fd_items, atfork, atforkvalue, r_pid);
174   if (! err)
175     {
176       i = 0;
177
178       if (fd_child_list)
179         {
180           while (fd_child_list[i] != ASSUAN_INVALID_FD)
181             {
182               fd_child_list[i] = (assuan_fd_t) fd_items[i].peer_name;
183               i++;
184             }
185         }
186     }
187   free (fd_items);
188   return err;
189 }
190
191
192 /* If action is 0, like waitpid.  If action is 1, just release the PID?  */
193 static pid_t
194 my_waitpid (assuan_context_t ctx, pid_t pid,
195             int nowait, int *status, int options)
196 {
197 #ifdef HAVE_W32_SYSTEM
198   CloseHandle ((HANDLE) pid);
199 #else
200   /* We can't just release the PID, a waitpid is mandatory.  But
201      NOWAIT in POSIX systems just means the caller already did the
202      waitpid for this child.  */
203   if (! nowait)
204     return _gpgme_ath_waitpid (pid, status, options);
205 #endif
206   return 0;
207 }
208
209
210
211
212 static int
213 my_socketpair (assuan_context_t ctx, int namespace, int style,
214                int protocol, assuan_fd_t filedes[2])
215 {
216 #ifdef HAVE_W32_SYSTEM
217   gpg_err_set_errno (ENOSYS);
218   return -1;
219 #else
220   /* FIXME: Debug output missing.  */
221   return __assuan_socketpair (ctx, namespace, style, protocol, filedes);
222 #endif
223 }
224
225
226 static int
227 my_socket (assuan_context_t ctx, int namespace, int style, int protocol)
228 {
229   return _gpgme_io_socket (namespace, style, protocol);
230 }
231
232
233 static int
234 my_connect (assuan_context_t ctx, int sock, struct sockaddr *addr,
235             socklen_t length)
236 {
237   return _gpgme_io_connect (sock, addr, length);
238 }
239
240
241 struct assuan_system_hooks _gpgme_assuan_system_hooks =
242   {
243     ASSUAN_SYSTEM_HOOKS_VERSION,
244     my_usleep,
245     my_pipe,
246     my_close,
247     my_read,
248     my_write,
249     my_recvmsg,
250     my_sendmsg,
251     my_spawn,
252     my_waitpid,
253     my_socketpair,
254     my_socket,
255     my_connect
256   };
257