Line data Source code
1 : /* system.c - System support functions.
2 : Copyright (C) 2009 Free Software Foundation, Inc.
3 :
4 : This file is part of Assuan.
5 :
6 : Assuan is free software; you can redistribute it and/or modify it
7 : under the terms of the GNU Lesser General Public License as
8 : published by the Free Software Foundation; either version 2.1 of
9 : the License, or (at your option) any later version.
10 :
11 : Assuan is distributed in the hope that it will be useful, but
12 : WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 : Lesser General Public License for more details.
15 :
16 : You should have received a copy of the GNU Lesser General Public
17 : License along with this program; if not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 :
21 : #ifdef HAVE_CONFIG_H
22 : #include <config.h>
23 : #endif
24 :
25 : #include <stdlib.h>
26 : #include <errno.h>
27 : #ifdef HAVE_SYS_TYPES_H
28 : /* Solaris 8 needs sys/types.h before time.h. */
29 : # include <sys/types.h>
30 : #endif
31 : #include <time.h>
32 : #ifdef HAVE_FCNTL_H
33 : #include <fcntl.h>
34 : #endif
35 :
36 : #include "assuan-defs.h"
37 : #include "debug.h"
38 :
39 : #define DEBUG_SYSIO 0
40 :
41 :
42 :
43 :
44 : /* Manage memory specific to a context. */
45 :
46 : void *
47 7 : _assuan_malloc (assuan_context_t ctx, size_t cnt)
48 : {
49 7 : return ctx->malloc_hooks.malloc (cnt);
50 : }
51 :
52 : void *
53 0 : _assuan_realloc (assuan_context_t ctx, void *ptr, size_t cnt)
54 : {
55 0 : return ctx->malloc_hooks.realloc (ptr, cnt);
56 : }
57 :
58 : void *
59 2 : _assuan_calloc (assuan_context_t ctx, size_t cnt, size_t elsize)
60 : {
61 : void *ptr;
62 : size_t nbytes;
63 :
64 2 : nbytes = cnt * elsize;
65 :
66 : /* Check for overflow. */
67 2 : if (elsize && nbytes / elsize != cnt)
68 : {
69 0 : gpg_err_set_errno (ENOMEM);
70 0 : return NULL;
71 : }
72 :
73 2 : ptr = ctx->malloc_hooks.malloc (nbytes);
74 2 : if (ptr)
75 2 : memset (ptr, 0, nbytes);
76 2 : return ptr;
77 : }
78 :
79 : void
80 13 : _assuan_free (assuan_context_t ctx, void *ptr)
81 : {
82 13 : if (ptr)
83 9 : ctx->malloc_hooks.free (ptr);
84 13 : }
85 :
86 :
87 : /* Release the memory at PTR using the allocation handler of the
88 : context CTX. This is a convenience function. */
89 : void
90 0 : assuan_free (assuan_context_t ctx, void *ptr)
91 : {
92 0 : _assuan_free (ctx, ptr);
93 0 : }
94 :
95 :
96 :
97 : /* Copy the system hooks struct, paying attention to version
98 : differences. SRC is usually from the user, DST MUST be from the
99 : library. */
100 : void
101 0 : _assuan_system_hooks_copy (assuan_system_hooks_t dst,
102 : assuan_system_hooks_t src)
103 :
104 : {
105 : /* Reset the defaults. */
106 0 : if (dst != &_assuan_system_hooks)
107 0 : memcpy (dst, &_assuan_system_hooks, sizeof (*dst));
108 :
109 0 : dst->version = ASSUAN_SYSTEM_HOOKS_VERSION;
110 0 : if (src->version >= 1)
111 : {
112 0 : dst->usleep = src->usleep;
113 0 : dst->pipe = src->pipe;
114 0 : dst->close = src->close;
115 0 : dst->read = src->read;
116 0 : dst->write = src->write;
117 0 : dst->sendmsg = src->sendmsg;
118 0 : dst->recvmsg = src->recvmsg;
119 0 : dst->spawn = src->spawn;
120 0 : dst->waitpid = src->waitpid;
121 0 : dst->socketpair = src->socketpair;
122 : }
123 0 : if (src->version >= 2)
124 : {
125 0 : dst->socket = src->socket;
126 0 : dst->connect = src->connect;
127 : }
128 0 : if (src->version > 2)
129 : /* FIXME. Application uses newer version of the library. What to
130 : do? */
131 : ;
132 0 : }
133 :
134 :
135 :
136 : /* Sleep for the given number of microseconds. */
137 : void
138 0 : _assuan_usleep (assuan_context_t ctx, unsigned int usec)
139 : {
140 0 : TRACE1 (ctx, ASSUAN_LOG_SYSIO, "_assuan_usleep", ctx,
141 : "usec=%u", usec);
142 :
143 0 : (ctx->system.usleep) (ctx, usec);
144 0 : }
145 :
146 :
147 :
148 : /* Create a pipe with one inheritable end. */
149 : int
150 2 : _assuan_pipe (assuan_context_t ctx, assuan_fd_t fd[2], int inherit_idx)
151 : {
152 : int err;
153 2 : TRACE_BEG2 (ctx, ASSUAN_LOG_SYSIO, "_assuan_pipe", ctx,
154 : "inherit_idx=%i (Assuan uses it for %s)",
155 : inherit_idx, inherit_idx ? "reading" : "writing");
156 :
157 2 : err = (ctx->system.pipe) (ctx, fd, inherit_idx);
158 2 : if (err)
159 0 : return TRACE_SYSRES (err);
160 :
161 2 : return TRACE_SUC2 ("read=0x%x, write=0x%x", fd[0], fd[1]);
162 : }
163 :
164 :
165 :
166 : /* Close the given file descriptor, created with _assuan_pipe or one
167 : of the socket functions. */
168 : int
169 9 : _assuan_close (assuan_context_t ctx, assuan_fd_t fd)
170 : {
171 9 : TRACE1 (ctx, ASSUAN_LOG_SYSIO, "_assuan_close", ctx,
172 : "fd=0x%x", fd);
173 :
174 9 : return (ctx->system.close) (ctx, fd);
175 : }
176 :
177 :
178 : /* Same as assuan_close but used for the inheritable end of a
179 : pipe. */
180 : int
181 2 : _assuan_close_inheritable (assuan_context_t ctx, assuan_fd_t fd)
182 : {
183 2 : TRACE1 (ctx, ASSUAN_LOG_SYSIO, "_assuan_close_inheritable", ctx,
184 : "fd=0x%x", fd);
185 :
186 : #ifdef HAVE_W32CE_SYSTEM
187 : return 0; /* Nothing to do because it is a rendezvous id. */
188 : #else
189 2 : return (ctx->system.close) (ctx, fd);
190 : #endif
191 : }
192 :
193 :
194 :
195 : ssize_t
196 6 : _assuan_read (assuan_context_t ctx, assuan_fd_t fd, void *buffer, size_t size)
197 : {
198 : #if DEBUG_SYSIO
199 : ssize_t res;
200 : TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_read", ctx,
201 : "fd=0x%x, buffer=%p, size=%i", fd, buffer, size);
202 : res = (ctx->system.read) (ctx, fd, buffer, size);
203 : return TRACE_SYSRES (res);
204 : #else
205 6 : return (ctx->system.read) (ctx, fd, buffer, size);
206 : #endif
207 : }
208 :
209 :
210 :
211 : ssize_t
212 12 : _assuan_write (assuan_context_t ctx, assuan_fd_t fd, const void *buffer,
213 : size_t size)
214 : {
215 : #if DEBUG_SYSIO
216 : ssize_t res;
217 : TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_write", ctx,
218 : "fd=0x%x, buffer=%p, size=%i", fd, buffer, size);
219 : res = (ctx->system.write) (ctx, fd, buffer, size);
220 : return TRACE_SYSRES (res);
221 : #else
222 12 : return (ctx->system.write) (ctx, fd, buffer, size);
223 : #endif
224 : }
225 :
226 :
227 :
228 : int
229 32 : _assuan_recvmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
230 : int flags)
231 : {
232 : #if DEBUG_SYSIO
233 : ssize_t res;
234 : TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_recvmsg", ctx,
235 : "fd=0x%x, msg=%p, flags=0x%x", fd, msg, flags);
236 : res = (ctx->system.recvmsg) (ctx, fd, msg, flags);
237 : if (res > 0)
238 : {
239 : struct cmsghdr *cmptr;
240 :
241 : TRACE_LOG2 ("msg->msg_iov[0] = { iov_base=%p, iov_len=%i }",
242 : msg->msg_iov[0].iov_base, msg->msg_iov[0].iov_len);
243 : TRACE_LOGBUF (msg->msg_iov[0].iov_base, res);
244 :
245 : cmptr = CMSG_FIRSTHDR (msg);
246 : if (cmptr)
247 : {
248 : void *data = CMSG_DATA (cmptr);
249 : TRACE_LOG5 ("cmsg_len=0x%x (0x%x data), cmsg_level=0x%x, "
250 : "cmsg_type=0x%x, first data int=0x%x", cmptr->cmsg_len,
251 : cmptr->cmsg_len - (((char *)data) - ((char *)cmptr)),
252 : cmptr->cmsg_level, cmptr->cmsg_type, *(int *)data);
253 : }
254 : }
255 : return TRACE_SYSRES (res);
256 : #else
257 32 : return (ctx->system.recvmsg) (ctx, fd, msg, flags);
258 : #endif
259 : }
260 :
261 :
262 :
263 : int
264 59 : _assuan_sendmsg (assuan_context_t ctx, assuan_fd_t fd, assuan_msghdr_t msg,
265 : int flags)
266 : {
267 : #if DEBUG_SYSIO
268 : ssize_t res;
269 : TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_sendmsg", ctx,
270 : "fd=0x%x, msg=%p, flags=0x%x", fd, msg, flags);
271 : {
272 : struct cmsghdr *cmptr;
273 :
274 : TRACE_LOG2 ("msg->iov[0] = { iov_base=%p, iov_len=%i }",
275 : msg->msg_iov[0].iov_base, msg->msg_iov[0].iov_len);
276 : TRACE_LOGBUF (msg->msg_iov[0].iov_base, msg->msg_iov[0].iov_len);
277 :
278 : cmptr = CMSG_FIRSTHDR (msg);
279 : if (cmptr)
280 : {
281 : void *data = CMSG_DATA (cmptr);
282 : TRACE_LOG5 ("cmsg_len=0x%x (0x%x data), cmsg_level=0x%x, "
283 : "cmsg_type=0x%x, first data int=0x%x", cmptr->cmsg_len,
284 : cmptr->cmsg_len - (((char *)data) - ((char *)cmptr)),
285 : cmptr->cmsg_level, cmptr->cmsg_type, *(int *)data);
286 : }
287 : }
288 : res = (ctx->system.sendmsg) (ctx, fd, msg, flags);
289 : return TRACE_SYSRES (res);
290 : #else
291 59 : return (ctx->system.sendmsg) (ctx, fd, msg, flags);
292 : #endif
293 : }
294 :
295 :
296 :
297 : /* Create a new process from NAME and ARGV. Provide FD_IN and FD_OUT
298 : as stdin and stdout. Inherit the ASSUAN_INVALID_FD-terminated
299 : FD_CHILD_LIST as given (no remapping), which must be inheritable.
300 : On Unix, call ATFORK with ATFORKVALUE after fork and before exec. */
301 : int
302 2 : _assuan_spawn (assuan_context_t ctx, pid_t *r_pid, const char *name,
303 : const char **argv,
304 : assuan_fd_t fd_in, assuan_fd_t fd_out,
305 : assuan_fd_t *fd_child_list,
306 : void (*atfork) (void *opaque, int reserved),
307 : void *atforkvalue, unsigned int flags)
308 : {
309 : int res;
310 : int i;
311 2 : TRACE_BEG6 (ctx, ASSUAN_LOG_CTX, "_assuan_spawn", ctx,
312 : "name=%s,fd_in=0x%x,fd_out=0x%x,"
313 : "atfork=%p,atforkvalue=%p,flags=%i",
314 : name ? name : "(null)", fd_in, fd_out,
315 : atfork, atforkvalue, flags);
316 :
317 2 : if (name)
318 : {
319 1 : i = 0;
320 4 : while (argv[i])
321 : {
322 2 : TRACE_LOG2 ("argv[%2i] = %s", i, argv[i]);
323 2 : i++;
324 : }
325 : }
326 2 : i = 0;
327 2 : if (fd_child_list)
328 : {
329 7 : while (fd_child_list[i] != ASSUAN_INVALID_FD)
330 : {
331 3 : TRACE_LOG2 ("fd_child_list[%2i] = 0x%x", i, fd_child_list[i]);
332 3 : i++;
333 : }
334 : }
335 :
336 2 : res = (ctx->system.spawn) (ctx, r_pid, name, argv, fd_in, fd_out,
337 : fd_child_list, atfork, atforkvalue, flags);
338 :
339 3 : if (name)
340 : {
341 1 : TRACE_LOG1 ("pid = 0x%x", *r_pid);
342 : }
343 : else
344 : {
345 2 : TRACE_LOG2 ("pid = 0x%x (%s)", *r_pid, *argv);
346 : }
347 :
348 3 : return TRACE_SYSERR (res);
349 : }
350 :
351 :
352 :
353 : /* FIXME: Add some sort of waitpid function that covers GPGME and
354 : gpg-agent's use of assuan. */
355 : pid_t
356 3 : _assuan_waitpid (assuan_context_t ctx, pid_t pid, int action,
357 : int *status, int options)
358 : {
359 : #if DEBUG_SYSIO
360 : ssize_t res;
361 : TRACE_BEG4 (ctx, ASSUAN_LOG_SYSIO, "_assuan_waitpid", ctx,
362 : "pid=%i, action=%i, status=%p, options=%i",
363 : pid, action, status, options);
364 : res = (ctx->system.waitpid) (ctx, pid, action, status, options);
365 : return TRACE_SYSRES (res);
366 : #else
367 3 : return (ctx->system.waitpid) (ctx, pid, action, status, options);
368 : #endif
369 : }
370 :
371 :
372 :
373 : int
374 1 : _assuan_socketpair (assuan_context_t ctx, int namespace, int style,
375 : int protocol, assuan_fd_t filedes[2])
376 : {
377 : int res;
378 1 : TRACE_BEG4 (ctx, ASSUAN_LOG_SYSIO, "_assuan_socketpair", ctx,
379 : "namespace=%i,style=%i,protocol=%i,filedes=%p",
380 : namespace, style, protocol, filedes);
381 :
382 1 : res = (ctx->system.socketpair) (ctx, namespace, style, protocol, filedes);
383 1 : if (res == 0)
384 1 : TRACE_LOG2 ("filedes = { 0x%x, 0x%x }", filedes[0], filedes[1]);
385 :
386 1 : return TRACE_SYSERR (res);
387 : }
388 :
389 :
390 :
391 : int
392 0 : _assuan_socket (assuan_context_t ctx, int namespace, int style, int protocol)
393 : {
394 : int res;
395 0 : TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_socket", ctx,
396 : "namespace=%i,style=%i,protocol=%i",
397 : namespace, style, protocol);
398 :
399 0 : res = (ctx->system.socket) (ctx, namespace, style, protocol);
400 0 : return TRACE_SYSRES (res);
401 : }
402 :
403 :
404 : int
405 0 : _assuan_connect (assuan_context_t ctx, int sock, struct sockaddr *addr, socklen_t length)
406 : {
407 : int res;
408 0 : TRACE_BEG3 (ctx, ASSUAN_LOG_SYSIO, "_assuan_connect", ctx,
409 : "socket=%i,addr=%p,length=%i", sock, addr, length);
410 :
411 0 : res = (ctx->system.connect) (ctx, sock, addr, length);
412 0 : return TRACE_SYSRES (res);
413 : }
414 :
|