diff options
Diffstat (limited to 'agent/gpg-agent.c')
-rw-r--r-- | agent/gpg-agent.c | 916 |
1 files changed, 0 insertions, 916 deletions
diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c deleted file mode 100644 index 3c823e5f6..000000000 --- a/agent/gpg-agent.c +++ /dev/null @@ -1,916 +0,0 @@ -/* gpg-agent.c - The GnuPG Agent - * Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. - * - * This file is part of GnuPG. - * - * GnuPG is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GnuPG is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - */ - -#include <config.h> - -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <stdarg.h> -#include <string.h> -#include <errno.h> -#include <assert.h> -#include <time.h> -#include <fcntl.h> -#include <sys/socket.h> -#include <sys/un.h> -#include <unistd.h> -#include <signal.h> -#ifdef USE_GNU_PTH -# include <pth.h> -#endif - -#include <gcrypt.h> - -#define JNLIB_NEED_LOG_LOGV -#include "agent.h" -#include "../assuan/assuan.h" /* malloc hooks */ - -#include "i18n.h" -#include "sysutils.h" - - -enum cmd_and_opt_values -{ aNull = 0, - oCsh = 'c', - oQuiet = 'q', - oSh = 's', - oVerbose = 'v', - - oNoVerbose = 500, - oOptions, - oDebug, - oDebugAll, - oDebugWait, - oNoGreeting, - oNoOptions, - oHomedir, - oNoDetach, - oNoGrab, - oLogFile, - oServer, - oDaemon, - oBatch, - - oPinentryProgram, - oDisplay, - oTTYname, - oTTYtype, - oLCctype, - oLCmessages, - oScdaemonProgram, - oDefCacheTTL, - oDisablePth, - - oIgnoreCacheForSigning, - oKeepTTY, - oKeepDISPLAY, - -aTest }; - - - -static ARGPARSE_OPTS opts[] = { - - { 301, NULL, 0, N_("@Options:\n ") }, - - { oServer, "server", 0, N_("run in server mode (foreground)") }, - { oDaemon, "daemon", 0, N_("run in daemon mode (background)") }, - { oVerbose, "verbose", 0, N_("verbose") }, - { oQuiet, "quiet", 0, N_("be somewhat more quiet") }, - { oSh, "sh", 0, N_("sh-style command output") }, - { oCsh, "csh", 0, N_("csh-style command output") }, - { oOptions, "options" , 2, N_("read options from file")}, - { oDebug, "debug" ,4|16, N_("set debugging flags")}, - { oDebugAll, "debug-all" ,0, N_("enable full debugging")}, - { oDebugWait,"debug-wait",1, "@"}, - { oNoDetach, "no-detach" ,0, N_("do not detach from the console")}, - { oNoGrab, "no-grab" ,0, N_("do not grab keyboard and mouse")}, - { oLogFile, "log-file" ,2, N_("use a log file for the server")}, - { oDisablePth, "disable-pth", 0, N_("do not allow multiple connections")}, - - { oPinentryProgram, "pinentry-program", 2 , "path to PIN Entry program" }, - { oDisplay, "display", 2, "set the display" }, - { oTTYname, "ttyname", 2, "set the tty terminal node name" }, - { oTTYtype, "ttytype", 2, "set the tty terminal type" }, - { oLCctype, "lc-ctype", 2, "set the tty LC_CTYPE value" }, - { oLCmessages, "lc-messages", 2, "set the tty LC_MESSAGES value" }, - - { oScdaemonProgram, "scdaemon-program", 2 , "path to SCdaemon program" }, - { oDefCacheTTL, "default-cache-ttl", 4, - "|N|expire cached PINs after N seconds"}, - { oIgnoreCacheForSigning, "ignore-cache-for-signing", 0, - "do not use the PIN cache when signing"}, - { oKeepTTY, "keep-tty", 0, N_("ignore requests to change the TTY")}, - { oKeepDISPLAY, "keep-display", - 0, N_("ignore requests to change the X display")}, - {0} -}; - - -static volatile int caught_fatal_sig = 0; - -/* flag to indicate that a shutdown was requested */ -static int shutdown_pending; - - -/* It is possible that we are currently running under setuid permissions */ -static int maybe_setuid = 1; - -/* Name of the communication socket */ -static char socket_name[128]; - -static void create_directories (void); -#ifdef USE_GNU_PTH -static void handle_connections (int listen_fd); -#endif - - - -static const char * -my_strusage (int level) -{ - const char *p; - switch (level) - { - case 11: p = "gpg-agent (GnuPG)"; - break; - case 13: p = VERSION; break; - case 17: p = PRINTABLE_OS_NAME; break; - case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n"); - break; - case 1: - case 40: p = _("Usage: gpg-agent [options] (-h for help)"); - break; - case 41: p = _("Syntax: gpg-agent [options] [command [args]]\n" - "Secret key management for GnuPG\n"); - break; - - default: p = NULL; - } - return p; -} - - - -static void -i18n_init (void) -{ -#ifdef USE_SIMPLE_GETTEXT - set_gettext_file( PACKAGE ); -#else -#ifdef ENABLE_NLS - setlocale (LC_ALL, ""); - bindtextdomain (PACKAGE, LOCALEDIR); - textdomain (PACKAGE); -#endif -#endif -} - - - -/* Used by gcry for logging */ -static void -my_gcry_logger (void *dummy, int level, const char *fmt, va_list arg_ptr) -{ - /* translate the log levels */ - switch (level) - { - case GCRY_LOG_CONT: level = JNLIB_LOG_CONT; break; - case GCRY_LOG_INFO: level = JNLIB_LOG_INFO; break; - case GCRY_LOG_WARN: level = JNLIB_LOG_WARN; break; - case GCRY_LOG_ERROR:level = JNLIB_LOG_ERROR; break; - case GCRY_LOG_FATAL:level = JNLIB_LOG_FATAL; break; - case GCRY_LOG_BUG: level = JNLIB_LOG_BUG; break; - case GCRY_LOG_DEBUG:level = JNLIB_LOG_DEBUG; break; - default: level = JNLIB_LOG_ERROR; break; - } - log_logv (level, fmt, arg_ptr); -} - - -static void -cleanup (void) -{ - if (*socket_name) - { - char *p; - - remove (socket_name); - p = strrchr (socket_name, '/'); - if (p) - { - *p = 0; - rmdir (socket_name); - *p = '/'; - } - *socket_name = 0; - } -} - - -static RETSIGTYPE -cleanup_sh (int sig) -{ - if (caught_fatal_sig) - raise (sig); - caught_fatal_sig = 1; - - /* gcry_control( GCRYCTL_TERM_SECMEM );*/ - cleanup (); - -#ifndef HAVE_DOSISH_SYSTEM - { /* reset action to default action and raise signal again */ - struct sigaction nact; - nact.sa_handler = SIG_DFL; - sigemptyset( &nact.sa_mask ); - nact.sa_flags = 0; - sigaction( sig, &nact, NULL); - } -#endif - raise( sig ); -} - -int -main (int argc, char **argv ) -{ - ARGPARSE_ARGS pargs; - int orig_argc; - int may_coredump; - char **orig_argv; - FILE *configfp = NULL; - char *configname = NULL; - const char *shell; - unsigned configlineno; - int parse_debug = 0; - int default_config =1; - int greeting = 0; - int nogreeting = 0; - int pipe_server = 0; - int is_daemon = 0; - int nodetach = 0; - int csh_style = 0; - char *logfile = NULL; - int debug_wait = 0; - int disable_pth = 0; - - set_strusage (my_strusage); - gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN); - /* Please note that we may running SUID(ROOT), so be very CAREFUL - when adding any stuff between here and the call to INIT_SECMEM() - somewhere after the option parsing */ - log_set_prefix ("gpg-agent", 1|4); - i18n_init (); - - /* check that the libraries are suitable. Do it here because - the option parsing may need services of the library */ - if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) ) - { - log_fatal( _("libgcrypt is too old (need %s, have %s)\n"), - NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) ); - } - - assuan_set_malloc_hooks (gcry_malloc, gcry_realloc, gcry_free); -#ifdef USE_GNU_PTH - assuan_set_io_func (pth_read, pth_write); -#endif - - gcry_set_log_handler (my_gcry_logger, NULL); - gcry_control (GCRYCTL_USE_SECURE_RNDPOOL); - - may_coredump = disable_core_dumps (); - - shell = getenv ("SHELL"); - if (shell && strlen (shell) >= 3 && !strcmp (shell+strlen (shell)-3, "csh") ) - csh_style = 1; - - opt.homedir = getenv("GNUPGHOME"); - if (!opt.homedir || !*opt.homedir) - opt.homedir = GNUPG_DEFAULT_HOMEDIR; - opt.def_cache_ttl = 10*60; /* default to 10 minutes */ - - - /* check whether we have a config file on the commandline */ - orig_argc = argc; - orig_argv = argv; - pargs.argc = &argc; - pargs.argv = &argv; - pargs.flags= 1|(1<<6); /* do not remove the args, ignore version */ - while (arg_parse( &pargs, opts)) - { - if (pargs.r_opt == oDebug || pargs.r_opt == oDebugAll) - parse_debug++; - else if (pargs.r_opt == oOptions) - { /* yes there is one, so we do not try the default one, but - read the option file when it is encountered at the - commandline */ - default_config = 0; - } - else if (pargs.r_opt == oNoOptions) - default_config = 0; /* --no-options */ - else if (pargs.r_opt == oHomedir) - opt.homedir = pargs.r.ret_str; - } - - /* initialize the secure memory. */ - gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0); - maybe_setuid = 0; - - /* - Now we are now working under our real uid - */ - - - if (default_config) - configname = make_filename (opt.homedir, "gpg-agent.conf", NULL ); - - argc = orig_argc; - argv = orig_argv; - pargs.argc = &argc; - pargs.argv = &argv; - pargs.flags= 1; /* do not remove the args */ - next_pass: - if (configname) - { - configlineno = 0; - configfp = fopen (configname, "r"); - if (!configfp) - { - if (default_config) - { - if( parse_debug ) - log_info (_("NOTE: no default option file `%s'\n"), - configname ); - } - else - { - log_error (_("option file `%s': %s\n"), - configname, strerror(errno) ); - exit(2); - } - xfree (configname); - configname = NULL; - } - if (parse_debug && configname ) - log_info (_("reading options from `%s'\n"), configname ); - default_config = 0; - } - - while (optfile_parse( configfp, configname, &configlineno, &pargs, opts) ) - { - switch (pargs.r_opt) - { - case oQuiet: opt.quiet = 1; break; - case oVerbose: opt.verbose++; break; - case oBatch: opt.batch=1; break; - - case oDebug: opt.debug |= pargs.r.ret_ulong; break; - case oDebugAll: opt.debug = ~0; break; - case oDebugWait: debug_wait = pargs.r.ret_int; break; - - case oOptions: - /* config files may not be nested (silently ignore them) */ - if (!configfp) - { - xfree(configname); - configname = xstrdup(pargs.r.ret_str); - goto next_pass; - } - break; - case oNoGreeting: nogreeting = 1; break; - case oNoVerbose: opt.verbose = 0; break; - case oNoOptions: break; /* no-options */ - case oHomedir: opt.homedir = pargs.r.ret_str; break; - case oNoDetach: nodetach = 1; break; - case oNoGrab: opt.no_grab = 1; break; - case oLogFile: logfile = pargs.r.ret_str; break; - case oCsh: csh_style = 1; break; - case oSh: csh_style = 0; break; - case oServer: pipe_server = 1; break; - case oDaemon: is_daemon = 1; break; - case oDisablePth: disable_pth = 1; break; - - case oPinentryProgram: opt.pinentry_program = pargs.r.ret_str; break; - case oDisplay: opt.display = xstrdup (pargs.r.ret_str); break; - case oTTYname: opt.ttyname = xstrdup (pargs.r.ret_str); break; - case oTTYtype: opt.ttytype = xstrdup (pargs.r.ret_str); break; - case oLCctype: opt.lc_ctype = xstrdup (pargs.r.ret_str); break; - case oLCmessages: opt.lc_messages = xstrdup (pargs.r.ret_str); break; - case oScdaemonProgram: opt.scdaemon_program = pargs.r.ret_str; break; - case oDefCacheTTL: opt.def_cache_ttl = pargs.r.ret_ulong; break; - - case oIgnoreCacheForSigning: opt.ignore_cache_for_signing = 1; break; - case oKeepTTY: opt.keep_tty = 1; break; - case oKeepDISPLAY: opt.keep_display = 1; break; - - default : pargs.err = configfp? 1:2; break; - } - } - if (configfp) - { - fclose( configfp ); - configfp = NULL; - xfree(configname); - configname = NULL; - goto next_pass; - } - xfree (configname); - configname = NULL; - if (log_get_errorcount(0)) - exit(2); - if (nogreeting ) - greeting = 0; - - if (greeting) - { - fprintf (stderr, "%s %s; %s\n", - strusage(11), strusage(13), strusage(14) ); - fprintf (stderr, "%s\n", strusage(15) ); - } -#ifdef IS_DEVELOPMENT_VERSION - log_info ("NOTE: this is a development version!\n"); -#endif - - - if (atexit (cleanup)) - { - log_error ("atexit failed\n"); - cleanup (); - exit (1); - } - - create_directories (); - - if (debug_wait && pipe_server) - { - log_debug ("waiting for debugger - my pid is %u .....\n", - (unsigned int)getpid()); - sleep (debug_wait); - log_debug ("... okay\n"); - } - - /* now start with logging to a file if this is desired */ - if (logfile) - { - log_set_file (logfile); - log_set_prefix (NULL, 1|2|4); - } - - - if (pipe_server) - { /* this is the simple pipe based server */ - start_command_handler (-1, -1); - } - else if (!is_daemon) - { - log_info (_("please use the option `--daemon'" - " to run the program in the background\n")); - } - else - { /* regular server mode */ - int fd; - pid_t pid; - int len; - struct sockaddr_un serv_addr; - char *p; - - *socket_name = 0; - snprintf (socket_name, DIM(socket_name)-1, - "/tmp/gpg-XXXXXX/S.gpg-agent"); - socket_name[DIM(socket_name)-1] = 0; - p = strrchr (socket_name, '/'); - if (!p) - BUG (); - *p = 0;; - if (!mkdtemp(socket_name)) - { - log_error ("can't create directory `%s': %s\n", - socket_name, strerror(errno) ); - exit (1); - } - *p = '/'; - - if (strchr (socket_name, ':') ) - { - log_error ("colons are not allowed in the socket name\n"); - exit (1); - } - if (strlen (socket_name)+1 >= sizeof serv_addr.sun_path ) - { - log_error ("name of socket too long\n"); - exit (1); - } - - - fd = socket (AF_UNIX, SOCK_STREAM, 0); - if (fd == -1) - { - log_error ("can't create socket: %s\n", strerror(errno) ); - exit (1); - } - - memset (&serv_addr, 0, sizeof serv_addr); - serv_addr.sun_family = AF_UNIX; - strcpy (serv_addr.sun_path, socket_name); - len = (offsetof (struct sockaddr_un, sun_path) - + strlen(serv_addr.sun_path) + 1); - - if (bind (fd, (struct sockaddr*)&serv_addr, len) == -1) - { - log_error ("error binding socket to `%s': %s\n", - serv_addr.sun_path, strerror (errno) ); - close (fd); - exit (1); - } - - if (listen (fd, 5 ) == -1) - { - log_error ("listen() failed: %s\n", strerror (errno)); - close (fd); - exit (1); - } - - if (opt.verbose) - log_info ("listening on socket `%s'\n", socket_name ); - - - fflush (NULL); - pid = fork (); - if (pid == (pid_t)-1) - { - log_fatal ("fork failed: %s\n", strerror (errno) ); - exit (1); - } - else if (pid) - { /* we are the parent */ - char *infostr; - - close (fd); - - /* create the info string: <name>:<pid>:<protocol_version> */ - if (asprintf (&infostr, "GPG_AGENT_INFO=%s:%lu:1", - socket_name, (ulong)pid ) < 0) - { - log_error ("out of core\n"); - kill (pid, SIGTERM); - exit (1); - } - *socket_name = 0; /* don't let cleanup() remove the socket - - the child should do this from now on */ - if (argc) - { /* run the program given on the commandline */ - if (putenv (infostr)) - { - log_error ("failed to set environment: %s\n", - strerror (errno) ); - kill (pid, SIGTERM ); - exit (1); - } - execvp (argv[0], argv); - log_error ("failed to run the command: %s\n", strerror (errno)); - kill (pid, SIGTERM); - exit (1); - } - else - { - /* print the environment string, so that the caller can use - shell's eval to set it */ - if (csh_style) - { - *strchr (infostr, '=') = ' '; - printf ( "setenv %s\n", infostr); - } - else - { - printf ( "%s; export GPG_AGENT_INFO;\n", infostr); - } - free (infostr); - exit (0); - } - /*NEVER REACHED*/ - } /* end parent */ - - - /* this is the child */ - - /* detach from tty and put process into a new session */ - if (!nodetach ) - { - int i; - - /* close stdin, stdout and stderr unless it is the log stream */ - for (i=0; i <= 2; i++) - { - if ( log_get_fd () != i) - close (i); - } - if (setsid() == -1) - { - log_error ("setsid() failed: %s\n", strerror(errno) ); - cleanup (); - exit (1); - } - opt.running_detached = 1; - } - - if (chdir("/")) - { - log_error ("chdir to / failed: %s\n", strerror (errno)); - exit (1); - } - - -#ifdef USE_GNU_PTH - if (!disable_pth) - { - struct sigaction sa; - - if (!pth_init ()) - { - log_error ("failed to initialize the Pth library\n"); - exit (1); - } - - sa.sa_handler = SIG_IGN; - sigemptyset (&sa.sa_mask); - sa.sa_flags = 0; - sigaction (SIGPIPE, &sa, NULL); - handle_connections (fd); - } - else -#endif /*!USE_GNU_PTH*/ - /* setup signals */ - { - struct sigaction oact, nact; - - nact.sa_handler = cleanup_sh; - sigemptyset (&nact.sa_mask); - nact.sa_flags = 0; - - sigaction (SIGHUP, NULL, &oact); - if (oact.sa_handler != SIG_IGN) - sigaction (SIGHUP, &nact, NULL); - sigaction( SIGTERM, NULL, &oact ); - if (oact.sa_handler != SIG_IGN) - sigaction (SIGTERM, &nact, NULL); - nact.sa_handler = SIG_IGN; - sigaction (SIGPIPE, &nact, NULL); - sigaction (SIGINT, &nact, NULL); - - start_command_handler (fd, -1); - } - close (fd); - } - - return 0; -} - -void -agent_exit (int rc) -{ - /*FIXME: update_random_seed_file();*/ -#if 1 - /* at this time a bit annoying */ - if (opt.debug & DBG_MEMSTAT_VALUE) - { - gcry_control( GCRYCTL_DUMP_MEMORY_STATS ); - gcry_control( GCRYCTL_DUMP_RANDOM_STATS ); - } - if (opt.debug) - gcry_control (GCRYCTL_DUMP_SECMEM_STATS ); -#endif - gcry_control (GCRYCTL_TERM_SECMEM ); - rc = rc? rc : log_get_errorcount(0)? 2 : 0; - exit (rc); -} - - -static void -reread_configuration (void) -{ - /* FIXME: Move parts of the option parsing to here. */ -} - - -static void -create_private_keys_directory (const char *home) -{ - char *fname; - struct stat statbuf; - - fname = make_filename (home, GNUPG_PRIVATE_KEYS_DIR, NULL); - if (stat (fname, &statbuf) && errno == ENOENT) - { - if (mkdir (fname, S_IRUSR|S_IWUSR|S_IXUSR )) - log_error (_("can't create directory `%s': %s\n"), - fname, strerror(errno) ); - else if (!opt.quiet) - log_info (_("directory `%s' created\n"), fname); - } - xfree (fname); -} - -/* Create the directory only if the supplied directory name is the - same as the default one. This way we avoid to create arbitrary - directories when a non-default home directory is used. To cope - with HOME, we compare only the suffix if we see that the default - homedir does start with a tilde. We don't stop here in case of - problems because other functions will throw an error anyway.*/ -static void -create_directories (void) -{ - struct stat statbuf; - const char *defhome = GNUPG_DEFAULT_HOMEDIR; - char *home; - - home = make_filename (opt.homedir, NULL); - if ( stat (home, &statbuf) ) - { - if (errno == ENOENT) - { - if ( (*defhome == '~' - && (strlen (home) >= strlen (defhome+1) - && !strcmp (home + strlen(home) - - strlen (defhome+1), defhome+1))) - || (*defhome != '~' && !strcmp (home, defhome) ) - ) - { - if (mkdir (home, S_IRUSR|S_IWUSR|S_IXUSR )) - log_error (_("can't create directory `%s': %s\n"), - home, strerror(errno) ); - else - { - if (!opt.quiet) - log_info (_("directory `%s' created\n"), home); - create_private_keys_directory (home); - } - } - } - else - log_error ("error stat-ing `%s': %s\n", home, strerror (errno)); - } - else if ( !S_ISDIR(statbuf.st_mode)) - { - log_error ("can't use `%s' as home directory\n", home); - } - else /* exists and is a directory. */ - { - create_private_keys_directory (home); - } - xfree (home); -} - - - -#ifdef USE_GNU_PTH -static void -handle_signal (int signo) -{ - switch (signo) - { - case SIGHUP: - log_info ("SIGHUP received - " - "re-reading configuration and flushing cache\n"); - agent_flush_cache (); - reread_configuration (); - break; - - case SIGUSR1: - if (opt.verbose < 5) - opt.verbose++; - log_info ("SIGUSR1 received - verbosity set to %d\n", opt.verbose); - break; - - case SIGUSR2: - if (opt.verbose) - opt.verbose--; - log_info ("SIGUSR2 received - verbosity set to %d\n", opt.verbose ); - break; - - case SIGTERM: - if (!shutdown_pending) - log_info ("SIGTERM received - shutting down ...\n"); - else - log_info ("SIGTERM received - still %ld running threads\n", - pth_ctrl( PTH_CTRL_GETTHREADS )); - shutdown_pending++; - if (shutdown_pending > 2) - { - log_info ("shutdown forced\n"); - log_info ("%s %s stopped\n", strusage(11), strusage(13) ); - cleanup (); - agent_exit (0); - } - break; - - case SIGINT: - log_info ("SIGINT received - immediate shutdown\n"); - log_info( "%s %s stopped\n", strusage(11), strusage(13)); - cleanup (); - agent_exit (0); - break; - - default: - log_info ("signal %d received - no action defined\n", signo); - } -} - - -static void * -start_connection_thread (void *arg) -{ - int fd = (int)arg; - - if (opt.verbose) - log_info ("handler for fd %d started\n", fd); - start_command_handler (-1, fd); - if (opt.verbose) - log_info ("handler for fd %d terminated\n", fd); - - return NULL; -} - - -static void -handle_connections (int listen_fd) -{ - pth_attr_t tattr; - pth_event_t ev; - sigset_t sigs; - int signo; - struct sockaddr_un paddr; - socklen_t plen = sizeof( paddr ); - int fd; - - tattr = pth_attr_new(); - pth_attr_set (tattr, PTH_ATTR_JOINABLE, 0); - pth_attr_set (tattr, PTH_ATTR_STACK_SIZE, 32*1024); - pth_attr_set (tattr, PTH_ATTR_NAME, "gpg-agent"); - - sigemptyset (&sigs ); - sigaddset (&sigs, SIGHUP); - sigaddset (&sigs, SIGUSR1); - sigaddset (&sigs, SIGUSR2); - sigaddset (&sigs, SIGINT); - sigaddset (&sigs, SIGTERM); - ev = pth_event (PTH_EVENT_SIGS, &sigs, &signo); - - for (;;) - { - if (shutdown_pending) - { - if (pth_ctrl (PTH_CTRL_GETTHREADS) == 1) - break; /* ready */ - - /* Do not accept anymore connections and wait for existing - connections to terminate */ - signo = 0; - pth_wait (ev); - if (pth_event_occurred (ev) && signo) - handle_signal (signo); - continue; - } - - fd = pth_accept_ev (listen_fd, (struct sockaddr *)&paddr, &plen, ev); - if (fd == -1) - { - if (pth_event_occurred (ev)) - { - handle_signal (signo); - continue; - } - log_error ("accept failed: %s - waiting 1s\n", strerror (errno)); - pth_sleep(1); - continue; - } - - if (!pth_spawn (tattr, start_connection_thread, (void*)fd)) - { - log_error ("error spawning connection handler: %s\n", - strerror (errno) ); - close (fd); - } - } - - pth_event_free (ev, PTH_FREE_ALL); - cleanup (); - log_info ("%s %s stopped\n", strusage(11), strusage(13)); -} -#endif /*USE_GNU_PTH*/ |