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