2009-11-10 Marcus Brinkmann <marcus@g10code.de>
[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 /* Create a pipe with an inheritable end.  */
45 static int
46 my_pipe (assuan_context_t ctx, assuan_fd_t fds[2], int inherit_idx)
47 {
48   return _gpgme_io_pipe (fds, inherit_idx);
49 }
50
51
52 /* Close the given file descriptor, created with _assuan_pipe or one
53    of the socket functions.  */
54 static int
55 my_close (assuan_context_t ctx, assuan_fd_t fd)
56 {
57   return _gpgme_io_close (fd);
58 }
59
60
61 static ssize_t
62 my_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
63 {
64   return _gpgme_io_read (fd, buffer, size);
65 }
66
67
68 static ssize_t
69 my_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer, size_t size)
70 {
71   return _gpgme_io_write (fd, buffer, size);
72 }
73
74
75 static int
76 my_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
77             int flags)
78 {
79 #ifdef HAVE_W32_SYSTEM
80   errno = ENOSYS;
81   return -1;
82 #else
83   return _gpgme_io_recvmsg (fd, msg, flags);
84 #endif
85 }
86
87
88
89 static int
90 my_sendmsg (assuan_context_t ctx, assuan_fd_t fd, const assuan_msghdr_t msg,
91             int flags)
92 {
93 #ifdef HAVE_W32_SYSTEM
94   errno = ENOSYS;
95   return -1;
96 #else
97   return _gpgme_io_sendmsg (fd, msg, flags);
98 #endif
99 }
100
101
102 /* If NAME is NULL, don't exec, just fork.  FD_CHILD_LIST is modified
103    to reflect the value of the FD in the peer process (on
104    Windows).  */
105 static int
106 my_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
107           const char **argv,
108           assuan_fd_t fd_in, assuan_fd_t fd_out,
109           assuan_fd_t *fd_child_list,
110           void (*atfork) (void *opaque, int reserved),
111           void *atforkvalue, unsigned int flags)
112 {
113   int err;
114   struct spawn_fd_item_s *fd_items;
115   int i;
116
117   assert (name);
118
119   if (! name)
120     {
121       errno = ENOSYS;
122       return -1;
123     }
124
125   i = 0;
126   if (fd_child_list)
127     {
128       while (fd_child_list[i] != ASSUAN_INVALID_FD)
129         i++;
130     }
131   /* fd_in, fd_out, terminator */
132   i += 3;
133   fd_items = malloc (sizeof (struct spawn_fd_item_s) * i);
134   if (! fd_items)
135     return -1;
136   i = 0;
137   if (fd_child_list)
138     {
139       while (fd_child_list[i] != ASSUAN_INVALID_FD)
140         {
141           fd_items[i].fd = fd_child_list[i];
142           fd_items[i].dup_to = -1;
143           i++;
144         }
145     }
146   if (fd_in != ASSUAN_INVALID_FD)
147     {
148       fd_items[i].fd = fd_in;
149       fd_items[i].dup_to = 0;
150       i++;
151     }
152   if (fd_out != ASSUAN_INVALID_FD)
153     {
154       fd_items[i].fd = fd_out;
155       fd_items[i].dup_to = 1;
156       i++;
157     }
158   fd_items[i].fd = -1;
159   fd_items[i].dup_to = -1;
160
161   err = _gpgme_io_spawn (name, argv, IOSPAWN_FLAG_NOCLOSE, fd_items,
162                          atfork, atforkvalue, r_pid);
163   if (! err)
164     {
165       i = 0;
166
167       if (fd_child_list)
168         {
169           while (fd_child_list[i] != ASSUAN_INVALID_FD)
170             {
171               fd_child_list[i] = fd_items[i].peer_name;
172               i++;
173             }
174         }
175     }
176   free (fd_items);
177   return err;
178 }
179
180
181 /* If action is 0, like waitpid.  If action is 1, just release the PID?  */
182 static pid_t
183 my_waitpid (assuan_context_t ctx, pid_t pid,
184             int nowait, int *status, int options)
185 {
186 #ifdef HAVE_W32_SYSTEM
187   CloseHandle ((HANDLE) pid);
188 #else
189   /* We can't just release the PID, a waitpid is mandatory.  But
190      NOWAIT in POSIX systems just means the caller already did the
191      waitpid for this child.  */
192   if (! nowait)
193     return _gpgme_ath_waitpid (pid, status, options); 
194 #endif
195   return 0;
196 }
197
198
199
200
201 static int
202 my_socketpair (assuan_context_t ctx, int namespace, int style,
203                int protocol, assuan_fd_t filedes[2])
204 {
205 #ifdef HAVE_W32_SYSTEM
206   errno = ENOSYS;
207   return -1;
208 #else
209   /* FIXME: Debug output missing.  */
210   return __assuan_socketpair (ctx, namespace, style, protocol, filedes);
211 #endif
212 }
213
214
215 struct assuan_system_hooks _gpgme_assuan_system_hooks =
216   {
217     ASSUAN_SYSTEM_HOOKS_VERSION,
218     my_usleep,
219     my_pipe,
220     my_close,
221     my_read,
222     my_write,
223     my_recvmsg,
224     my_sendmsg,
225     my_spawn,
226     my_waitpid,
227     my_socketpair
228   };
229