diff options
Diffstat (limited to 'src/main.c')
-rw-r--r-- | src/main.c | 242 |
1 files changed, 106 insertions, 136 deletions
@@ -38,6 +38,7 @@ #include "heap.h" #include "filter.h" #include "child.h" +#include "loop.h" #include "log.h" #include "reqs.h" #include "sock.h" @@ -47,10 +48,18 @@ /* * Global Structures */ -struct config_s config; -struct config_s config_defaults; +struct config_s *config; +static struct config_s configs[2]; +static const char* config_file; unsigned int received_sighup = FALSE; /* boolean */ +static struct config_s* +get_next_config(void) +{ + if (config == &configs[0]) return &configs[1]; + return &configs[0]; +} + /* * Handle a signal */ @@ -61,12 +70,14 @@ takesig (int sig) int status; switch (sig) { + case SIGUSR1: case SIGHUP: received_sighup = TRUE; break; + case SIGINT: case SIGTERM: - config.quit = TRUE; + config->quit = TRUE; break; case SIGCHLD: @@ -162,52 +173,6 @@ get_id (char *str) } /** - * process_cmdline: - * @argc: argc as passed to main() - * @argv: argv as passed to main() - * - * This function parses command line arguments. - **/ -static void -process_cmdline (int argc, char **argv, struct config_s *conf) -{ - int opt; - - while ((opt = getopt (argc, argv, "c:vdh")) != EOF) { - switch (opt) { - case 'v': - display_version (); - exit (EX_OK); - - case 'd': - conf->godaemon = FALSE; - break; - - case 'c': - if (conf->config_file != NULL) { - safefree (conf->config_file); - } - conf->config_file = safestrdup (optarg); - if (!conf->config_file) { - fprintf (stderr, - "%s: Could not allocate memory.\n", - argv[0]); - exit (EX_SOFTWARE); - } - break; - - case 'h': - display_usage (); - exit (EX_OK); - - default: - display_usage (); - exit (EX_USAGE); - } - } -} - -/** * change_user: * @program: The name of the program. Pass argv[0] here. * @@ -218,16 +183,16 @@ process_cmdline (int argc, char **argv, struct config_s *conf) static void change_user (const char *program) { - if (config.group && strlen (config.group) > 0) { - int gid = get_id (config.group); + if (config->group && strlen (config->group) > 0) { + int gid = get_id (config->group); if (gid < 0) { - struct group *thisgroup = getgrnam (config.group); + struct group *thisgroup = getgrnam (config->group); if (!thisgroup) { fprintf (stderr, "%s: Unable to find group \"%s\".\n", - program, config.group); + program, config->group); exit (EX_NOUSER); } @@ -237,7 +202,7 @@ change_user (const char *program) if (setgid (gid) < 0) { fprintf (stderr, "%s: Unable to change to group \"%s\".\n", - program, config.group); + program, config->group); exit (EX_NOPERM); } @@ -252,19 +217,19 @@ change_user (const char *program) #endif log_message (LOG_INFO, "Now running as group \"%s\".", - config.group); + config->group); } - if (config.user && strlen (config.user) > 0) { - int uid = get_id (config.user); + if (config->user && strlen (config->user) > 0) { + int uid = get_id (config->user); if (uid < 0) { - struct passwd *thisuser = getpwnam (config.user); + struct passwd *thisuser = getpwnam (config->user); if (!thisuser) { fprintf (stderr, "%s: Unable to find user \"%s\".\n", - program, config.user); + program, config->user); exit (EX_NOUSER); } @@ -274,78 +239,99 @@ change_user (const char *program) if (setuid (uid) < 0) { fprintf (stderr, "%s: Unable to change to user \"%s\".\n", - program, config.user); + program, config->user); exit (EX_NOPERM); } log_message (LOG_INFO, "Now running as user \"%s\".", - config.user); + config->user); } } -static void initialize_config_defaults (struct config_s *conf) -{ - memset (conf, 0, sizeof(*conf)); - - conf->config_file = safestrdup (SYSCONFDIR "/tinyproxy.conf"); - if (!conf->config_file) { - fprintf (stderr, PACKAGE ": Could not allocate memory.\n"); - exit (EX_SOFTWARE); - } - conf->godaemon = TRUE; - /* - * Make sure the HTML error pages array is NULL to begin with. - * (FIXME: Should have a better API for all this) - */ - conf->errorpages = NULL; - conf->stathost = safestrdup (TINYPROXY_STATHOST); - conf->idletimeout = MAX_IDLE_TIME; - conf->logf_name = NULL; - conf->pidpath = NULL; -} - /** * convenience wrapper around reload_config_file * that also re-initializes logging. */ -int reload_config (void) +int reload_config (int reload_logging) { int ret; + struct config_s *c_next = get_next_config(); - shutdown_logging (); + log_message (LOG_NOTICE, "Reloading config file"); + + if (reload_logging) shutdown_logging (); + + ret = reload_config_file (config_file, c_next); - ret = reload_config_file (config_defaults.config_file, &config, - &config_defaults); if (ret != 0) { goto done; } - ret = setup_logging (); + if(config) free_config (config); + config = c_next; + + if (reload_logging) ret = setup_logging (); + log_message (LOG_NOTICE, "Reloading config file finished"); done: return ret; } +static void setup_sig(int sig, signal_func *sigh, + const char* signame, const char* argv0) { + if (set_signal_handler (sig, sigh) == SIG_ERR) { + fprintf (stderr, "%s: Could not set the \"%s\" signal.\n", + argv0, signame); + exit (EX_OSERR); + } +} + int main (int argc, char **argv) { + int opt, daemonized = TRUE; + + srand(time(NULL)); /* for hashmap seeds */ + /* Only allow u+rw bits. This may be required for some versions * of glibc so that mkstemp() doesn't make us vulnerable. */ umask (0177); - log_message (LOG_INFO, "Initializing " PACKAGE " ..."); + log_message (LOG_NOTICE, "Initializing " PACKAGE " ..."); - if (config_compile_regex()) { + if (config_init()) { + fprintf(stderr, "ERROR: config_init() failed\n"); exit (EX_SOFTWARE); } - initialize_config_defaults (&config_defaults); - process_cmdline (argc, argv, &config_defaults); + config_file = SYSCONFDIR "/tinyproxy.conf"; + + while ((opt = getopt (argc, argv, "c:vdh")) != EOF) { + switch (opt) { + case 'v': + display_version (); + exit (EX_OK); + + case 'd': + daemonized = FALSE; + break; + + case 'c': + config_file = optarg; + break; + + case 'h': + display_usage (); + exit (EX_OK); - if (reload_config_file (config_defaults.config_file, - &config, - &config_defaults)) { + default: + display_usage (); + exit (EX_USAGE); + } + } + + if (reload_config(0)) { exit (EX_SOFTWARE); } @@ -355,40 +341,36 @@ main (int argc, char **argv) * in the list of allowed headers, since it is required in a * HTTP/1.0 request. Also add the Content-Type header since it * goes hand in hand with Content-Length. */ - if (is_anonymous_enabled ()) { - anonymous_insert ("Content-Length"); - anonymous_insert ("Content-Type"); + if (is_anonymous_enabled (config)) { + anonymous_insert (config, safestrdup("Content-Length")); + anonymous_insert (config, safestrdup("Content-Type")); } - if (config.godaemon == TRUE) { - if (!config.syslog && config.logf_name == NULL) + if (daemonized == TRUE) { + if (!config->syslog && config->logf_name == NULL) fprintf(stderr, "WARNING: logging deactivated " "(can't log to stdout when daemonized)\n"); makedaemon (); } - if (set_signal_handler (SIGPIPE, SIG_IGN) == SIG_ERR) { - fprintf (stderr, "%s: Could not set the \"SIGPIPE\" signal.\n", - argv[0]); - exit (EX_OSERR); - } + setup_sig(SIGPIPE, SIG_IGN, "SIGPIPE", argv[0]); #ifdef FILTER_ENABLE - if (config.filter) + if (config->filter) filter_init (); #endif /* FILTER_ENABLE */ /* Start listening on the selected port. */ - if (child_listening_sockets(config.listen_addrs, config.port) < 0) { + if (child_listening_sockets(config->listen_addrs, config->port) < 0) { fprintf (stderr, "%s: Could not create listening sockets.\n", argv[0]); exit (EX_OSERR); } /* Create pid file before we drop privileges */ - if (config.pidpath) { - if (pidfile_create (config.pidpath) < 0) { + if (config->pidpath) { + if (pidfile_create (config->pidpath) < 0) { fprintf (stderr, "%s: Could not create PID file.\n", argv[0]); exit (EX_OSERR); @@ -399,7 +381,7 @@ main (int argc, char **argv) if (geteuid () == 0) change_user (argv[0]); else - log_message (LOG_WARNING, + log_message (LOG_INFO, "Not running as root, so not changing UID/GID."); /* Create log file after we drop privileges */ @@ -407,56 +389,44 @@ main (int argc, char **argv) exit (EX_SOFTWARE); } - if (child_pool_create () < 0) { - fprintf (stderr, - "%s: Could not create the pool of children.\n", - argv[0]); - exit (EX_SOFTWARE); - } - /* These signals are only for the parent process. */ log_message (LOG_INFO, "Setting the various signals."); - if (set_signal_handler (SIGCHLD, takesig) == SIG_ERR) { - fprintf (stderr, "%s: Could not set the \"SIGCHLD\" signal.\n", - argv[0]); - exit (EX_OSERR); - } + setup_sig (SIGCHLD, takesig, "SIGCHLD", argv[0]); + setup_sig (SIGTERM, takesig, "SIGTERM", argv[0]); + setup_sig (SIGINT, takesig, "SIGINT", argv[0]); + if (daemonized) setup_sig (SIGHUP, takesig, "SIGHUP", argv[0]); + setup_sig (SIGUSR1, takesig, "SIGUSR1", argv[0]); - if (set_signal_handler (SIGTERM, takesig) == SIG_ERR) { - fprintf (stderr, "%s: Could not set the \"SIGTERM\" signal.\n", - argv[0]); - exit (EX_OSERR); - } - - if (set_signal_handler (SIGHUP, takesig) == SIG_ERR) { - fprintf (stderr, "%s: Could not set the \"SIGHUP\" signal.\n", - argv[0]); - exit (EX_OSERR); - } + loop_records_init(); /* Start the main loop */ log_message (LOG_INFO, "Starting main loop. Accepting connections."); child_main_loop (); - log_message (LOG_INFO, "Shutting down."); + log_message (LOG_NOTICE, "Shutting down."); child_kill_children (SIGTERM); child_close_sock (); + child_free_children(); + + loop_records_destroy(); /* Remove the PID file */ - if (config.pidpath != NULL && unlink (config.pidpath) < 0) { + if (config->pidpath != NULL && unlink (config->pidpath) < 0) { log_message (LOG_WARNING, "Could not remove PID file \"%s\": %s.", - config.pidpath, strerror (errno)); + config->pidpath, strerror (errno)); } #ifdef FILTER_ENABLE - if (config.filter) + if (config->filter) filter_destroy (); #endif /* FILTER_ENABLE */ + free_config (config); + shutdown_logging (); return EXIT_SUCCESS; |