1 /* g13.c - Disk Key management with GnuPG
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/>.
37 #include "gc-opt-flags.h"
43 #include "mountinfo.h"
46 enum cmd_and_opt_values
{
101 static ARGPARSE_OPTS opts
[] = {
103 ARGPARSE_group (300, N_("@Commands:\n ")),
105 ARGPARSE_c (aCreate
, "create", N_("Create a new file system container")),
106 ARGPARSE_c (aMount
, "mount", N_("Mount a file system container") ),
107 ARGPARSE_c (aUmount
, "umount", N_("Unmount a file system container") ),
108 ARGPARSE_c (aServer
, "server", N_("Run in server mode")),
110 ARGPARSE_c (aGPGConfList
, "gpgconf-list", "@"),
111 ARGPARSE_c (aGPGConfTest
, "gpgconf-test", "@"),
113 ARGPARSE_group (301, N_("@\nOptions:\n ")),
115 ARGPARSE_s_s (oRecipient
, "recipient", N_("|USER-ID|encrypt for USER-ID")),
117 ARGPARSE_s_s (oOutput
, "output", N_("|FILE|write output to FILE")),
118 ARGPARSE_s_n (oVerbose
, "verbose", N_("verbose")),
119 ARGPARSE_s_n (oQuiet
, "quiet", N_("be somewhat more quiet")),
120 ARGPARSE_s_n (oNoTTY
, "no-tty", N_("don't use the terminal at all")),
121 ARGPARSE_s_n (oNoDetach
, "no-detach", N_("do not detach from the console")),
122 ARGPARSE_s_s (oLogFile
, "log-file", N_("|FILE|write log output to FILE")),
123 ARGPARSE_s_n (oNoLogFile
, "no-log-file", "@"),
124 ARGPARSE_s_i (oLoggerFD
, "logger-fd", "@"),
126 ARGPARSE_s_s (oAuditLog
, "audit-log",
127 N_("|FILE|write an audit log to FILE")),
128 ARGPARSE_s_n (oDryRun
, "dry-run", N_("do not make any changes")),
130 ARGPARSE_s_s (oOptions
, "options", N_("|FILE|read options from FILE")),
132 ARGPARSE_p_u (oDebug
, "debug", "@"),
133 ARGPARSE_s_s (oDebugLevel
, "debug-level",
134 N_("|LEVEL|set the debugging level to LEVEL")),
135 ARGPARSE_s_n (oDebugAll
, "debug-all", "@"),
136 ARGPARSE_s_n (oDebugNone
, "debug-none", "@"),
137 ARGPARSE_s_i (oDebugWait
, "debug-wait", "@"),
138 ARGPARSE_s_n (oDebugAllowCoreDump
, "debug-allow-core-dump", "@"),
140 ARGPARSE_s_i (oStatusFD
, "status-fd",
141 N_("|FD|write status info to this FD")),
143 ARGPARSE_group (302, N_(
144 "@\n(See the man page for a complete listing of all commands and options)\n"
147 ARGPARSE_group (303, N_("@\nExamples:\n\n"
151 /* Hidden options. */
152 ARGPARSE_s_n (oNoVerbose
, "no-verbose", "@"),
153 ARGPARSE_s_n (oNoSecmemWarn
, "no-secmem-warning", "@"),
154 ARGPARSE_s_n (oNoGreeting
, "no-greeting", "@"),
155 ARGPARSE_s_n (oNoOptions
, "no-options", "@"),
156 ARGPARSE_s_s (oHomedir
, "homedir", "@"),
157 ARGPARSE_s_s (oAgentProgram
, "agent-program", "@"),
158 ARGPARSE_s_s (oGpgProgram
, "gpg-program", "@"),
159 ARGPARSE_s_s (oDisplay
, "display", "@"),
160 ARGPARSE_s_s (oTTYname
, "ttyname", "@"),
161 ARGPARSE_s_s (oTTYtype
, "ttytype", "@"),
162 ARGPARSE_s_s (oLCctype
, "lc-ctype", "@"),
163 ARGPARSE_s_s (oLCmessages
, "lc-messages", "@"),
164 ARGPARSE_s_s (oXauthority
, "xauthority", "@"),
165 ARGPARSE_s_s (oFakedSystemTime
, "faked-system-time", "@"),
166 ARGPARSE_s_n (oWithColons
, "with-colons", "@"),
167 ARGPARSE_s_n (oNoRandomSeedFile
, "no-random-seed-file", "@"),
169 /* Command aliases. */
175 /* The timer tick interval used by the idle task. */
176 #define TIMERTICK_INTERVAL_SEC (1)
179 /* Global variable to keep an error count. */
180 int g13_errors_seen
= 0;
182 /* It is possible that we are currently running under setuid permissions. */
183 static int maybe_setuid
= 1;
185 /* Helper to implement --debug-level and --debug. */
186 static const char *debug_level
;
187 static unsigned int debug_value
;
189 /* Flag to indicate that a shutdown was requested. */
190 static int shutdown_pending
;
192 /* The thread id of the idle task. */
193 static pth_t idle_task_tid
;
197 static void set_cmd (enum cmd_and_opt_values
*ret_cmd
,
198 enum cmd_and_opt_values new_cmd
);
200 static void emergency_cleanup (void);
201 static void start_idle_task (void);
202 static void join_idle_task (void);
206 /* Begin Pth wrapper functions. */
207 ASSUAN_SYSTEM_PTH_IMPL
;
209 GCRY_THREAD_OPTION_PTH_IMPL
;
210 static int fixed_gcry_pth_init (void)
212 return pth_self ()? 0 : (pth_init () == FALSE
) ? errno
: 0;
214 /* End Pth wrapper functions. */
218 my_strusage( int level
)
224 case 11: p
= "g13 (GnuPG)";
226 case 13: p
= VERSION
; break;
227 case 17: p
= PRINTABLE_OS_NAME
; break;
228 case 19: p
= _("Please report bugs to <" PACKAGE_BUGREPORT
">.\n");
231 case 40: p
= _("Usage: g13 [options] [files] (-h for help)");
234 p
= _("Syntax: g13 [options] [files]\n"
235 "Create, mount or unmount an encrypted file system container\n");
238 case 31: p
= "\nHome: "; break;
239 case 32: p
= opt
.homedir
; break;
241 default: p
= NULL
; break;
248 wrong_args (const char *text
)
250 fputs (_("usage: g13 [options] "), stderr
);
251 fputs (text
, stderr
);
257 /* Setup the debugging. With a DEBUG_LEVEL of NULL only the active
258 debug flags are propagated to the subsystems. With DEBUG_LEVEL
259 set, a specific set of debug flags is set; and individual debugging
260 flags will be added on top. */
266 else if (!strcmp (debug_level
, "none"))
268 else if (!strcmp (debug_level
, "basic"))
269 opt
.debug
= DBG_ASSUAN_VALUE
|DBG_MOUNT_VALUE
;
270 else if (!strcmp (debug_level
, "advanced"))
271 opt
.debug
= DBG_ASSUAN_VALUE
|DBG_MOUNT_VALUE
;
272 else if (!strcmp (debug_level
, "expert"))
273 opt
.debug
= (DBG_ASSUAN_VALUE
|DBG_MOUNT_VALUE
|DBG_CRYPTO_VALUE
);
274 else if (!strcmp (debug_level
, "guru"))
278 log_error (_("invalid debug-level `%s' given\n"), debug_level
);
282 opt
.debug
|= debug_value
;
284 if (opt
.debug
&& !opt
.verbose
)
289 if (opt
.debug
& DBG_CRYPTO_VALUE
)
290 gcry_control (GCRYCTL_SET_DEBUG_FLAGS
, 1);
291 gcry_control (GCRYCTL_SET_VERBOSITY
, (int)opt
.verbose
);
297 set_cmd (enum cmd_and_opt_values
*ret_cmd
, enum cmd_and_opt_values new_cmd
)
299 enum cmd_and_opt_values cmd
= *ret_cmd
;
301 if (!cmd
|| cmd
== new_cmd
)
305 log_error (_("conflicting commands\n"));
313 /* Helper to add recipients to a list. */
315 add_encryption_key (ctrl_t ctrl
, const char *name
,
316 void /*FIXME*/ *keylist
, int is_cms
)
318 /* FIXME: Decide whether to add a CMS or OpenPGP key and then add
319 the key to a list. */
320 /* int rc = foo_add_to_certlist (ctrl, name, 0, recplist, is_encrypt_to); */
323 /* if (recp_required) */
325 /* log_error ("can't encrypt to `%s': %s\n", name, gpg_strerror (rc)); */
326 /* gpgsm_status2 (ctrl, STATUS_INV_RECP, */
327 /* get_inv_recpsgnr_code (rc), name, NULL); */
330 /* log_info (_("NOTE: won't be able to encrypt to `%s': %s\n"), */
331 /* name, gpg_strerror (rc)); */
333 return 0; /* Key is good. */
338 main ( int argc
, char **argv
)
346 FILE *configfp
= NULL
;
347 char *configname
= NULL
;
348 unsigned configlineno
;
350 int no_more_options
= 0;
351 int default_config
=1;
352 char *logfile
= NULL
;
353 char *auditlog
= NULL
;
357 int use_random_seed
= 1;
360 enum cmd_and_opt_values cmd
= 0;
361 struct server_control_s ctrl
;
362 estream_t auditfp
= NULL
;
363 strlist_t recipients
= NULL
;
367 gnupg_reopen_std ("g13");
368 set_strusage (my_strusage
);
369 gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN
);
371 log_set_prefix ("g13", 1);
373 /* Make sure that our subsystems are ready. */
375 init_common_subsystems ();
377 /* Libgcrypt requires us to register the threading model first.
378 Note that this will also do the pth_init. */
379 gcry_threads_pth
.init
= fixed_gcry_pth_init
;
380 err
= gcry_control (GCRYCTL_SET_THREAD_CBS
, &gcry_threads_pth
);
383 log_fatal ("can't register GNU Pth with Libgcrypt: %s\n",
387 /* Check that the Libgcrypt is suitable. */
388 if (!gcry_check_version (NEED_LIBGCRYPT_VERSION
) )
389 log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt",
390 NEED_LIBGCRYPT_VERSION
, gcry_check_version (NULL
) );
392 /* Take extra care of the random pool. */
393 gcry_control (GCRYCTL_USE_SECURE_RNDPOOL
);
395 may_coredump
= disable_core_dumps ();
397 gnupg_init_signals (0, emergency_cleanup
);
399 create_dotlock (NULL
); /* Register locking cleanup. */
401 opt
.homedir
= default_homedir ();
403 /* First check whether we have a config file on the commandline. */
408 pargs
.flags
= 1|(1<<6); /* Do not remove the args, ignore version. */
409 while (arg_parse( &pargs
, opts
))
411 if (pargs
.r_opt
== oDebug
|| pargs
.r_opt
== oDebugAll
)
413 else if (pargs
.r_opt
== oOptions
)
414 { /* Yes, there is one, so we do not try the default one but
415 read the config file when it is encountered at the
419 else if (pargs
.r_opt
== oNoOptions
)
420 default_config
= 0; /* --no-options */
421 else if (pargs
.r_opt
== oHomedir
)
422 opt
.homedir
= pargs
.r
.ret_str
;
425 /* Initialize the secure memory. */
426 gcry_control (GCRYCTL_INIT_SECMEM
, 16384, 0);
430 Now we are now working under our real uid
433 /* Setup malloc hooks. */
435 struct assuan_malloc_hooks malloc_hooks
;
437 malloc_hooks
.malloc
= gcry_malloc
;
438 malloc_hooks
.realloc
= gcry_realloc
;
439 malloc_hooks
.free
= gcry_free
;
440 assuan_set_malloc_hooks (&malloc_hooks
);
443 /* Prepare libassuan. */
444 assuan_set_assuan_log_prefix (log_get_prefix (NULL
));
445 assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT
);
446 assuan_set_system_hooks (ASSUAN_SYSTEM_PTH
);
449 /* Setup a default control structure for command line mode. */
450 memset (&ctrl
, 0, sizeof ctrl
);
451 g13_init_default_ctrl (&ctrl
);
453 /* Set the default option file */
455 configname
= make_filename (opt
.homedir
, "g13.conf", NULL
);
461 pargs
.flags
= 1; /* Do not remove the args. */
467 configfp
= fopen (configname
, "r");
473 log_info (_("NOTE: no default option file `%s'\n"), configname
);
477 log_error (_("option file `%s': %s\n"),
478 configname
, strerror(errno
));
484 if (parse_debug
&& configname
)
485 log_info (_("reading options from `%s'\n"), configname
);
489 while (!no_more_options
490 && optfile_parse (configfp
, configname
, &configlineno
, &pargs
, opts
))
496 set_cmd (&cmd
, pargs
.r_opt
);
506 set_cmd (&cmd
, pargs
.r_opt
);
509 case oOutput
: opt
.outfile
= pargs
.r
.ret_str
; break;
511 case oQuiet
: opt
.quiet
= 1; break;
512 case oNoGreeting
: nogreeting
= 1; break;
515 case oDryRun
: opt
.dry_run
= 1; break;
519 gcry_control (GCRYCTL_SET_VERBOSITY
, (int)opt
.verbose
);
523 gcry_control (GCRYCTL_SET_VERBOSITY
, (int)opt
.verbose
);
526 case oLogFile
: logfile
= pargs
.r
.ret_str
; break;
527 case oNoLogFile
: logfile
= NULL
; break;
529 case oAuditLog
: auditlog
= pargs
.r
.ret_str
; break;
531 case oNoDetach
: nodetach
= 1; break;
533 case oDebug
: debug_value
|= pargs
.r
.ret_ulong
; break;
534 case oDebugAll
: debug_value
= ~0; break;
535 case oDebugNone
: debug_value
= 0; break;
536 case oDebugLevel
: debug_level
= pargs
.r
.ret_str
; break;
537 case oDebugWait
: debug_wait
= pargs
.r
.ret_int
; break;
538 case oDebugAllowCoreDump
:
539 may_coredump
= enable_core_dumps ();
542 case oStatusFD
: ctrl
.status_fd
= pargs
.r
.ret_int
; break;
543 case oLoggerFD
: log_set_fd (pargs
.r
.ret_int
); break;
545 case oNoOptions
: break; /* no-options */
547 /* Config files may not be nested (silently ignore them). */
551 configname
= xstrdup (pargs
.r
.ret_str
);
556 case oHomedir
: opt
.homedir
= pargs
.r
.ret_str
; break;
558 case oAgentProgram
: opt
.agent_program
= pargs
.r
.ret_str
; break;
559 case oGpgProgram
: opt
.gpg_program
= pargs
.r
.ret_str
; break;
560 case oDisplay
: opt
.display
= xstrdup (pargs
.r
.ret_str
); break;
561 case oTTYname
: opt
.ttyname
= xstrdup (pargs
.r
.ret_str
); break;
562 case oTTYtype
: opt
.ttytype
= xstrdup (pargs
.r
.ret_str
); break;
563 case oLCctype
: opt
.lc_ctype
= xstrdup (pargs
.r
.ret_str
); break;
564 case oLCmessages
: opt
.lc_messages
= xstrdup (pargs
.r
.ret_str
); break;
565 case oXauthority
: opt
.xauthority
= xstrdup (pargs
.r
.ret_str
); break;
567 case oFakedSystemTime
:
569 time_t faked_time
= isotime2epoch (pargs
.r
.ret_str
);
570 if (faked_time
== (time_t)(-1))
571 faked_time
= (time_t)strtoul (pargs
.r
.ret_str
, NULL
, 10);
572 gnupg_set_time (faked_time
, 0);
576 case oNoSecmemWarn
: gcry_control (GCRYCTL_DISABLE_SECMEM_WARN
); break;
578 case oNoRandomSeedFile
: use_random_seed
= 0; break;
580 case oRecipient
: /* Store the encryption key. */
581 add_to_strlist (&recipients
, pargs
.r
.ret_str
);
586 pargs
.err
= configfp
? ARGPARSE_PRINT_WARNING
:ARGPARSE_PRINT_ERROR
;
595 /* Keep a copy of the config filename. */
596 opt
.config_filename
= configname
;
603 if (!opt
.config_filename
)
604 opt
.config_filename
= make_filename (opt
.homedir
, "g13.conf", NULL
);
606 if (log_get_errorcount(0))
609 /* Now that we have the options parsed we need to update the default
610 control structure. */
611 g13_init_default_ctrl (&ctrl
);
618 fprintf (stderr
, "%s %s; %s\n",
619 strusage(11), strusage(13), strusage(14) );
620 fprintf (stderr
, "%s\n", strusage(15) );
623 if (may_coredump
&& !opt
.quiet
)
624 log_info (_("WARNING: program may create a core file!\n"));
628 log_set_file (logfile
);
629 log_set_prefix (NULL
, 1|2|4);
632 if (gnupg_faked_time_p ())
634 gnupg_isotime_t tbuf
;
636 log_info (_("WARNING: running with faked system time: "));
637 gnupg_get_isotime (tbuf
);
642 /* Print any pending secure memory warnings. */
643 gcry_control (GCRYCTL_RESUME_SECMEM_WARN
);
645 /* Setup the debug flags for all subsystems. */
648 /* Install a regular exit handler to make real sure that the secure
649 memory gets wiped out. */
650 if (atexit (emergency_cleanup
))
652 log_error ("atexit failed\n");
656 /* Terminate if we found any error until now. */
657 if (log_get_errorcount(0))
660 /* Set the standard GnuPG random seed file. */
663 char *p
= make_filename (opt
.homedir
, "random_seed", NULL
);
664 gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE
, p
);
668 /* Store given filename into FNAME. */
669 fname
= argc
? *argv
: NULL
;
671 /* Parse all given encryption keys. This does a lookup of the keys
672 and stops if any of the given keys was not found. */
678 for (sl
= recipients
; sl
; sl
= sl
->next
)
679 if (add_encryption_key (&ctrl
, sl
->d
, NULL
/* FIXME*/, 0))
685 /* Dispatch command. */
689 { /* List options and default values in the GPG Conf format. */
690 char *config_filename_esc
= percent_escape (opt
.config_filename
, NULL
);
692 printf ("gpgconf-g13.conf:%lu:\"%s\n",
693 GC_OPT_FLAG_DEFAULT
, config_filename_esc
);
694 xfree (config_filename_esc
);
696 printf ("verbose:%lu:\n", GC_OPT_FLAG_NONE
);
697 printf ("quiet:%lu:\n", GC_OPT_FLAG_NONE
);
698 printf ("debug-level:%lu:\"none:\n", GC_OPT_FLAG_DEFAULT
);
699 printf ("log-file:%lu:\n", GC_OPT_FLAG_NONE
);
703 /* This is merely a dummy command to test whether the
704 configuration file is valid. */
710 err
= g13_server (&ctrl
);
712 log_error ("server exited with error: %s <%s>\n",
713 gpg_strerror (err
), gpg_strsource (err
));
719 case aCreate
: /* Create a new container. */
722 wrong_args ("--create filename");
724 err
= g13_create_container (&ctrl
, argv
[0]);
726 log_error ("error creating a new container: %s <%s>\n",
727 gpg_strerror (err
), gpg_strsource (err
));
733 case aMount
: /* Mount a container. */
735 if (argc
!= 1 && argc
!= 2 )
736 wrong_args ("--mount filename [mountpoint]");
738 err
= g13_mount_container (&ctrl
, argv
[0], argc
== 2?argv
[1]:NULL
);
740 log_error ("error mounting container `%s': %s <%s>\n",
741 *argv
, gpg_strerror (err
), gpg_strsource (err
));
746 log_error (_("invalid command (there is no implicit command)\n"));
753 /* Print the audit result if needed. */
754 if (auditlog
&& auditfp
)
756 /* audit_print_result (ctrl.audit, auditfp, 0); */
757 /* audit_release (ctrl.audit); */
764 return 8; /*NOTREACHED*/
768 /* Note: This function is used by signal handlers!. */
770 emergency_cleanup (void)
772 gcry_control (GCRYCTL_TERM_SECMEM
);
779 gcry_control (GCRYCTL_UPDATE_RANDOM_SEED_FILE
);
780 if (opt
.debug
& DBG_MEMSTAT_VALUE
)
782 gcry_control( GCRYCTL_DUMP_MEMORY_STATS
);
783 gcry_control( GCRYCTL_DUMP_RANDOM_STATS
);
786 gcry_control (GCRYCTL_DUMP_SECMEM_STATS
);
787 emergency_cleanup ();
788 rc
= rc
? rc
: log_get_errorcount(0)? 2 : g13_errors_seen
? 1 : 0;
793 /* Store defaults into the per-connection CTRL object. */
795 g13_init_default_ctrl (struct server_control_s
*ctrl
)
797 ctrl
->conttype
= CONTTYPE_ENCFS
;
801 /* This function is called for each signal we catch. It is run in the
802 main context or the one of a Pth thread and thus it is not
803 restricted in what it may do. */
805 handle_signal (int signo
)
809 #ifndef HAVE_W32_SYSTEM
811 log_info ("SIGHUP received - re-reading configuration\n");
812 /* Fixme: Not yet implemented. */
816 log_info ("SIGUSR1 received - printing internal information:\n");
817 pth_ctrl (PTH_CTRL_DUMPSTATE
, log_get_stream ());
818 mountinfo_dump_all ();
822 log_info ("SIGUSR2 received - no action defined\n");
826 if (!shutdown_pending
)
827 log_info ("SIGTERM received - shutting down ...\n");
829 log_info ("SIGTERM received - still %u runners active\n",
830 runner_get_threads ());
832 if (shutdown_pending
> 2)
834 log_info ("shutdown forced\n");
835 log_info ("%s %s stopped\n", strusage(11), strusage(13) );
841 log_info ("SIGINT received - immediate shutdown\n");
842 log_info( "%s %s stopped\n", strusage(11), strusage(13));
845 #endif /*!HAVE_W32_SYSTEM*/
848 log_info ("signal %d received - no action defined\n", signo
);
853 /* This ticker function is called about every TIMERTICK_INTERVAL_SEC
858 /* log_debug ("TICK\n"); */
862 /* The idle task. We use a separate thread to do idle stuff and to
865 idle_task (void *dummy_arg
)
867 sigset_t sigs
; /* The set of signals we want to catch. */
868 pth_event_t ev
; /* The main event to catch signals. */
869 pth_event_t time_ev
; /* The time event. */
870 int signo
; /* The number of a raised signal is stored here. */
874 /* Create the event to catch the signals. */
875 #ifndef HAVE_W32_SYSTEM
876 sigemptyset (&sigs
);
877 sigaddset (&sigs
, SIGHUP
);
878 sigaddset (&sigs
, SIGUSR1
);
879 sigaddset (&sigs
, SIGUSR2
);
880 sigaddset (&sigs
, SIGINT
);
881 sigaddset (&sigs
, SIGTERM
);
882 pth_sigmask (SIG_UNBLOCK
, &sigs
, NULL
);
886 ev
= pth_event (PTH_EVENT_SIGS
, &sigs
, &signo
);
888 /* The time event neds to computed n tghe fly. */
893 /* The shutdown flag allows us to terminate the idle task. */
894 if (shutdown_pending
)
896 runner_cancel_all ();
898 if (!runner_get_threads ())
902 /* Create a timeout event if needed. To help with power saving
903 we syncronize the ticks to the next full second. */
908 nexttick
= pth_timeout (TIMERTICK_INTERVAL_SEC
, 0);
909 if (nexttick
.tv_usec
> 10) /* Use a 10 usec threshhold. */
912 nexttick
.tv_usec
= 0;
914 time_ev
= pth_event (PTH_EVENT_TIME
, nexttick
);
917 pth_event_concat (ev
, time_ev
, NULL
);
919 pth_event_isolate (time_ev
);
921 if (pth_event_occurred (ev
))
923 handle_signal (signo
);
926 if (time_ev
&& pth_event_occurred (time_ev
))
928 pth_event_free (time_ev
, PTH_FREE_ALL
);
934 pth_event_free (ev
, PTH_FREE_ALL
);
936 pth_event_free (time_ev
, PTH_FREE_ALL
);
937 log_info (_("%s %s stopped\n"), strusage(11), strusage(13));
942 /* Start the idle task. */
944 start_idle_task (void)
949 tattr
= pth_attr_new ();
950 pth_attr_set (tattr
, PTH_ATTR_JOINABLE
, 1);
951 pth_attr_set (tattr
, PTH_ATTR_STACK_SIZE
, 64*1024);
952 pth_attr_set (tattr
, PTH_ATTR_NAME
, "idle-task");
954 tid
= pth_spawn (tattr
, idle_task
, NULL
);
957 log_fatal ("error starting idle task: %s\n",
958 gpg_strerror (gpg_error_from_syserror ()));
959 return; /*NOTREACHED*/
962 pth_attr_destroy (tattr
);
966 /* Wait for the idle task to finish. */
968 join_idle_task (void)
972 if (!pth_join (idle_task_tid
, NULL
))
973 log_error ("waiting for idle task thread failed: %s\n",
974 gpg_strerror (gpg_error_from_syserror ()));