2
Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
4
This program is free software; you can redistribute it and/or
5
modify it under the terms of the GNU General Public License as
6
published by the Free Software Foundation; version 2 of the
9
This program is distributed in the hope that it will be useful,
10
but WITHOUT ANY WARRANTY; without even the implied warranty of
11
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
GNU General Public License for more details.
14
You should have received a copy of the GNU General Public License
15
along with this program; if not, write to the Free Software
16
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
1
/* Copyright (C) 2007 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
19
* \section Architecture
21
* MySQL Proxy is based around the C10k problem as described by http://kegel.com/c10k.html
23
* This leads to some basic features
24
* - 10.000 concurrent connections in one program
25
* - spreading the load over several backends
26
* - each backend might be able to only handle 100 connections (max_connections)
29
* - reusing idling backend connections
30
* - splitting client connections into several backend connections
32
* Most of the magic is happening in the scripting layer provided by lua (http://lua.org/) which
35
* - is very easy to embed
36
* - is small (200kb stripped) and efficient (see http://shootout.alioth.debian.org/gp4/benchmark.php?test=all&lang=all)
37
* - is easy to read and write
39
* \section a walk through the code
41
* To understand the code you basicly only have to know about the three files documented below:
45
* -# command-line handling
49
* - network_mysqld_thread() (supposed be called as thread)
50
* -# registers event-halders (event_set(..., network_mysqld_con_accept, ...))
51
* -# calls event_base_dispatch() [libevent] in the mainloop
52
* - network_mysqld_con_accept()
53
* -# is called when the listen()ing socket gets a incoming connection
54
* -# sets the event-handler for the established connection (e.g. network_mysqld_proxy_connection_init())
55
* -# calls network_mysqld_con_handle() on the connection
56
* - network_mysqld_con_handle() is the state-machine
57
* -# implements the states of the \ref protocol "MySQL Protocol"
58
* -# calls plugin functions (registered by e.g. network_mysqld_proxy_connection_init())
59
* - network-mysqld-proxy.c
60
* - implements the \ref proxy_states "proxy specific states"
62
* The other files only help those based main modules to do their job:
64
* - network-mysqld-proto.c
65
* - the byte functions around the \ref proto "MySQL protocol"
67
* - basic socket struct
68
* - network-mysqld-table.c
69
* - internal tables to select from on the admin interface (to be removed)
70
* - \ref sql-tokenizer.h "sql-tokenizer.y"
71
* - a flex based tokenizer for MySQL's SQL dialect (no parser)
72
* - network-conn-pool.c
73
* - a connection pool for server connections
22
78
* the user-interface for the MySQL Proxy @see main()
79
124
#include "chassis-log.h"
80
125
#include "chassis-keyfile.h"
81
126
#include "chassis-mainloop.h"
82
#include "chassis-path.h"
83
#include "chassis-limits.h"
84
#include "chassis-filemode.h"
85
#include "chassis-win32-service.h"
86
#include "chassis-unix-daemon.h"
87
#include "chassis-frontend.h"
88
#include "chassis-options.h"
91
#define CHASSIS_NEWLINE "\r\n"
93
#define CHASSIS_NEWLINE "\n"
129
* turn a GTimeVal into string
131
* @return string in ISO notation with micro-seconds
133
static gchar * g_timeval_string(GTimeVal *t1, GString *str) {
136
g_string_set_size(str, 63);
138
used_len = strftime(str->str, str->allocated_len, "%Y-%m-%dT%H:%M:%S", gmtime(&t1->tv_sec));
140
g_assert(used_len < str->allocated_len);
143
g_string_append_printf(str, ".%06ld", t1->tv_usec);
152
* start the app in the background
156
static void daemonize(void) {
158
signal(SIGTTOU, SIG_IGN);
161
signal(SIGTTIN, SIG_IGN);
164
signal(SIGTSTP, SIG_IGN);
166
if (fork() != 0) exit(0);
168
if (setsid() == -1) exit(0);
170
signal(SIGHUP, SIG_IGN);
172
if (fork() != 0) exit(0);
96
181
#define GETTEXT_PACKAGE "mysql-proxy"
99
* options of the MySQL Proxy frontend
103
int verbose_shutdown;
115
GOptionEntry *config_entries;
120
gchar **plugin_names;
122
guint invoke_dbg_on_crash;
124
/* the --keepalive option isn't available on Unix */
128
gint max_files_number;
130
gint event_thread_count;
139
} chassis_frontend_t;
142
* create a new the frontend for the chassis
144
chassis_frontend_t *chassis_frontend_new(void) {
145
chassis_frontend_t *frontend;
147
frontend = g_slice_new0(chassis_frontend_t);
148
frontend->event_thread_count = 1;
149
frontend->max_files_number = 0;
155
* free the frontend of the chassis
157
void chassis_frontend_free(chassis_frontend_t *frontend) {
158
if (!frontend) return;
160
if (frontend->keyfile) g_key_file_free(frontend->keyfile);
161
if (frontend->default_file) g_free(frontend->default_file);
164
if (frontend->base_dir) g_free(frontend->base_dir);
165
if (frontend->user) g_free(frontend->user);
166
if (frontend->pid_file) g_free(frontend->pid_file);
167
if (frontend->log_level) g_free(frontend->log_level);
168
if (frontend->plugin_dir) g_free(frontend->plugin_dir);
170
if (frontend->plugin_names) {
171
g_strfreev(frontend->plugin_names);
174
if (frontend->lua_path) g_free(frontend->lua_path);
175
if (frontend->lua_cpath) g_free(frontend->lua_cpath);
176
if (frontend->lua_subdirs) g_strfreev(frontend->lua_subdirs);
178
g_slice_free(chassis_frontend_t, frontend);
182
* setup the options of the chassis
184
int chassis_frontend_set_chassis_options(chassis_frontend_t *frontend, chassis_options_t *opts) {
185
chassis_options_add(opts,
186
"verbose-shutdown", 0, 0, G_OPTION_ARG_NONE, &(frontend->verbose_shutdown), "Always log the exit code when shutting down", NULL);
188
chassis_options_add(opts,
189
"daemon", 0, 0, G_OPTION_ARG_NONE, &(frontend->daemon_mode), "Start in daemon-mode", NULL);
192
chassis_options_add(opts,
193
"user", 0, 0, G_OPTION_ARG_STRING, &(frontend->user), "Run mysql-proxy as user", "<user>");
196
chassis_options_add(opts,
197
"basedir", 0, 0, G_OPTION_ARG_STRING, &(frontend->base_dir), "Base directory to prepend to relative paths in the config", "<absolute path>");
199
chassis_options_add(opts,
200
"pid-file", 0, 0, G_OPTION_ARG_STRING, &(frontend->pid_file), "PID file in case we are started as daemon", "<file>");
202
chassis_options_add(opts,
203
"plugin-dir", 0, 0, G_OPTION_ARG_STRING, &(frontend->plugin_dir), "path to the plugins", "<path>");
205
chassis_options_add(opts,
206
"plugins", 0, 0, G_OPTION_ARG_STRING_ARRAY, &(frontend->plugin_names), "plugins to load", "<name>");
208
chassis_options_add(opts,
209
"log-level", 0, 0, G_OPTION_ARG_STRING, &(frontend->log_level), "log all messages of level ... or higher", "(error|warning|info|message|debug)");
211
chassis_options_add(opts,
212
"log-file", 0, 0, G_OPTION_ARG_STRING, &(frontend->log_filename), "log all messages in a file", "<file>");
214
chassis_options_add(opts,
215
"log-use-syslog", 0, 0, G_OPTION_ARG_NONE, &(frontend->use_syslog), "log all messages to syslog", NULL);
217
chassis_options_add(opts,
218
"log-backtrace-on-crash", 0, 0, G_OPTION_ARG_NONE, &(frontend->invoke_dbg_on_crash), "try to invoke debugger on crash", NULL);
221
chassis_options_add(opts,
222
"keepalive", 0, 0, G_OPTION_ARG_NONE, &(frontend->auto_restart), "try to restart the proxy if it crashed", NULL);
225
chassis_options_add(opts,
226
"max-open-files", 0, 0, G_OPTION_ARG_INT, &(frontend->max_files_number), "maximum number of open files (ulimit -n)", NULL);
228
chassis_options_add(opts,
229
"event-threads", 0, 0, G_OPTION_ARG_INT, &(frontend->event_thread_count), "number of event-handling threads (default: 1)", NULL);
231
chassis_options_add(opts,
232
"lua-path", 0, 0, G_OPTION_ARG_STRING, &(frontend->lua_path), "set the LUA_PATH", "<...>");
234
chassis_options_add(opts,
235
"lua-cpath", 0, 0, G_OPTION_ARG_STRING, &(frontend->lua_cpath), "set the LUA_CPATH", "<...>");
241
static void sigsegv_handler(int G_GNUC_UNUSED signum) {
242
g_on_error_stack_trace(g_get_prgname());
244
abort(); /* trigger a SIGABRT instead of just exiting */
248
* This is the "real" main which is called both on Windows and UNIX platforms.
249
* For the Windows service case, this will also handle the notifications and set
250
* up the logging support appropriately.
252
int main_cmdline(int argc, char **argv) {
254
#ifdef HAVE_SIGACTION
255
static struct sigaction sigsegv_sa;
183
int main(int argc, char **argv) {
257
186
/* read the command-line options */
258
GOptionContext *option_ctx = NULL;
259
GOptionEntry *main_entries = NULL;
260
chassis_frontend_t *frontend = NULL;
261
chassis_options_t *opts = NULL;
187
GOptionContext *option_ctx;
263
188
GError *gerr = NULL;
264
chassis_log *log = NULL;
266
/* a little helper macro to set the src-location that we stepped out at to exit */
267
#define GOTO_EXIT(status) \
268
exit_code = status; \
269
exit_location = G_STRLOC; \
272
190
int exit_code = EXIT_SUCCESS;
273
const gchar *exit_location = G_STRLOC;
275
if (chassis_frontend_init_glib()) { /* init the thread, module, ... system */
276
GOTO_EXIT(EXIT_FAILURE);
279
/* start the logging ... to stderr */
280
log = chassis_log_new();
281
log->min_lvl = G_LOG_LEVEL_MESSAGE; /* display messages while parsing or loading plugins */
191
int print_version = 0;
193
const gchar *check_str = NULL;
195
gchar *pid_file = NULL;
196
gchar *plugin_dir = NULL;
197
gchar *default_file = NULL;
198
GOptionEntry *config_entries;
199
gchar **plugin_names = NULL;
201
gchar *log_level = NULL;
203
GKeyFile *keyfile = NULL;
206
/* can't appear in the configfile */
207
GOptionEntry base_main_entries[] =
209
{ "version", 'V', 0, G_OPTION_ARG_NONE, NULL, "Show version", NULL },
210
{ "defaults-file", 0, 0, G_OPTION_ARG_STRING, NULL, "configuration file", "<file>" },
212
{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
215
GOptionEntry main_entries[] =
217
{ "daemon", 0, 0, G_OPTION_ARG_NONE, NULL, "Start in daemon-mode", NULL },
218
{ "pid-file", 0, 0, G_OPTION_ARG_STRING, NULL, "PID file in case we are started as daemon", "<file>" },
219
{ "plugin-dir", 0, 0, G_OPTION_ARG_STRING, NULL, "path to the plugins", "<path>" },
220
{ "plugins", 0, 0, G_OPTION_ARG_STRING_ARRAY, NULL, "plugins to load", "<name>" },
221
{ "log-level", 0, 0, G_OPTION_ARG_STRING, NULL, "log all messages of level ... or higer", "(error|warning|info|message|debug)" },
222
{ "log-file", 0, 0, G_OPTION_ARG_STRING, NULL, "log all messages in a file", "<file>" },
223
{ "log-use-syslog", 0, 0, G_OPTION_ARG_NONE, NULL, "send all log-messages to syslog", NULL },
225
{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
228
if (!GLIB_CHECK_VERSION(2, 6, 0)) {
229
g_error("the glib header are too old, need at least 2.6.0, got: %d.%d.%d",
230
GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
233
check_str = glib_check_version(GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
236
g_error("%s, got: lib=%d.%d.%d, headers=%d.%d.%d",
238
glib_major_version, glib_minor_version, glib_micro_version,
239
GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
242
if (!g_module_supported()) {
243
g_error("loading modules is not supported on this platform");
250
log = chassis_log_init();
282
252
g_log_set_default_handler(chassis_log_func, log);
285
if (chassis_win32_is_service() && chassis_log_set_event_log(log, g_get_prgname())) {
286
GOTO_EXIT(EXIT_FAILURE);
289
if (chassis_frontend_init_win32()) { /* setup winsock */
290
GOTO_EXIT(EXIT_FAILURE);
294
/* may fail on library mismatch */
295
if (NULL == (srv = chassis_new())) {
296
GOTO_EXIT(EXIT_FAILURE);
299
srv->log = log; /* we need the log structure for the log-rotation */
301
frontend = chassis_frontend_new();
302
option_ctx = g_option_context_new("- MySQL Proxy");
254
srv = chassis_init();
255
/* assign the mysqld part to the */
256
network_mysqld_init(srv);
259
base_main_entries[i++].arg_data = &(print_version);
260
base_main_entries[i++].arg_data = &(default_file);
263
main_entries[i++].arg_data = &(daemon_mode);
264
main_entries[i++].arg_data = &(pid_file);
265
main_entries[i++].arg_data = &(plugin_dir);
266
main_entries[i++].arg_data = &(plugin_names);
268
main_entries[i++].arg_data = &(log_level);
269
main_entries[i++].arg_data = &(log->log_filename);
270
main_entries[i++].arg_data = &(log->use_syslog);
272
option_ctx = g_option_context_new("- MySQL App Shell");
273
g_option_context_add_main_entries(option_ctx, base_main_entries, GETTEXT_PACKAGE);
274
g_option_context_set_help_enabled(option_ctx, FALSE);
275
g_option_context_set_ignore_unknown_options(option_ctx, TRUE);
304
278
* parse once to get the basic options like --defaults-file and --version
306
280
* leave the unknown options in the list
308
if (chassis_frontend_init_base_options(option_ctx,
310
&(frontend->print_version),
311
&(frontend->default_file),
316
g_clear_error(&gerr);
318
GOTO_EXIT(EXIT_FAILURE);
282
if (FALSE == g_option_context_parse(option_ctx, &argc, &argv, &gerr)) {
283
g_critical("%s", gerr->message);
285
exit_code = EXIT_FAILURE;
321
if (frontend->default_file) {
322
if (!(frontend->keyfile = chassis_frontend_open_config_file(frontend->default_file, &gerr))) {
323
g_critical("%s: loading config from '%s' failed: %s",
325
frontend->default_file,
290
keyfile = g_key_file_new();
291
g_key_file_set_list_separator(keyfile, ',');
293
if (FALSE == g_key_file_load_from_file(keyfile, default_file, G_KEY_FILE_NONE, &gerr)) {
294
g_critical("loading configuration from %s failed: %s",
327
g_clear_error(&gerr);
328
GOTO_EXIT(EXIT_FAILURE);
298
exit_code = EXIT_FAILURE;
332
/* print the main version number here, but don't exit
333
* we check for print_version again, after loading the plugins (if any)
334
* and print their version numbers, too. then we exit cleanly.
336
if (frontend->print_version) {
337
#ifndef CHASSIS_BUILD_TAG
338
#define CHASSIS_BUILD_TAG PACKAGE_STRING
304
printf("%s\r\n", PACKAGE_STRING);
305
printf(" glib2: %d.%d.%d\r\n", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION);
307
printf(" libevent: %s\r\n", event_get_version());
340
g_print("%s" CHASSIS_NEWLINE, CHASSIS_BUILD_TAG);
341
chassis_frontend_print_version();
310
exit_code = EXIT_SUCCESS;
344
315
/* add the other options which can also appear in the configfile */
345
opts = chassis_options_new();
346
chassis_frontend_set_chassis_options(frontend, opts);
347
main_entries = chassis_options_to_g_option_entries(opts);
348
g_option_context_add_main_entries(option_ctx, main_entries, NULL);
316
g_option_context_add_main_entries(option_ctx, main_entries, GETTEXT_PACKAGE);
351
319
* parse once to get the basic options
355
323
if (FALSE == g_option_context_parse(option_ctx, &argc, &argv, &gerr)) {
356
324
g_critical("%s", gerr->message);
358
GOTO_EXIT(EXIT_FAILURE);
361
if (frontend->keyfile) {
362
if (chassis_keyfile_to_options(frontend->keyfile, "mysql-proxy", main_entries)) {
363
GOTO_EXIT(EXIT_FAILURE);
368
if (chassis_frontend_init_basedir(argv[0], &(frontend->base_dir))) {
369
GOTO_EXIT(EXIT_FAILURE);
372
/* basic setup is done, base-dir is known, ... */
373
frontend->lua_subdirs = g_new(char *, 2);
374
frontend->lua_subdirs[0] = g_strdup("mysql-proxy");
375
frontend->lua_subdirs[1] = NULL;
377
if (chassis_frontend_init_lua_path(frontend->lua_path, frontend->base_dir, frontend->lua_subdirs)) {
378
GOTO_EXIT(EXIT_FAILURE);
381
if (chassis_frontend_init_lua_cpath(frontend->lua_cpath, frontend->base_dir, frontend->lua_subdirs)) {
382
GOTO_EXIT(EXIT_FAILURE);
385
/* assign the mysqld part to the */
386
network_mysqld_init(srv); /* starts the also the lua-scope, LUA_PATH and LUA_CPATH have to be set before this being called */
389
#ifdef HAVE_SIGACTION
390
/* register the sigsegv interceptor */
392
memset(&sigsegv_sa, 0, sizeof(sigsegv_sa));
393
sigsegv_sa.sa_handler = sigsegv_handler;
394
sigemptyset(&sigsegv_sa.sa_mask);
396
if (frontend->invoke_dbg_on_crash && !(RUNNING_ON_VALGRIND)) {
397
sigaction(SIGSEGV, &sigsegv_sa, NULL);
402
* some plugins cannot see the chassis struct from the point
403
* where they open files, hence we must make it available
405
srv->base_dir = g_strdup(frontend->base_dir);
407
chassis_frontend_init_plugin_dir(&frontend->plugin_dir, srv->base_dir);
410
* these are used before we gathered all the options
411
* from the plugins, thus we need to fix them up before
412
* dealing with all the rest.
414
chassis_resolve_path(srv->base_dir, &frontend->log_filename);
415
chassis_resolve_path(srv->base_dir, &frontend->pid_file);
416
chassis_resolve_path(srv->base_dir, &frontend->plugin_dir);
421
if (frontend->log_filename) {
422
log->log_filename = g_strdup(frontend->log_filename);
425
log->use_syslog = frontend->use_syslog;
427
if (log->log_filename && log->use_syslog) {
428
g_critical("%s: log-file and log-use-syslog were given, but only one is allowed",
430
GOTO_EXIT(EXIT_FAILURE);
433
if (log->log_filename && FALSE == chassis_log_open(log)) {
434
g_critical("can't open log-file '%s': %s", log->log_filename, g_strerror(errno));
436
GOTO_EXIT(EXIT_FAILURE);
439
/* handle log-level after the config-file is read, just in case it is specified in the file */
440
if (frontend->log_level) {
441
if (0 != chassis_log_set_level(log, frontend->log_level)) {
442
g_critical("--log-level=... failed, level '%s' is unknown ",
443
frontend->log_level);
445
GOTO_EXIT(EXIT_FAILURE);
448
/* if it is not set, use "critical" as default */
449
log->min_lvl = G_LOG_LEVEL_CRITICAL;
453
* the MySQL Proxy should load 'admin' and 'proxy' plugins
455
if (!frontend->plugin_names) {
456
frontend->plugin_names = g_new(char *, 3);
458
frontend->plugin_names[0] = g_strdup("admin");
459
frontend->plugin_names[1] = g_strdup("proxy");
460
frontend->plugin_names[2] = NULL;
463
if (chassis_frontend_load_plugins(srv->modules,
464
frontend->plugin_dir,
465
frontend->plugin_names)) {
466
GOTO_EXIT(EXIT_FAILURE);
469
if (chassis_frontend_init_plugins(srv->modules,
479
g_clear_error(&gerr);
481
GOTO_EXIT(EXIT_FAILURE);
485
/* if we only print the version numbers, exit and don't do any more work */
486
if (frontend->print_version) {
487
chassis_frontend_print_lua_version();
488
chassis_frontend_print_plugin_versions(srv->modules);
489
GOTO_EXIT(EXIT_SUCCESS);
326
exit_code = EXIT_FAILURE;
330
if (log->log_filename) {
331
if (0 != chassis_log_open(log)) {
332
g_critical("can't open log-file '%s': %s", log->log_filename, g_strerror(errno));
334
exit_code = EXIT_FAILURE;
340
if (0 != chassis_log_set_level(log, log_level)) {
341
g_critical("--log-level=... failed, level '%s' is unknown ", log_level);
343
exit_code = EXIT_FAILURE;
349
if (chassis_keyfile_to_options(keyfile, "mysql-proxy", main_entries)) {
350
exit_code = EXIT_FAILURE;
355
if (!plugin_dir) plugin_dir = g_strdup(LIBDIR);
357
/* if not plugins are specified, load admin and proxy */
359
plugin_names = g_new0(char *, 3);
361
#define IS_PNAME(pname) \
362
((strlen(argv[0]) > sizeof(pname) - 1) && \
363
0 == strcmp(argv[0] + strlen(argv[0]) - (sizeof(pname) - 1), pname) \
366
/* check what we are called as */
367
if (IS_PNAME("mysql-proxy")) {
368
plugin_names[0] = g_strdup("admin");
369
plugin_names[1] = g_strdup("proxy");
370
plugin_names[2] = NULL;
374
/* load the plugins */
375
for (i = 0; plugin_names && plugin_names[i]; i++) {
376
char *plugin_filename = g_strdup_printf("lib%s.la", plugin_names[i]);
378
p = chassis_plugin_load(plugin_dir, plugin_filename);
379
g_free(plugin_filename);
382
g_critical("setting --plugins-dir=<dir> might help");
383
exit_code = EXIT_FAILURE;
387
g_ptr_array_add(srv->modules, p);
389
if (NULL != (config_entries = chassis_plugin_get_options(p))) {
390
gchar *group_desc = g_strdup_printf("%s-module", plugin_names[i]);
391
gchar *help_msg = g_strdup_printf("Show options for the %s-module", plugin_names[i]);
392
const gchar *group_name = plugin_names[i];
394
GOptionGroup *option_grp = g_option_group_new(group_name, group_desc, help_msg, NULL, NULL);
395
g_option_group_add_entries(option_grp, config_entries);
396
g_option_context_add_group(option_ctx, option_grp);
401
/* parse the new options */
402
if (FALSE == g_option_context_parse(option_ctx, &argc, &argv, &gerr)) {
403
g_critical("%s", gerr->message);
405
exit_code = EXIT_FAILURE;
410
if (chassis_keyfile_to_options(keyfile, "mysql-proxy", config_entries)) {
411
exit_code = EXIT_FAILURE;
492
418
/* we know about the options now, lets parse them */
520
435
g_critical("unknown option: %s", argv[1]);
522
GOTO_EXIT(EXIT_FAILURE);
525
/* make sure that he max-thread-count isn't negative */
526
if (frontend->event_thread_count < 1) {
527
g_critical("--event-threads has to be >= 1, is %d", frontend->event_thread_count);
529
GOTO_EXIT(EXIT_FAILURE);
532
srv->event_thread_count = frontend->event_thread_count;
437
exit_code = EXIT_FAILURE;
442
#if defined(HAVE_LUA_H) && defined(DATADIR)
444
* if the LUA_PATH is not set, set a good default
446
if (!g_getenv("LUA_PATH")) {
447
g_setenv("LUA_PATH", LUA_PATHSEP LUA_PATHSEP DATADIR "/?.lua", 1);
535
452
signal(SIGPIPE, SIG_IGN);
537
if (frontend->daemon_mode) {
538
chassis_unix_daemonize();
541
if (frontend->auto_restart) {
542
int child_exit_status = EXIT_SUCCESS; /* forward the exit-status of the child */
543
int ret = chassis_unix_proc_keepalive(&child_exit_status);
546
/* the agent stopped */
548
exit_code = child_exit_status;
466
if (-1 == (fd = open(pid_file, O_WRONLY|O_TRUNC|O_CREAT, 0600))) {
467
g_critical("%s.%d: open(%s) failed: %s",
472
exit_code = EXIT_FAILURE;
549
473
goto exit_nicely;
550
} else if (ret < 0) {
551
GOTO_EXIT(EXIT_FAILURE);
553
/* we are the child, go on */
557
if (frontend->pid_file) {
558
if (0 != chassis_frontend_write_pidfile(frontend->pid_file, &gerr)) {
559
g_critical("%s", gerr->message);
560
g_clear_error(&gerr);
562
GOTO_EXIT(EXIT_FAILURE);
566
/* the message has to be _after_ the g_option_content_parse() to
567
* hide from the output if the --help is asked for
569
g_message("%s started", PACKAGE_STRING); /* add tag to the logfile (after we opened the logfile) */
572
if (chassis_win32_is_service()) chassis_win32_service_set_state(SERVICE_RUNNING, 0);
576
* we have to drop root privileges in chassis_mainloop() after
577
* the plugins opened the ports, so we need the user there
579
srv->user = g_strdup(frontend->user);
581
if (frontend->max_files_number) {
582
if (0 != chassis_fdlimit_set(frontend->max_files_number)) {
583
g_critical("%s: setting fdlimit = %d failed: %s (%d)",
585
frontend->max_files_number,
588
GOTO_EXIT(EXIT_FAILURE);
591
g_debug("max open file-descriptors = %"G_GINT64_FORMAT,
592
chassis_fdlimit_get());
476
pid_str = g_strdup_printf("%d", getpid());
478
write(fd, pid_str, strlen(pid_str));
594
484
if (chassis_mainloop(srv)) {
595
485
/* looks like we failed */
596
g_critical("%s: Failure from chassis_mainloop. Shutting down.", G_STRLOC);
597
GOTO_EXIT(EXIT_FAILURE);
487
exit_code = EXIT_FAILURE;
601
/* necessary to set the shutdown flag, because the monitor will continue
602
* to schedule timers otherwise, causing an infinite loop in cleanup
605
exit_location = G_STRLOC;
607
chassis_set_shutdown_location(exit_location);
609
if (!frontend->print_version) {
610
g_log(G_LOG_DOMAIN, (frontend->verbose_shutdown ? G_LOG_LEVEL_CRITICAL : G_LOG_LEVEL_MESSAGE),
611
"shutting down normally, exit code is: %d", exit_code); /* add a tag to the logfile */
615
if (chassis_win32_is_service()) chassis_win32_service_set_state(SERVICE_STOP_PENDING, 0);
618
chassis_frontend_free(frontend);
492
if (keyfile) g_key_file_free(keyfile);
493
if (default_file) g_free(default_file);
620
495
if (gerr) g_error_free(gerr);
621
496
if (option_ctx) g_option_context_free(option_ctx);
622
497
if (srv) chassis_free(srv);
623
if (opts) chassis_options_free(opts);
624
if (main_entries) g_free(main_entries);
499
if (pid_file) g_free(pid_file);
500
if (log_level) g_free(log_level);
501
if (plugin_dir) g_free(plugin_dir);
504
for (i = 0; plugin_names[i]; i++) {
505
g_free(plugin_names[i]);
507
g_free(plugin_names);
626
510
chassis_log_free(log);
629
if (chassis_win32_is_service()) chassis_win32_service_set_state(SERVICE_STOPPED, 0);
632
#ifdef HAVE_SIGACTION
633
/* reset the handler */
634
sigsegv_sa.sa_handler = SIG_DFL;
635
if (frontend->invoke_dbg_on_crash && !(RUNNING_ON_VALGRIND)) {
636
sigaction(SIGSEGV, &sigsegv_sa, NULL);
640
512
return exit_code;
644
* On Windows we first look if we are started as a service and
645
* set that up if appropriate.
646
* We eventually fall down through to main_cmdline, even on Windows.
648
int main(int argc, char **argv) {
649
#ifdef WIN32_AS_SERVICE
650
return main_win32(argc, argv, main_cmdline);
652
return main_cmdline(argc, argv);