/**
 * This is the "real" main which is called both on Windows and UNIX platforms.
 * For the Windows service case, this will also handle the notifications and set
 * up the logging support appropriately.
 */
int main_cmdline(int argc, char **argv) {
	chassis *srv = NULL;
#ifdef HAVE_SIGACTION
	static struct sigaction sigsegv_sa;
#endif
	/* read the command-line options */
	GOptionContext *option_ctx = NULL;
	GOptionEntry *main_entries = NULL;
	chassis_frontend_t *frontend = NULL;
	chassis_options_t *opts = NULL;

	GError *gerr = NULL;
	chassis_log *log = NULL;

	/* a little helper macro to set the src-location that we stepped out at to exit */
#define GOTO_EXIT(status) \
	exit_code = status; \
	exit_location = G_STRLOC; \
	goto exit_nicely;

	int exit_code = EXIT_SUCCESS;
	const gchar *exit_location = G_STRLOC;

	if (chassis_frontend_init_glib()) { /* init the thread, module, ... system */
		GOTO_EXIT(EXIT_FAILURE);
	}

	/* start the logging ... to stderr */
	log = chassis_log_new();
	log->min_lvl = G_LOG_LEVEL_MESSAGE; /* display messages while parsing or loading plugins */
	g_log_set_default_handler(chassis_log_func, log);

#ifdef _WIN32
	if (chassis_win32_is_service() && chassis_log_set_event_log(log, g_get_prgname())) {
		GOTO_EXIT(EXIT_FAILURE);
	}

	if (chassis_frontend_init_win32()) { /* setup winsock */
		GOTO_EXIT(EXIT_FAILURE);
	}
#endif

	/* may fail on library mismatch */
	if (NULL == (srv = chassis_new())) {
		GOTO_EXIT(EXIT_FAILURE);
	}

	srv->log = log; /* we need the log structure for the log-rotation */

	frontend = chassis_frontend_new();
	option_ctx = g_option_context_new("- MySQL Proxy");
	/**
	 * parse once to get the basic options like --defaults-file and --version
	 *
	 * leave the unknown options in the list
	 */
	if (chassis_frontend_init_base_options(option_ctx,
				&argc, &argv,
				&(frontend->print_version),
				&(frontend->default_file),
				&gerr)) {
		g_critical("%s: %s",
				G_STRLOC,
				gerr->message);
		g_clear_error(&gerr);

		GOTO_EXIT(EXIT_FAILURE);
	}

#ifndef _WIN32
	signal(SIGPIPE, SIG_IGN);

	srv->daemon_mode  = frontend->daemon_mode;			/* add by vinchen/CFR */
	srv->auto_restart = frontend->auto_restart;

	if (frontend->daemon_mode) {
		chassis_unix_daemonize();
	}

	if (frontend->auto_restart) {
		int child_exit_status = EXIT_SUCCESS; /* forward the exit-status of the child */
		int ret = chassis_unix_proc_keepalive(&child_exit_status);

		if (ret > 0) {
			/* the agent stopped */

			exit_code = child_exit_status;
			goto exit_nicely;
		} else if (ret < 0) {
			GOTO_EXIT(EXIT_FAILURE);
		} else {
			/* we are the child, go on */
		}
	}
#endif

	if (frontend->default_file) {
		srv->default_file = g_strdup(frontend->default_file); //add by vinchen/CFR
		if (!(frontend->keyfile = chassis_frontend_open_config_file(frontend->default_file, &gerr))) {
			g_critical("%s: loading config from '%s' failed: %s",
					G_STRLOC,
					frontend->default_file,
					gerr->message);
			g_clear_error(&gerr);
			GOTO_EXIT(EXIT_FAILURE);
		}
	}

	/* print the main version number here, but don't exit
	 * we check for print_version again, after loading the plugins (if any)
	 * and print their version numbers, too. then we exit cleanly.
	 */
	if (frontend->print_version) {
#ifndef CHASSIS_BUILD_TAG
#define CHASSIS_BUILD_TAG PACKAGE_STRING
#endif
		g_print("%s" CHASSIS_NEWLINE, CHASSIS_BUILD_TAG); 
		chassis_frontend_print_version();
	}
	
	/* add the other options which can also appear in the configfile */
	opts = chassis_options_new();
	chassis_frontend_set_chassis_options(frontend, opts);
	main_entries = chassis_options_to_g_option_entries(opts);
	g_option_context_add_main_entries(option_ctx, main_entries, NULL);

	/**
	 * parse once to get the basic options 
	 *
	 * leave the unknown options in the list
	 */
	if (FALSE == g_option_context_parse(option_ctx, &argc, &argv, &gerr)) {
		g_critical("%s", gerr->message);

		GOTO_EXIT(EXIT_FAILURE);
	}

	if (frontend->keyfile) {
		if (chassis_keyfile_to_options(frontend->keyfile, "mysql-proxy", main_entries)) {
			GOTO_EXIT(EXIT_FAILURE);
		}
	}

	//add by vinchen/CFR
	if (frontend->base_dir != NULL)
		srv->base_dir_org = g_strdup(frontend->base_dir);

	if (chassis_frontend_init_basedir(argv[0], &(frontend->base_dir))) {
		GOTO_EXIT(EXIT_FAILURE);
	}

	/* basic setup is done, base-dir is known, ... */
	frontend->lua_subdirs = g_new(char *, 2);
	frontend->lua_subdirs[0] = g_strdup("mysql-proxy");
	frontend->lua_subdirs[1] = NULL;

	if (chassis_frontend_init_lua_path(frontend->lua_path, frontend->base_dir, frontend->lua_subdirs)) {
		GOTO_EXIT(EXIT_FAILURE);
	}
	
	if (chassis_frontend_init_lua_cpath(frontend->lua_cpath, frontend->base_dir, frontend->lua_subdirs)) {
		GOTO_EXIT(EXIT_FAILURE);
	}

	/* assign the mysqld part to the */
	network_mysqld_init(srv); /* starts the also the lua-scope, LUA_PATH and LUA_CPATH have to be set before this being called */


#ifdef HAVE_SIGACTION
	/* register the sigsegv interceptor */

	memset(&sigsegv_sa, 0, sizeof(sigsegv_sa));
	sigsegv_sa.sa_handler = sigsegv_handler;
	sigemptyset(&sigsegv_sa.sa_mask);

	srv->invoke_dbg_on_crash = frontend->invoke_dbg_on_crash;	//add by vinchen/CFR

	if (frontend->invoke_dbg_on_crash && !(RUNNING_ON_VALGRIND)) {
		sigaction(SIGSEGV, &sigsegv_sa, NULL);
	}
#endif

	/*
	 * some plugins cannot see the chassis struct from the point
	 * where they open files, hence we must make it available
	 */
	srv->base_dir = g_strdup(frontend->base_dir);

	if (frontend->plugin_dir)			//vinchen/CFR
		srv->plugin_dir_org = g_strdup(frontend->plugin_dir);
	if (frontend->pid_file)
		srv->pid_file_org	= g_strdup(frontend->pid_file);
	if (frontend->log_filename)
		srv->log_file_name_org	= g_strdup(frontend->log_filename);
	if (frontend->lua_path)
		srv->lua_path_org		= g_strdup(frontend->lua_path);
	if (frontend->lua_cpath)
		srv->lua_cpath_org		= g_strdup(frontend->lua_cpath);
	srv->max_files_number	= frontend->max_files_number;

	srv->conn_log = frontend->conn_log; //add by huibohuang
  srv->query_response_time_stats = frontend->query_response_time_stats;
	
	srv->ignore_user = g_strdupv(frontend->ignore_user);

	chassis_frontend_init_plugin_dir(&frontend->plugin_dir, srv->base_dir);
	
	/* 
	 * these are used before we gathered all the options
	 * from the plugins, thus we need to fix them up before
	 * dealing with all the rest.
	 */
	chassis_resolve_path(srv->base_dir, &frontend->log_filename);
	chassis_resolve_path(srv->base_dir, &frontend->pid_file);
	chassis_resolve_path(srv->base_dir, &frontend->plugin_dir);

	/*
	 * start the logging
	 */
	if (frontend->log_filename) {
		log->log_filename = g_strdup(frontend->log_filename);
	}

	log->use_syslog = frontend->use_syslog;

	if (log->log_filename && log->use_syslog) {
		g_critical("%s: log-file and log-use-syslog were given, but only one is allowed",
				G_STRLOC);
		GOTO_EXIT(EXIT_FAILURE);
	}

	if (log->log_filename && FALSE == chassis_log_open(log)) {
		g_critical("can't open log-file '%s': %s", log->log_filename, g_strerror(errno));

		GOTO_EXIT(EXIT_FAILURE);
	}


	/* handle log-level after the config-file is read, just in case it is specified in the file */
	if (frontend->log_level) {
		if (0 != chassis_log_set_level(log, frontend->log_level)) {
			g_critical("--log-level=... failed, level '%s' is unknown ",
					frontend->log_level);

			GOTO_EXIT(EXIT_FAILURE);
		}
	} else {
		/* if it is not set, use "critical" as default */
		log->min_lvl = G_LOG_LEVEL_CRITICAL;
	}

	/*
	 * the MySQL Proxy should load 'admin' and 'proxy' plugins
	 */
	if (!frontend->plugin_names) {
		frontend->plugin_names = g_new(char *, 2);

		frontend->plugin_names[0] = g_strdup("proxy");
		frontend->plugin_names[1] = NULL;
	}
Exemple #2
0
/**
 * This is the "real" main which is called both on Windows and UNIX platforms.
 * For the Windows service case, this will also handle the notifications and set
 * up the logging support appropriately.
 */
int main_cmdline(int argc, char **argv) {
	chassis *srv = NULL;
#ifdef HAVE_SIGACTION
	static struct sigaction sigsegv_sa;
#endif
	/* read the command-line options */
	GOptionContext *option_ctx = NULL;
	GOptionEntry *main_entries = NULL;
	chassis_frontend_t *frontend = NULL;
	chassis_options_t *opts = NULL;

	GError *gerr = NULL;
	chassis_log_t *log = NULL;

	/* a little helper macro to set the src-location that we stepped out at to exit */
#define GOTO_EXIT(status) \
	exit_code = status; \
	exit_location = G_STRLOC; \
	goto exit_nicely;

	int exit_code = EXIT_SUCCESS;
	const gchar *exit_location = G_STRLOC;

	if (chassis_frontend_init_glib()) { /* init the thread, module, ... system */
		GOTO_EXIT(EXIT_FAILURE);
	}

	log = chassis_log_new();
	chassis_log_set_default(log, NULL, G_LOG_LEVEL_CRITICAL); /* default to stderr for everything that is critical */

	g_log_set_default_handler(chassis_log_func, log);

#ifdef _WIN32
	if (chassis_frontend_init_win32()) { /* setup winsock */
		GOTO_EXIT(EXIT_FAILURE);
	}
#endif

	/* may fail on library mismatch */
	if (NULL == (srv = chassis_new())) {
		GOTO_EXIT(EXIT_FAILURE);
	}

	srv->log = log; /* we need the log structure for the log-rotation */

	frontend = chassis_frontend_new();
	option_ctx = g_option_context_new("- MySQL Proxy");

	/**
	 * parse once to get the basic options like --defaults-file and --version
	 *
	 * leave the unknown options in the list
	 */
	if (chassis_frontend_init_base_options(option_ctx,
				&argc, &argv,
				&(frontend->print_version),
				&(frontend->default_file),
				&gerr)) {
		g_critical("%s: %s",
				G_STRLOC,
				gerr->message);
		g_clear_error(&gerr);

		GOTO_EXIT(EXIT_FAILURE);
	}

	if (frontend->default_file) {
		if (!(frontend->keyfile = chassis_frontend_open_config_file(frontend->default_file, &gerr))) {
			g_critical("%s: loading config from '%s' failed: %s",
					G_STRLOC,
					frontend->default_file,
					gerr->message);
			g_clear_error(&gerr);
			GOTO_EXIT(EXIT_FAILURE);
		}
	}

	/* print the main version number here, but don't exit
	 * we check for print_version again, after loading the plugins (if any)
	 * and print their version numbers, too. then we exit cleanly.
	 */
	if (frontend->print_version) {
#ifndef CHASSIS_BUILD_TAG
#define CHASSIS_BUILD_TAG PACKAGE_STRING
#endif
		g_print("%s" CHASSIS_NEWLINE, CHASSIS_BUILD_TAG); 
		chassis_frontend_print_version();
	}
	
	/* add the other options which can also appear in the configfile */
	opts = chassis_options_new();
	chassis_frontend_set_chassis_options(frontend, opts);
	main_entries = chassis_options_to_g_option_entries(opts);
	g_option_context_add_main_entries(option_ctx, main_entries, NULL);

	/**
	 * parse once to get the basic options 
	 *
	 * leave the unknown options in the list
	 */
	if (FALSE == g_option_context_parse(option_ctx, &argc, &argv, &gerr)) {
		g_critical("%s", gerr->message);

		GOTO_EXIT(EXIT_FAILURE);
	}

	if (frontend->keyfile) {
		if (chassis_keyfile_to_options(frontend->keyfile, "mysql-proxy", main_entries)) {
			GOTO_EXIT(EXIT_FAILURE);
		}
	}


	if (chassis_frontend_init_basedir(argv[0], &(frontend->base_dir))) {
		GOTO_EXIT(EXIT_FAILURE);
	}

	/* basic setup is done, base-dir is known, ... */
	frontend->lua_subdirs = g_new(char *, 2);
	frontend->lua_subdirs[0] = g_strdup("mysql-proxy");
	frontend->lua_subdirs[1] = NULL;

	if (chassis_frontend_init_lua_path(frontend->lua_path, frontend->base_dir, frontend->lua_subdirs)) {
		GOTO_EXIT(EXIT_FAILURE);
	}
	
	if (chassis_frontend_init_lua_cpath(frontend->lua_cpath, frontend->base_dir, frontend->lua_subdirs)) {
		GOTO_EXIT(EXIT_FAILURE);
	}

	/* assign the mysqld part to the */
	network_mysqld_init(srv); /* starts the also the lua-scope, LUA_PATH and LUA_CPATH have to be set before this being called */


#ifdef HAVE_SIGACTION
	/* register the sigsegv interceptor */

	memset(&sigsegv_sa, 0, sizeof(sigsegv_sa));
	sigsegv_sa.sa_handler = sigsegv_handler;
	sigemptyset(&sigsegv_sa.sa_mask);

	if (frontend->invoke_dbg_on_crash && !(RUNNING_ON_VALGRIND)) {
		sigaction(SIGSEGV, &sigsegv_sa, NULL);
	}
#endif

	/*
	 * some plugins cannot see the chassis struct from the point
	 * where they open files, hence we must make it available
	 */
	srv->base_dir = g_strdup(frontend->base_dir);

	chassis_frontend_init_plugin_dir(&frontend->plugin_dir, srv->base_dir);
	
	/* 
	 * these are used before we gathered all the options
	 * from the plugins, thus we need to fix them up before
	 * dealing with all the rest.
	 */
	chassis_resolve_path(srv->base_dir, &frontend->log_config_filename);
	chassis_resolve_path(srv->base_dir, &frontend->log_filename);
	chassis_resolve_path(srv->base_dir, &frontend->pid_file);
	chassis_resolve_path(srv->base_dir, &frontend->plugin_dir);

	/*
	 * start the logging
	 *
	 * If we have a log config file, it takes precendence before the simple other log-* options.
	 */

	if (frontend->log_filename && frontend->use_syslog) {
		g_critical("%s: log-file and log-use-syslog were given, but only one is allowed",
				G_STRLOC);
		GOTO_EXIT(EXIT_FAILURE);
	}

	if (frontend->log_config_filename) {
		if (FALSE == chassis_log_load_config(log, frontend->log_config_filename, &gerr)) {
			g_critical("%s: reading log-config from %s failed: %s",
					G_STRLOC,
					frontend->log_config_filename,
					gerr->message);
			g_clear_error(&gerr);

			GOTO_EXIT(EXIT_FAILURE);
		}

		/* the system should now be set up, let's try to log something */
		g_message("this should go to the root logger on level message");
	} else {
		/* set a default config */
		chassis_log_backend_t *backend;
		chassis_log_domain_t *domain;
		GLogLevelFlags log_lvl = G_LOG_LEVEL_CRITICAL;

		/* handle log-level after the config-file is read, just in case it is specified in the file */
		if (frontend->log_level) {
			log_lvl = chassis_log_level_string_to_level(frontend->log_level);

			if (0 == log_lvl) {
				g_critical("--log-level=... failed, level '%s' is unknown ",
						frontend->log_level);

				GOTO_EXIT(EXIT_FAILURE);
			}
		}

		if (frontend->log_filename) {
			backend = chassis_log_backend_file_new(frontend->log_filename);
		} else if (frontend->use_syslog) {
			backend = chassis_log_backend_syslog_new();
#ifdef _WIN32
		} else if (chassis_win32_is_service()) {
			backend = chassis_log_backend_eventlog_new();
#endif
		} else {
			backend = chassis_log_backend_stderr_new();
		}
		chassis_log_register_backend(log, backend);

		domain = chassis_log_domain_new(CHASSIS_LOG_DEFAULT_DOMAIN, log_lvl, backend);
		chassis_log_register_domain(log, domain);
	}

	/*
	 * the MySQL Proxy should load 'admin' and 'proxy' plugins
	 */
	if (!frontend->plugin_names) {
		frontend->plugin_names = g_new(char *, 3);

		frontend->plugin_names[0] = g_strdup("admin");
		frontend->plugin_names[1] = g_strdup("proxy");
		frontend->plugin_names[2] = NULL;
	}