1 /* runner.c - Run and watch the backend engines
2 * Copyright (C) 2009 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
6 * GnuPG is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * GnuPG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
33 #include "../common/exechelp.h"
36 /* The runner object. */
39 char *name
; /* The name of this runner. */
41 int spawned
; /* True if runner_spawn has been called. */
42 pth_t threadid
; /* The TID of the runner thread. */
43 runner_t next_running
; /* Builds a list of all running threads. */
44 int canceled
; /* Set if a cancel has already been send once. */
46 int cancel_flag
; /* If set the thread should terminate itself. */
49 /* We use a reference counter to know when it is safe to remove the
50 object. Lackiong an explicit ref fucntion this counter will take
51 only these two values:
53 1 = Thread not running or only the thread is still running.
54 2 = Thread is running and someone is holding a reference. */
57 pid_t pid
; /* PID of the backend's process (the engine). */
58 int in_fd
; /* File descriptors to read from the engine. */
59 int out_fd
; /* File descriptors to write to the engine. */
60 engine_handler_fnc_t handler
; /* The handler functions. */
61 engine_handler_cleanup_fnc_t handler_cleanup
;
62 void *handler_data
; /* Private data of HANDLER and HANDLER_CLEANUP. */
64 /* Instead of IN_FD we use an estream. Note that the runner thread
65 may close the stream and set status_fp to NULL at any time. Thus
66 it won't be a good idea to use it while the runner thread is
72 /* The head of the list of all running threads. */
73 static runner_t running_threads
;
78 /* Write NBYTES of BUF to file descriptor FD. */
80 writen (int fd
, const void *buf
, size_t nbytes
)
82 size_t nleft
= nbytes
;
87 nwritten
= pth_write (fd
, buf
, nleft
);
96 buf
= (const char*)buf
+ nwritten
;
104 check_already_spawned (runner_t runner
, const char *funcname
)
108 log_error ("BUG: runner already spawned - ignoring call to %s\n",
117 /* Return the number of active threads. */
119 runner_get_threads (void)
124 for (r
= running_threads
; r
; r
= r
->next_running
)
130 /* The public release function. */
132 runner_release (runner_t runner
)
137 if (!--runner
->refcount
)
140 es_fclose (runner
->status_fp
);
141 if (runner
->in_fd
!= -1)
142 close (runner
->in_fd
);
143 if (runner
->out_fd
!= -1)
144 close (runner
->out_fd
);
146 /* Fixme: close the process. */
148 /* Tell the engine to release its data. */
149 if (runner
->handler_cleanup
)
150 runner
->handler_cleanup (runner
->handler_data
);
152 if (runner
->pid
!= (pid_t
)(-1))
154 /* The process has not been cleaned up - do it now. */
155 gnupg_kill_process (runner
->pid
);
156 /* (Actually we should use the program name and not the
157 arbitrary NAME of the runner object. However it does not
158 matter because that information is only used for
160 gnupg_wait_process (runner
->name
, runner
->pid
, NULL
);
163 xfree (runner
->name
);
168 /* Create a new runner context. On success a new runner object is
169 stored at R_RUNNER. On failure NULL is stored at this address and
170 an error code returned. */
172 runner_new (runner_t
*r_runner
, const char *name
)
178 runner
= xtrycalloc (1, sizeof *runner
);
180 return gpg_error_from_syserror ();
181 runner
->name
= xtrystrdup (name
? name
: "[unknown]");
185 return gpg_error_from_syserror ();
187 runner
->refcount
= 1;
188 runner
->pid
= (pid_t
)(-1);
198 /* A runner usually maintaines two file descriptors to control the
199 backend engine. This function is used to set these file
200 descriptors. The function takes ownership of these file
201 descriptors. IN_FD will be used to read from engine and OUT_FD to
202 send data to the engine. */
204 runner_set_fds (runner_t runner
, int in_fd
, int out_fd
)
206 if (check_already_spawned (runner
, "runner_set_fds"))
209 if (runner
->in_fd
!= -1)
210 close (runner
->in_fd
);
211 if (runner
->out_fd
!= -1)
212 close (runner
->out_fd
);
213 runner
->in_fd
= in_fd
;
214 runner
->out_fd
= out_fd
;
218 /* Set the PID of the backend engine. After this call the engine is
219 owned by the runner object. */
221 runner_set_pid (runner_t runner
, pid_t pid
)
223 if (check_already_spawned (runner
, "runner_set_fds"))
230 /* Register the engine handler fucntions HANDLER and HANDLER_CLEANUP
231 and its private HANDLER_DATA with RUNNER. */
233 runner_set_handler (runner_t runner
,
234 engine_handler_fnc_t handler
,
235 engine_handler_cleanup_fnc_t handler_cleanup
,
238 if (check_already_spawned (runner
, "runner_set_handler"))
241 runner
->handler
= handler
;
242 runner
->handler_cleanup
= handler_cleanup
;
243 runner
->handler_data
= handler_data
;
247 /* The thread spawned by runner_spawn. */
249 runner_thread (void *arg
)
251 runner_t runner
= arg
;
254 log_debug ("starting runner thread\n");
255 /* If a status_fp is available, the thread's main task is to read
256 from that stream and invoke the backend's handler function. This
257 is done on a line by line base and the line length is limited to
258 a reasonable value (about 1000 characters). Other work will
259 continue either due to an EOF of the stream or by demand of the
261 if (runner
->status_fp
)
266 estream_t fp
= runner
->status_fp
;
270 while (!err
&& !runner
->cancel_flag
&& (c
=es_getc (fp
)) != EOF
)
273 if (pos
>= sizeof buffer
- 5 || c
== '\n')
275 buffer
[pos
- (c
== '\n')] = 0;
277 log_info ("%s%s: %s\n",
278 runner
->name
, cont_line
? "(cont)":"", buffer
);
279 /* We handle only complete lines and ignore any stuff we
280 possibly had to truncate. That is - at least for the
281 encfs engine - not an issue because our changes to
282 the tool make sure that only relatively short prompt
283 lines are of interest. */
284 if (!cont_line
&& runner
->handler
)
285 err
= runner
->handler (runner
->handler_data
,
288 cont_line
= (c
!= '\n');
291 if (!err
&& runner
->cancel_flag
)
292 log_debug ("runner thread noticed cancel flag\n");
294 log_debug ("runner thread saw EOF\n");
299 log_info ("%s%s: %s\n",
300 runner
->name
, cont_line
? "(cont)":"", buffer
);
301 if (!cont_line
&& !err
&& runner
->handler
)
302 err
= runner
->handler (runner
->handler_data
,
305 if (!err
&& es_ferror (fp
))
307 err
= gpg_error_from_syserror ();
308 log_error ("error reading from %s: %s\n",
309 runner
->name
, gpg_strerror (err
));
312 runner
->status_fp
= NULL
;
314 log_debug ("runner thread closed status fp\n");
317 /* Now wait for the process to finish. */
318 if (!err
&& runner
->pid
!= (pid_t
)(-1))
322 log_debug ("runner thread waiting ...\n");
323 err
= gnupg_wait_process (runner
->name
, runner
->pid
, &exitcode
);
324 runner
->pid
= (pid_t
)(-1);
326 log_error ("running `%s' failed (exitcode=%d): %s\n",
327 runner
->name
, exitcode
, gpg_strerror (err
));
328 log_debug ("runner thread waiting finished\n");
331 /* Get rid of the runner object (note: it is refcounted). */
332 log_debug ("runner thread releasing runner ...\n");
336 for (r
= running_threads
, rprev
= NULL
; r
; rprev
= r
, r
= r
->next_running
)
340 running_threads
= r
->next_running
;
342 rprev
->next_running
= r
->next_running
;
343 r
->next_running
= NULL
;
347 runner_release (runner
);
348 log_debug ("runner thread runner released\n");
354 /* Spawn a new thread to let RUNNER work as a coprocess. */
356 runner_spawn (runner_t runner
)
362 if (check_already_spawned (runner
, "runner_spawn"))
363 return gpg_error (GPG_ERR_BUG
);
365 /* In case we have an input fd, open it as an estream so that the
366 Pth scheduling will work. The stdio functions don't work with
367 Pth because they don't call the pth counterparts of read and
368 write unless linker tricks are used. */
369 if (runner
->in_fd
!= -1)
373 fp
= es_fdopen (runner
->in_fd
, "r");
376 err
= gpg_error_from_syserror ();
377 log_error ("can't fdopen pipe for reading: %s\n", gpg_strerror (err
));
380 runner
->status_fp
= fp
;
381 runner
->in_fd
= -1; /* Now owned by status_fp. */
384 tattr
= pth_attr_new ();
385 pth_attr_set (tattr
, PTH_ATTR_JOINABLE
, 1);
386 pth_attr_set (tattr
, PTH_ATTR_STACK_SIZE
, 256*1024);
387 pth_attr_set (tattr
, PTH_ATTR_NAME
, runner
->name
);
389 tid
= pth_spawn (tattr
, runner_thread
, runner
);
392 err
= gpg_error_from_syserror ();
393 log_error ("error spawning runner thread: %s\n", gpg_strerror (err
));
396 /* The scheduler has not yet kicked in, thus we can safely set the
397 spawned flag and the tid. */
399 runner
->threadid
= tid
;
400 runner
->next_running
= running_threads
;
401 running_threads
= runner
;
403 pth_attr_destroy (tattr
);
405 /* The runner thread is now runnable. */
411 /* Cancel a running thread. */
413 runner_cancel (runner_t runner
)
415 /* Warning: runner_cancel_all has knowledge of this code. */
418 runner
->canceled
= 1; /* Mark that we canceled this one already. */
419 /* FIXME: This does only work if the thread emits status lines. We
420 need to change the trhead to wait on an event. */
421 runner
->cancel_flag
= 1;
422 /* For now we use the brutal way and kill the process. */
423 gnupg_kill_process (runner
->pid
);
428 /* Cancel all runner threads. */
430 runner_cancel_all (void)
436 for (r
= running_threads
; r
; r
= r
->next_running
)
437 if (r
->spawned
&& !r
->canceled
)
447 /* Send a line of data down to the engine. This line may not contain
448 a binary Nul or a LF character. This function is used by the
451 runner_send_line (runner_t runner
, const void *data
, size_t datalen
)
455 if (!runner
->spawned
)
457 log_error ("BUG: runner for %s not spawned\n", runner
->name
);
458 err
= gpg_error (GPG_ERR_INTERNAL
);
460 else if (runner
->out_fd
== -1)
462 log_error ("no output file descriptor for runner %s\n", runner
->name
);
463 err
= gpg_error (GPG_ERR_EBADF
);
465 else if (data
&& datalen
)
467 if (memchr (data
, '\n', datalen
))
469 log_error ("LF detected in response data\n");
470 err
= gpg_error (GPG_ERR_BUG
);
472 else if (memchr (data
, 0, datalen
))
474 log_error ("Nul detected in response data\n");
475 err
= gpg_error (GPG_ERR_BUG
);
477 else if (writen (runner
->out_fd
, data
, datalen
))
478 err
= gpg_error_from_syserror ();
482 if (writen (runner
->out_fd
, "\n", 1))
483 err
= gpg_error_from_syserror ();