int main(int argc, char **argv) { network_mysqld_table *table; /* read the command-line options */ GOptionContext *option_ctx; GOptionGroup *option_grp; GError *gerr = NULL; int i; int exit_code = 0; int print_version = 0; int daemon_mode = 0; int start_proxy = 1; const gchar *check_str = NULL; gchar *partition_info_host = NULL; gchar *partition_info_db = NULL; gchar *db_user = NULL; gchar *db_passwd = NULL; gchar *config_file = NULL; gchar *log_file = NULL; gchar *max_conn_pool = NULL; int log_all_queries = 0; int log_debug_msgs = 0; int log_raw_data = 0; GOptionEntry admin_entries[] = { { "admin-address", 'a', 0, G_OPTION_ARG_STRING, NULL, "listening address:port of internal admin-server (default: :4041)", "<host:port>"}, { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL} }; GOptionEntry proxy_entries[] = { { "proxy-address", 'p', 0, G_OPTION_ARG_STRING, NULL, "listening address:port of the proxy-server (default: :4040)", "<host:port>"}, { "partition-info-host", 'h', 0, G_OPTION_ARG_STRING, NULL, "host name of table partition info (default: not set)", "<host>"}, { "partition-info-database", 'd', 0, G_OPTION_ARG_STRING, NULL, "database name of table partition info (default: not set)", "<database>"}, { "db-user", 'u', 0, G_OPTION_ARG_STRING, NULL, "db user for connecting to the proxy and database partititons (default: not set)", "<userid>"}, { "db-user-password", 'P', 0, G_OPTION_ARG_STRING, NULL, "db user password for connecting to the proxy and database partititons (default: not set)", "password"}, { "proxy-skip-profiling", 0, G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, NULL, "disables profiling of queries (default: enabled)", NULL}, { "proxy-fix-bug-25371", 0, 0, G_OPTION_ARG_NONE, NULL, "fix bug #25371 (mysqld > 5.1.12) for older libmysql versions", NULL}, { "proxy-lua-script", 0, 0, G_OPTION_ARG_STRING, NULL, "filename of the lua script (default: not set)", "<file>"}, { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL} }; GOptionEntry main_entries[] = { { "version", 'V', 0, G_OPTION_ARG_NONE, NULL, "Show version", NULL}, { "daemon", 'D', 0, G_OPTION_ARG_NONE, NULL, "Start in daemon-mode", NULL}, { "pid-file", 0, 0, G_OPTION_ARG_STRING, NULL, "PID file in case we are started as daemon", "<file>"}, { "config-file", 'c', 0, G_OPTION_ARG_STRING, NULL, "configuration file (default is ./xxfs_dbproxy.conf)", "<file>"}, { "log-file", 'l', 0, G_OPTION_ARG_STRING, NULL, "log file (default is not set, using syslog)", "<file>"}, { "max-conn-pool-size", 'm', 0, G_OPTION_ARG_STRING, NULL, "max backend connections for each shard(default: 50)", "<number>"}, { "log-all-queries", 'L', 0, G_OPTION_ARG_NONE, NULL, "Log all queries(default: disabled)", NULL}, { "log-debug-messages", 'g', 0, G_OPTION_ARG_NONE, NULL, "Log debug messages(default: disabled)", NULL}, { "log-raw-data", 'r', 0, G_OPTION_ARG_NONE, NULL, "Log raw data sent/recved(default: disabled)", NULL}, { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL} }; if (!GLIB_CHECK_VERSION(2, 6, 0)) { log_error("the glib header are too old, need at least 2.6.0, got: %d.%d.%d", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION); } check_str = glib_check_version(GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION); if (check_str) { log_error("%s, got: lib=%d.%d.%d, headers=%d.%d.%d", check_str, glib_major_version, glib_minor_version, glib_micro_version, GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION); } srv = network_mysqld_init(); srv->config.network_type = NETWORK_TYPE_PROXY; /* doesn't matter anymore */ srv->config.proxy.fix_bug_25371 = 0; /** double ERR packet on AUTH failures */ srv->config.proxy.profiling = 1; srv->config.proxy.log_debug_messages = 1; set_debug_msg_logging(true); i = 0; admin_entries[i++].arg_data = &(srv->config.admin.address); i = 0; proxy_entries[i++].arg_data = &(srv->config.proxy.address); proxy_entries[i++].arg_data = &partition_info_host; proxy_entries[i++].arg_data = &partition_info_db; proxy_entries[i++].arg_data = &db_user; proxy_entries[i++].arg_data = &db_passwd; proxy_entries[i++].arg_data = &(srv->config.proxy.profiling); proxy_entries[i++].arg_data = &(srv->config.proxy.fix_bug_25371); proxy_entries[i++].arg_data = &(srv->config.proxy.lua_script); i = 0; main_entries[i++].arg_data = &(print_version); main_entries[i++].arg_data = &(daemon_mode); main_entries[i++].arg_data = &(srv->config.pid_file); main_entries[i++].arg_data = &config_file; main_entries[i++].arg_data = &log_file; main_entries[i++].arg_data = &max_conn_pool; main_entries[i++].arg_data = &log_all_queries; main_entries[i++].arg_data = &log_debug_msgs; main_entries[i++].arg_data = &log_raw_data; option_ctx = g_option_context_new("- SpockProxy"); g_option_context_add_main_entries(option_ctx, main_entries, GETTEXT_PACKAGE); option_grp = g_option_group_new("admin", "admin module", "Show options for the admin-module", NULL, NULL); g_option_group_add_entries(option_grp, admin_entries); g_option_context_add_group(option_ctx, option_grp); option_grp = g_option_group_new("proxy", "proxy-module", "Show options for the proxy-module", NULL, NULL); g_option_group_add_entries(option_grp, proxy_entries); g_option_context_add_group(option_ctx, option_grp); if (FALSE == g_option_context_parse(option_ctx, &argc, &argv, &gerr)) { log_error("%s", gerr->message); g_error_free(gerr); return -1; } g_option_context_free(option_ctx); if (config_file && config_file[0] != '\0') load_config_file(config_file); else load_config_file("xxfs_dbproxy.conf"); add_config_string("PARTITION_INFO_HOST", partition_info_host); add_config_string("PARTITION_INFO_DB", partition_info_db); add_config_string("DB_USER", db_user); add_config_string("DB_PASSWD", db_passwd); add_config_string("LOGFILE", log_file); add_config_string("MAX_CONN_POOL_SIZE", max_conn_pool); add_config_string("LOG_ALL_QUERIES", log_all_queries ? "1" : "0"); add_config_string("LOG_DEBUG_MSG", log_debug_msgs ? "1" : "0"); add_config_string("LOG_RAW_DATA", log_raw_data ? "1" : "0"); if (srv->config.admin.address == NULL) srv->config.admin.address = g_strdup(get_config_string("ADMIN_ADDRESS")); if (srv->config.proxy.address == NULL) srv->config.proxy.address = g_strdup(get_config_string("PROXY_ADDRESS")); srv->config.proxy.profiling = get_config_int("SKIP_PROFILING", srv->config.proxy.profiling); srv->config.proxy.fix_bug_25371 = get_config_int("FIX_BUG_25371", srv->config.proxy.fix_bug_25371); if (srv->config.proxy.lua_script == NULL) srv->config.proxy.lua_script = get_config_string("LUA_SCRIPT"); srv->config.proxy.log_debug_messages = get_config_int("LOG_DEBUG_MSG", srv->config.proxy.log_debug_messages); set_debug_msg_logging(srv->config.proxy.log_debug_messages); print_version = get_config_int("PRINT_PROXY_VERSION", print_version); daemon_mode = get_config_int("DAEMON_MODE", daemon_mode); if (srv->config.pid_file == NULL) srv->config.pid_file = get_config_string("PID_FILE"); #if defined(HAVE_LUA_H) && defined(LIBDIR) /** * if the LUA_PATH is not set, set a good default */ if (!g_getenv("LUA_PATH")) { g_setenv("LUA_PATH", LUA_PATHSEP LUA_PATHSEP LIBDIR "/?.lua", 1); } #endif if (print_version) { printf("%s, build time: %s %s\r\n", PACKAGE_STRING, __DATE__, __TIME__); return 0; } log_info("%s, build time: %s %s\r\n", PACKAGE_STRING, __DATE__, __TIME__); if(database_lookup_load() <0) exit(0); if (start_proxy) { if (!srv->config.proxy.address) srv->config.proxy.address = g_strdup(":4040"); if (!srv->config.proxy.backend_addresses) { srv->config.proxy.backend_addresses = g_new0(char *, 2); srv->config.proxy.backend_addresses[0] = g_strdup("127.0.0.1:3306"); } }
/** * 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; }
/** * 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; }
/** * 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_log_dbproxy(g_critical, "%s", 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_log_dbproxy(g_critical, "loading config from '%s' failed: %s", 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) { g_print("%s" CHASSIS_NEWLINE, CHASSIS_BUILD_TAG); g_print(" glib2: %d.%d.%d" CHASSIS_NEWLINE, GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION); g_print(" libevent: %s" CHASSIS_NEWLINE, event_get_version()); GOTO_EXIT(EXIT_SUCCESS); } /* 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); srv->opts = opts; /** * parse once to get the basic options * * leave the unknown options in the list */ g_option_context_set_help_enabled(option_ctx, TRUE); if (FALSE == g_option_context_parse(option_ctx, &argc, &argv, &gerr)) { g_log_dbproxy(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); } /* make sure that he max-thread-count isn't negative */ if (frontend->event_thread_count < 1) { g_log_dbproxy(g_critical, "--event-threads has to be >= 1, is %d", frontend->event_thread_count); GOTO_EXIT(EXIT_FAILURE); } srv->event_thread_count = frontend->event_thread_count; if (frontend->wait_timeout < 0) { g_log_dbproxy(g_critical, "--wait-timeout has to be >= 0, is %d", frontend->wait_timeout); GOTO_EXIT(EXIT_FAILURE); } srv->wait_timeout = frontend->wait_timeout; if (frontend->shutdown_timeout < 1) { g_log_dbproxy(g_critical, "--shutdown-timeout has to be >= 1, is %d", frontend->shutdown_timeout); GOTO_EXIT(EXIT_FAILURE); } srv->shutdown_timeout = frontend->shutdown_timeout; if (frontend->db_connection_idle_timeout < 0) { g_log_dbproxy(g_critical, "--db-connection-idle-timeout has to be >= 0, is %d", frontend->db_connection_idle_timeout); GOTO_EXIT(EXIT_FAILURE); } srv->db_connection_idle_timeout = frontend->db_connection_idle_timeout; if (frontend->db_connection_max_age < 0) { g_log_dbproxy(g_critical, "--db-connection-max-age has to be >= 0, is %d", frontend->db_connection_max_age); GOTO_EXIT(EXIT_FAILURE); } srv->db_connection_max_age = frontend->db_connection_max_age; if (frontend->mysql_version == NULL || strcmp(frontend->mysql_version, "5.5") == 0) { srv->my_version = MYSQL_55; } else if (frontend->mysql_version == NULL || strcmp(frontend->mysql_version, "5.6") == 0) { srv->my_version = MYSQL_56; } else { g_log_dbproxy(g_critical, "--mysql-version has to be 5.6 or 5.5, is %s", frontend->mysql_version); GOTO_EXIT(EXIT_FAILURE); } if (frontend->max_connections < 0) { g_log_dbproxy(g_critical, "--max-connections has to be >= 0, is %d", frontend->max_connections); GOTO_EXIT(EXIT_FAILURE); } srv->proxy_max_connections = frontend->max_connections; if (frontend->long_wait_time < 0) { g_log_dbproxy(g_critical, "--long-wait-time has to be >= 0, is %d", frontend->long_wait_time); GOTO_EXIT(EXIT_FAILURE); } srv->long_wait_time = frontend->long_wait_time; if (frontend->long_query_time < 0) { g_log_dbproxy(g_critical, "--long-query-time has to be >= 0, is %d", frontend->long_query_time); GOTO_EXIT(EXIT_FAILURE); } srv->long_query_time = frontend->long_query_time; if (frontend->query_response_time_stats < 0) { g_log_dbproxy(g_critical, "--query-response-time-stats has to be >= 0, is %d", frontend->query_response_time_stats); GOTO_EXIT(EXIT_FAILURE); } srv->query_response_time_stats = frontend->query_response_time_stats; if (frontend->query_response_time_stats > 1 && frontend->query_response_time_range_base < 2) { g_log_dbproxy(g_critical, "--query-response-time-range-base has to be >= 2, is %d", frontend->query_response_time_range_base); GOTO_EXIT(EXIT_FAILURE); } srv->query_response_time_range_base = frontend->query_response_time_range_base; if (frontend->lastest_query_num < 0) { g_log_dbproxy(g_critical, "--lastest-query-num has to be >= 0, is %d", frontend->lastest_query_num); GOTO_EXIT(EXIT_FAILURE); } srv->proxy_reserved->lastest_query_num = frontend->lastest_query_num; if (frontend->query_filter_time_threshold < -1) { g_log_dbproxy(g_critical, "--query-filter-time-threshold has to be >= -1, is %d", frontend->query_filter_time_threshold); GOTO_EXIT(EXIT_FAILURE); } srv->proxy_reserved->query_filter_time_threshold = frontend->query_filter_time_threshold; if (frontend->query_filter_frequent_threshold < 0) { g_log_dbproxy(g_critical, "--query-filter-frequent-threshold has to be >= 0, is %f", frontend->query_filter_frequent_threshold); GOTO_EXIT(EXIT_FAILURE); } srv->proxy_reserved->query_filter_frequent_threshold = frontend->query_filter_frequent_threshold; if (frontend->access_num_per_time_window < 1) { g_log_dbproxy(g_critical, "--freq-access-num-threshold has to be >= 1, is %d", frontend->access_num_per_time_window); GOTO_EXIT(EXIT_FAILURE); } srv->proxy_reserved->access_num_per_time_window = frontend->access_num_per_time_window; int flag = 0; if (frontend->auto_filter_flag == NULL || strcasecmp(frontend->auto_filter_flag, "OFF") == 0) flag = 0; else if (strcasecmp(frontend->auto_filter_flag, "ON") == 0) flag = 1; else { g_log_dbproxy(g_critical, "--auto-filter-flag has to be on or off, is %s", frontend->auto_filter_flag); GOTO_EXIT(EXIT_FAILURE); } srv->proxy_filter->auto_filter_flag = flag; if (frontend->manual_filter_flag == NULL || strcasecmp(frontend->manual_filter_flag, "OFF") == 0) flag = 0; else if (strcasecmp(frontend->manual_filter_flag, "ON") == 0) flag = 1; else { g_log_dbproxy(g_critical, "--manual-filter-flag has to be on or off, is %s", frontend->manual_filter_flag); GOTO_EXIT(EXIT_FAILURE); } srv->proxy_filter->manual_filter_flag = flag; if (frontend->max_backend_tr < 0) { g_log_dbproxy(g_critical, "--backend-max-thread-running has to be >= 0, is %d", frontend->max_backend_tr); GOTO_EXIT(EXIT_FAILURE); } srv->max_backend_tr = frontend->max_backend_tr; if (frontend->thread_running_sleep_delay < 1) { g_log_dbproxy(g_critical, "--thread-running-sleep-delay has to be >= 1, is %d", frontend->thread_running_sleep_delay); GOTO_EXIT(EXIT_FAILURE); } srv->thread_running_sleep_delay = frontend->thread_running_sleep_delay; if (frontend->remove_backend_timeout < 0) { g_log_dbproxy(g_critical, "--remove-backend-timeout has to be >= 0, is %d", frontend->remove_backend_timeout); GOTO_EXIT(EXIT_FAILURE); } /* assign the mysqld part to the */ network_mysqld_init(srv, frontend->default_file, frontend->remove_backend_timeout); /* 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); sigaction(SIGSEGV, &sigsegv_sa, NULL); #ifdef SIGBUS sigaction(SIGBUS, &sigsegv_sa, NULL); #endif sigaction(SIGILL, &sigsegv_sa, NULL); sigaction(SIGFPE, &sigsegv_sa, NULL); /*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. */ if (chassis_frontend_init_logdir(frontend->log_path)) { GOTO_EXIT(EXIT_FAILURE); } chassis_resolve_path(srv->base_dir, &frontend->log_path); chassis_resolve_path(srv->base_dir, &frontend->plugin_dir); /* * start the logging and pid */ if (frontend->log_path) { if (frontend->instance_name == NULL) { gchar *default_file = frontend->default_file; gchar *slash = strrchr(default_file, '/'); if (slash != NULL) ++slash; else slash = default_file; gchar *dot = strrchr(default_file, '.'); if (dot != NULL && dot >= slash) frontend->instance_name = g_strndup(slash, dot-slash); else frontend->instance_name = g_strdup(slash); } log->log_filename = g_strdup_printf("%s/%s.log", frontend->log_path, frontend->instance_name); frontend->pid_file = g_strdup_printf("%s/%s.pid", frontend->log_path, frontend->instance_name); srv->log_path = g_strdup(frontend->log_path); } log->use_syslog = frontend->use_syslog; if (log->log_filename && log->use_syslog) { g_log_dbproxy(g_critical, "log-file and log-use-syslog were given, but only one is allowed"); GOTO_EXIT(EXIT_FAILURE); } /* * we have to drop root privileges in chassis_mainloop() after * the plugins opened the ports, so we need the user there */ if (frontend->user) { srv->user = g_strdup(frontend->user); } /** * create the path of sql and its parents path if it is necessary */ gchar *sql_path = g_strdup_printf("%s/%s", srv->log_path, SQL_LOG_DIR); if(g_mkdir_with_parents(sql_path, S_IRWXU|S_IRWXG|S_IRWXO) != 0) { g_log_dbproxy(g_critical, "g_mkdir_with_parents(%s) failed: %s", sql_path, g_strerror(errno)); g_free(sql_path); GOTO_EXIT(EXIT_FAILURE); } g_free(sql_path); /* * check whether we should drop root privileges */ #ifndef _win32 if (srv->user) { struct passwd *user_info; uid_t user_id= geteuid(); /* Don't bother if we aren't superuser */ if (user_id) { g_log_dbproxy(g_warning, "current user is not root, --user is ignored"); } else { if (NULL == (user_info = getpwnam(srv->user))) { g_log_dbproxy(g_critical, "unknown user: %s", srv->user); return -1; } /* chown log-path */ if (-1 == chown_recursion(srv->log_path, user_info->pw_uid, user_info->pw_gid)) { g_log_dbproxy(g_critical, "chown_recursion(%s) failed: %s", srv->log_path, g_strerror(errno)); GOTO_EXIT(EXIT_FAILURE); } setgid(user_info->pw_gid); setuid(user_info->pw_uid); g_log_dbproxy(g_debug, "running as user: %s (%d/%d)", srv->user, user_info->pw_uid, user_info->pw_gid); /*check the config file can read or write, and the config file dir can execute*/ gchar *config_file = frontend->default_file; /*if the config_file is relative get the real path */ char resolved_path[PATH_MAX]; if (g_path_is_absolute(config_file) == FALSE) { realpath(config_file, resolved_path); config_file = resolved_path; } gchar *config_dir = g_path_get_dirname(config_file); if (-1 == faccessat(0, config_file, R_OK | W_OK, AT_EACCESS) || -1 == faccessat(0, config_dir, X_OK | W_OK, AT_EACCESS)) { g_free(config_dir); g_log_dbproxy(g_critical, "%s don't have correct privilege for the user %s set in the config file, config file should have read write privileges and the config file dir should have execute and write privilege.", config_file, srv->user); GOTO_EXIT(EXIT_FAILURE); } g_free(config_dir); g_log_dbproxy(g_message, "running as user: %s (%d/%d)", srv->user, user_info->pw_uid, user_info->pw_gid); } } #endif if (log->log_filename && FALSE == chassis_log_open(log)) { g_log_dbproxy(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_log_dbproxy(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; } if (frontend->log_trace_modules < 0) { g_log_dbproxy(g_critical, "log-trace-modules has to be >= 0, is %d", frontend->log_trace_modules); GOTO_EXIT(EXIT_FAILURE); } srv->log->log_trace_modules = frontend->log_trace_modules; if(frontend->db_connect_timeout < 0) { g_log_dbproxy(g_critical, "db_connect_timeout has to be >= 0.0, is %lf", frontend->db_connect_timeout); GOTO_EXIT(EXIT_FAILURE); } srv->db_connect_timeout = frontend->db_connect_timeout; /* * 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; }