in plugin/innodb_memcached/daemon_memcached/daemon/memcached.c [7058:7993]
int main (int argc, char **argv) {
#endif
int c;
bool lock_memory = false;
bool do_daemonize = false;
bool preallocate = false;
int maxcore = 0;
char *username = NULL;
char *pid_file = NULL;
struct passwd *pw;
struct rlimit rlim;
char unit = '\0';
int size_max = 0;
bool protocol_specified = false;
bool tcp_specified = false;
bool udp_specified = false;
memcached_context_t* m_config = (memcached_context_t*)p;
const char *engine;
const char *engine_config = NULL;
char old_options[1024] = { [0] = '\0' };
char *old_opts = old_options;
#ifdef INNODB_MEMCACHED
int option_argc = 0;
char** option_argv = NULL;
eng_config_info_t my_eng_config;
if (m_config->m_engine_library) {
engine = m_config->m_engine_library;
/* FIXME: We should have a better way to pass the callback structure
point to storage engine. It is now appended in the configure
string in eng_config_info_t structure */
my_eng_config.cb_ptr = m_config->m_innodb_api_cb;
my_eng_config.eng_r_batch_size = m_config->m_r_batch_size;
my_eng_config.eng_w_batch_size = m_config->m_w_batch_size;
my_eng_config.enable_binlog = m_config->m_enable_binlog;
my_eng_config.option_string = old_opts;
engine_config = (const char *) (&my_eng_config);
} else {
engine = "default_engine.so";
}
#else
engine = "default_engine.so";
#endif /* INNODB_MEMCACHED */
memcached_shutdown = 0;
memcached_initialized = 0;
if (!sanitycheck()) {
return(NULL);
}
/* make the time we started always be 2 seconds before we really
did, so time(0) - time.started is never zero. if so, things
like 'settings.oldest_live' which act as booleans as well as
values are now false in boolean context... */
process_started = time(0) - 2;
set_current_time();
/* Initialize the socket subsystem */
initialize_sockets();
/* init settings */
settings_init();
if (memcached_initialize_stderr_logger(get_server_api) != EXTENSION_SUCCESS) {
fprintf(stderr, "Failed to initialize log system\n");
return (NULL);
}
if (m_config->m_mem_option) {
daemon_memcached_make_option(m_config->m_mem_option,
&option_argc,
&option_argv);
}
#ifdef INNODB_MEMCACHED
if (option_argc > 0 && option_argv) {
/* Always reset the index to 1, since this function can
be invoked multiple times with install/uninstall plugins */
optind = 1;
while (-1 != (c = getopt(option_argc, option_argv,
"a:" /* access mask for unix socket */
"p:" /* TCP port number to listen on */
"s:" /* unix socket path to listen on */
"U:" /* UDP port number to listen on */
"m:" /* max memory to use for items in megabytes */
"M" /* return error on memory exhausted */
"c:" /* max simultaneous connections */
"k" /* lock down all paged memory */
"hi" /* help, licence info */
"r" /* maximize core file limit */
"v" /* verbose */
"d" /* daemon mode */
"l:" /* interface to listen on */
"u:" /* user identity to run as */
"P:" /* save PID in file */
"f:" /* factor? */
"n:" /* minimum space allocated for key+value+flags */
"t:" /* threads */
"D:" /* prefix delimiter? */
"L" /* Large memory pages */
"R:" /* max requests per event */
"C" /* Disable use of CAS */
"b:" /* backlog queue limit */
"B:" /* Binding protocol */
"I:" /* Max item size */
"S" /* Sasl ON */
"E:" /* Engine to load */
"e:" /* Engine options */
"q" /* Disallow detailed stats */
"X:" /* Load extension */
))) {
switch (c) {
case 'a':
/* access for unix domain socket, as octal mask (like chmod)*/
settings.access= strtol(optarg,NULL,8);
break;
case 'U':
settings.udpport = atoi(optarg);
udp_specified = true;
break;
case 'p':
settings.port = atoi(optarg);
tcp_specified = true;
break;
case 's':
settings.socketpath = optarg;
break;
case 'm':
settings.maxbytes = ((size_t)atoi(optarg)) * 1024 * 1024;
old_opts += sprintf(old_opts, "cache_size=%lu;",
(unsigned long)settings.maxbytes);
break;
case 'M':
settings.evict_to_free = 0;
old_opts += sprintf(old_opts, "eviction=false;");
break;
case 'c':
settings.maxconns = atoi(optarg);
break;
case 'h':
usage();
exit(EXIT_SUCCESS);
case 'i':
usage_license();
exit(EXIT_SUCCESS);
case 'k':
lock_memory = true;
break;
case 'v':
settings.verbose++;
perform_callbacks(ON_LOG_LEVEL, NULL, NULL);
break;
case 'l':
settings.inter= strdup(optarg);
break;
case 'd':
do_daemonize = true;
break;
case 'r':
maxcore = 1;
break;
case 'R':
settings.reqs_per_event = atoi(optarg);
if (settings.reqs_per_event <= 0) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"Number of requests per event must be greater than 0\n");
return (void*)1;
}
break;
case 'u':
username = optarg;
break;
case 'P':
pid_file = optarg;
break;
case 'f':
settings.factor = atof(optarg);
if (settings.factor <= 1.0) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"Factor must be greater than 1\n");
return (void*)1;
}
old_opts += sprintf(old_opts, "factor=%f;",
settings.factor);
break;
case 'n':
settings.chunk_size = atoi(optarg);
if (settings.chunk_size == 0) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"Chunk size must be greater than 0\n");
return (void*)1;
}
old_opts += sprintf(old_opts, "chunk_size=%u;",
settings.chunk_size);
break;
case 't':
settings.num_threads = atoi(optarg);
if (settings.num_threads <= 0) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"Number of threads must be greater than 0\n");
return (void*)1;
}
/* There're other problems when you get above 64 threads.
* In the future we should portably detect # of cores for the
* default.
*/
if (settings.num_threads > 64) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"WARNING: Setting a high number of worker"
"threads is not recommended.\n"
" Set this value to the number of cores in"
" your machine or less.\n");
}
break;
case 'D':
settings.prefix_delimiter = optarg[0];
settings.detail_enabled = 1;
break;
case 'L' :
if (enable_large_pages() == 0) {
preallocate = true;
old_opts += sprintf(old_opts, "preallocate=true;");
}
break;
case 'C' :
settings.use_cas = false;
break;
case 'b' :
settings.backlog = atoi(optarg);
break;
case 'B':
protocol_specified = true;
if (strcmp(optarg, "auto") == 0) {
settings.binding_protocol = negotiating_prot;
} else if (strcmp(optarg, "binary") == 0) {
settings.binding_protocol = binary_prot;
} else if (strcmp(optarg, "ascii") == 0) {
settings.binding_protocol = ascii_prot;
} else {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"Invalid value for binding protocol: %s\n"
" -- should be one of auto, binary, or ascii\n", optarg);
exit(EX_USAGE);
}
break;
case 'I':
unit = optarg[strlen(optarg)-1];
if (unit == 'k' || unit == 'm' ||
unit == 'K' || unit == 'M') {
optarg[strlen(optarg)-1] = '\0';
size_max = atoi(optarg);
if (unit == 'k' || unit == 'K')
size_max *= 1024;
if (unit == 'm' || unit == 'M')
size_max *= 1024 * 1024;
settings.item_size_max = size_max;
} else {
settings.item_size_max = atoi(optarg);
}
if (settings.item_size_max < 1024) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"Item max size cannot be less than 1024 bytes.\n");
return (void*)1;
}
if (settings.item_size_max > 1024 * 1024 * 128) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"Cannot set item size limit higher than 128 mb.\n");
return (void*)1;
}
if (settings.item_size_max > 1024 * 1024) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"WARNING: Setting item max size above 1MB is not"
" recommended!\n"
" Raising this limit increases the minimum memory requirements\n"
" and will decrease your memory efficiency.\n"
);
}
#ifndef __WIN32__
old_opts += sprintf(old_opts, "item_size_max=%zu;",
settings.item_size_max);
#else
old_opts += sprintf(old_opts, "item_size_max=%lu;", (long unsigned)
settings.item_size_max);
#endif
break;
case 'E':
engine = optarg;
break;
case 'e':
/* FIXME, we use engine_config to pass callback function
for now. Will need a better solution
engine_config = optarg; */
break;
case 'q':
settings.allow_detailed = false;
break;
case 'S': /* set Sasl authentication to true. Default is false */
# ifdef ENABLE_MEMCACHED_SASL
# ifndef SASL_ENABLED
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"This server is not built with SASL support.\n");
exit(EX_USAGE);
# endif /* !SASL_ENABLED */
settings.require_sasl = true;
# endif /* ENABLE_MEMCACHED_SASL */
break;
case 'X' :
{
char *ptr = strchr(optarg, ',');
if (ptr != NULL) {
*ptr = '\0';
++ptr;
}
if (!load_extension(optarg, ptr)) {
exit(EXIT_FAILURE);
}
if (ptr != NULL) {
*(ptr - 1) = ',';
}
}
break;
default:
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"Illegal argument \"%c\"\n", c);
return (void*)1;
}
}
free(option_argv);
}
fprintf(stderr, MEMCACHED_ATOMIC_MSG);
#else
/* process arguments */
while (-1 != (c = getopt(argc, argv,
"a:" /* access mask for unix socket */
"p:" /* TCP port number to listen on */
"s:" /* unix socket path to listen on */
"U:" /* UDP port number to listen on */
"m:" /* max memory to use for items in megabytes */
"M" /* return error on memory exhausted */
"c:" /* max simultaneous connections */
"k" /* lock down all paged memory */
"hi" /* help, licence info */
"r" /* maximize core file limit */
"v" /* verbose */
"d" /* daemon mode */
"l:" /* interface to listen on */
"u:" /* user identity to run as */
"P:" /* save PID in file */
"f:" /* factor? */
"n:" /* minimum space allocated for key+value+flags */
"t:" /* threads */
"D:" /* prefix delimiter? */
"L" /* Large memory pages */
"R:" /* max requests per event */
"C" /* Disable use of CAS */
"b:" /* backlog queue limit */
"B:" /* Binding protocol */
"I:" /* Max item size */
"S" /* Sasl ON */
"E:" /* Engine to load */
"e:" /* Engine options */
"q" /* Disallow detailed stats */
"X:" /* Load extension */
))) {
switch (c) {
case 'a':
/* access for unix domain socket, as octal mask (like chmod)*/
settings.access= strtol(optarg,NULL,8);
break;
case 'U':
settings.udpport = atoi(optarg);
udp_specified = true;
break;
case 'p':
settings.port = atoi(optarg);
tcp_specified = true;
break;
case 's':
settings.socketpath = optarg;
break;
case 'm':
settings.maxbytes = ((size_t)atoi(optarg)) * 1024 * 1024;
old_opts += sprintf(old_opts, "cache_size=%lu;",
(unsigned long)settings.maxbytes);
break;
case 'M':
settings.evict_to_free = 0;
old_opts += sprintf(old_opts, "eviction=false;");
break;
case 'c':
settings.maxconns = atoi(optarg);
break;
case 'h':
usage();
exit(EXIT_SUCCESS);
case 'i':
usage_license();
exit(EXIT_SUCCESS);
case 'k':
lock_memory = true;
break;
case 'v':
settings.verbose++;
perform_callbacks(ON_LOG_LEVEL, NULL, NULL);
break;
case 'l':
if (settings.inter != NULL) {
size_t len = strlen(settings.inter) + strlen(optarg) + 2;
char *p = malloc(len);
if (p == NULL) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"Failed to allocate memory\n");
return 1;
}
snprintf(p, len, "%s,%s", settings.inter, optarg);
free(settings.inter);
settings.inter = p;
} else {
settings.inter= strdup(optarg);
}
break;
case 'd':
do_daemonize = true;
break;
case 'r':
maxcore = 1;
break;
case 'R':
settings.reqs_per_event = atoi(optarg);
if (settings.reqs_per_event <= 0) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"Number of requests per event must be greater than 0\n");
return 1;
}
break;
case 'u':
username = optarg;
break;
case 'P':
pid_file = optarg;
break;
case 'f':
settings.factor = atof(optarg);
if (settings.factor <= 1.0) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"Factor must be greater than 1\n");
return 1;
}
old_opts += sprintf(old_opts, "factor=%f;",
settings.factor);
break;
case 'n':
settings.chunk_size = atoi(optarg);
if (settings.chunk_size == 0) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"Chunk size must be greater than 0\n");
return 1;
}
old_opts += sprintf(old_opts, "chunk_size=%u;",
settings.chunk_size);
break;
case 't':
settings.num_threads = atoi(optarg);
if (settings.num_threads <= 0) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"Number of threads must be greater than 0\n");
return 1;
}
/* There're other problems when you get above 64 threads.
* In the future we should portably detect # of cores for the
* default.
*/
if (settings.num_threads > 64) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"WARNING: Setting a high number of worker"
"threads is not recommended.\n"
" Set this value to the number of cores in"
" your machine or less.\n");
}
break;
case 'D':
settings.prefix_delimiter = optarg[0];
settings.detail_enabled = 1;
break;
case 'L' :
if (enable_large_pages() == 0) {
preallocate = true;
old_opts += sprintf(old_opts, "preallocate=true;");
}
break;
case 'C' :
settings.use_cas = false;
break;
case 'b' :
settings.backlog = atoi(optarg);
break;
case 'B':
protocol_specified = true;
if (strcmp(optarg, "auto") == 0) {
settings.binding_protocol = negotiating_prot;
} else if (strcmp(optarg, "binary") == 0) {
settings.binding_protocol = binary_prot;
} else if (strcmp(optarg, "ascii") == 0) {
settings.binding_protocol = ascii_prot;
} else {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"Invalid value for binding protocol: %s\n"
" -- should be one of auto, binary, or ascii\n", optarg);
exit(EX_USAGE);
}
break;
case 'I':
unit = optarg[strlen(optarg)-1];
if (unit == 'k' || unit == 'm' ||
unit == 'K' || unit == 'M') {
optarg[strlen(optarg)-1] = '\0';
size_max = atoi(optarg);
if (unit == 'k' || unit == 'K')
size_max *= 1024;
if (unit == 'm' || unit == 'M')
size_max *= 1024 * 1024;
settings.item_size_max = size_max;
} else {
settings.item_size_max = atoi(optarg);
}
if (settings.item_size_max < 1024) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"Item max size cannot be less than 1024 bytes.\n");
return 1;
}
if (settings.item_size_max > 1024 * 1024 * 128) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"Cannot set item size limit higher than 128 mb.\n");
return 1;
}
if (settings.item_size_max > 1024 * 1024) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"WARNING: Setting item max size above 1MB is not"
" recommended!\n"
" Raising this limit increases the minimum memory requirements\n"
" and will decrease your memory efficiency.\n"
);
}
#ifndef __WIN32__
old_opts += sprintf(old_opts, "item_size_max=%zu;",
settings.item_size_max);
#else
old_opts += sprintf(old_opts, "item_size_max=%lu;", (long unsigned)
settings.item_size_max);
#endif
break;
case 'E':
engine = optarg;
break;
case 'e':
engine_config = optarg;
break;
case 'q':
settings.allow_detailed = false;
break;
case 'S': /* set Sasl authentication to true. Default is false */
#ifndef SASL_ENABLED
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"This server is not built with SASL support.\n");
exit(EX_USAGE);
#endif
settings.require_sasl = true;
break;
case 'X' :
{
char *ptr = strchr(optarg, ',');
if (ptr != NULL) {
*ptr = '\0';
++ptr;
}
if (!load_extension(optarg, ptr)) {
exit(EXIT_FAILURE);
}
if (ptr != NULL) {
*(ptr - 1) = ',';
}
}
break;
default:
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"Illegal argument \"%c\"\n", c);
return 1;
}
}
#endif /* INNODB_MEMCACHED */
if (getenv("MEMCACHED_REQS_TAP_EVENT") != NULL) {
settings.reqs_per_tap_event = atoi(getenv("MEMCACHED_REQS_TAP_EVENT"));
}
if (settings.reqs_per_tap_event <= 0) {
settings.reqs_per_tap_event = DEFAULT_REQS_PER_TAP_EVENT;
}
if (install_sigterm_handler() != 0) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"Failed to install SIGTERM handler\n");
exit(EXIT_FAILURE);
}
char *topkeys_env = getenv("MEMCACHED_TOP_KEYS");
if (topkeys_env != NULL) {
settings.topkeys = atoi(topkeys_env);
if (settings.topkeys < 0) {
settings.topkeys = 0;
}
}
if (settings.require_sasl) {
if (!protocol_specified) {
settings.binding_protocol = binary_prot;
} else {
if (settings.binding_protocol == negotiating_prot) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"ERROR: You cannot use auto-negotiating protocol while requiring SASL.\n");
exit(EX_USAGE);
}
if (settings.binding_protocol == ascii_prot) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"ERROR: You cannot use only ASCII protocol while requiring SASL.\n");
exit(EX_USAGE);
}
}
}
if (tcp_specified && !udp_specified) {
settings.udpport = settings.port;
} else if (udp_specified && !tcp_specified) {
settings.port = settings.udpport;
}
/*
if (engine_config != NULL && strlen(old_options) > 0) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"ERROR: You can't mix -e with the old options\n");
return (NULL);
} else if (engine_config == NULL && strlen(old_options) > 0) {
engine_config = old_options;
} */
if (maxcore != 0) {
struct rlimit rlim_new;
/*
* First try raising to infinity; if that fails, try bringing
* the soft limit to the hard.
*/
if (getrlimit(RLIMIT_CORE, &rlim) == 0) {
rlim_new.rlim_cur = rlim_new.rlim_max = RLIM_INFINITY;
if (setrlimit(RLIMIT_CORE, &rlim_new)!= 0) {
/* failed. try raising just to the old max */
rlim_new.rlim_cur = rlim_new.rlim_max = rlim.rlim_max;
(void)setrlimit(RLIMIT_CORE, &rlim_new);
}
}
/*
* getrlimit again to see what we ended up with. Only fail if
* the soft limit ends up 0, because then no core files will be
* created at all.
*/
if ((getrlimit(RLIMIT_CORE, &rlim) != 0) || rlim.rlim_cur == 0) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"failed to ensure corefile creation\n");
exit(EX_OSERR);
}
}
/*
* If needed, increase rlimits to allow as many connections
* as needed.
*/
if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"failed to getrlimit number of files\n");
exit(EX_OSERR);
} else {
int maxfiles = settings.maxconns;
if (rlim.rlim_cur < maxfiles)
rlim.rlim_cur = maxfiles;
if (rlim.rlim_max < rlim.rlim_cur)
rlim.rlim_max = rlim.rlim_cur;
if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"failed to set rlimit for open files. Try running as"
" root or requesting smaller maxconns value.\n");
exit(EX_OSERR);
}
}
/* Sanity check for the connection structures */
int nfiles = 0;
if (settings.port != 0) {
nfiles += 2;
}
if (settings.udpport != 0) {
nfiles += settings.num_threads * 2;
}
if (settings.maxconns <= nfiles) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"Configuratioin error. \n"
"You specified %d connections, but the system will use at "
"least %d\nconnection structures to start.\n",
settings.maxconns, nfiles);
exit(EX_USAGE);
}
/* lose root privileges if we have them */
if (getuid() == 0 || geteuid() == 0) {
if (username == 0 || *username == '\0') {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"can't run as root without the -u switch\n");
exit(EX_USAGE);
}
if ((pw = getpwnam(username)) == 0) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"can't find the user %s to switch to\n", username);
exit(EX_NOUSER);
}
if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"failed to assume identity of user %s: %s\n", username,
strerror(errno));
exit(EX_OSERR);
}
}
#ifdef SASL_ENABLED
init_sasl();
#endif /* SASL */
/* daemonize if requested */
/* if we want to ensure our ability to dump core, don't chdir to / */
if (do_daemonize) {
if (sigignore(SIGHUP) == -1) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"Failed to ignore SIGHUP: ", strerror(errno));
}
if (daemonize(maxcore, settings.verbose) == -1) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"failed to daemon() in order to daemonize\n");
exit(EXIT_FAILURE);
}
}
/* lock paged memory if needed */
if (lock_memory) {
#ifdef HAVE_MLOCKALL
int res = mlockall(MCL_CURRENT | MCL_FUTURE);
if (res != 0) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"warning: -k invalid, mlockall() failed: %s\n",
strerror(errno));
}
#else
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"warning: -k invalid, mlockall() not supported on this platform. proceeding without.\n");
#endif
}
/* initialize main thread libevent instance */
main_base = event_init();
/* Load the storage engine */
ENGINE_HANDLE *engine_handle = NULL;
if (!load_engine(engine,get_server_api,settings.extensions.logger,&engine_handle)) {
/* Error already reported */
exit(EXIT_FAILURE);
}
if(!init_engine(engine_handle,engine_config,settings.extensions.logger)) {
#ifdef INNODB_MEMCACHED
shutdown_server();
goto func_exit;
#else
return(false);
#endif /* INNODB_MEMCACHED */
}
if(settings.verbose > 0) {
log_engine_details(engine_handle,settings.extensions.logger);
}
settings.engine.v1 = (ENGINE_HANDLE_V1 *) engine_handle;
if (settings.engine.v1->arithmetic == NULL) {
settings.engine.v1->arithmetic = internal_arithmetic;
}
/* initialize other stuff */
stats_init();
if (!(conn_cache = cache_create("conn", sizeof(conn), sizeof(void*),
conn_constructor, conn_destructor))) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"Failed to create connection cache\n");
exit(EXIT_FAILURE);
}
default_independent_stats = new_independent_stats();
#ifdef INNODB_MEMCACHED
if (!default_independent_stats) {
exit(EXIT_FAILURE);
}
#endif
#ifndef __WIN32__
/*
* ignore SIGPIPE signals; we can use errno == EPIPE if we
* need that information
*/
if (sigignore(SIGPIPE) == -1) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"failed to ignore SIGPIPE; sigaction");
exit(EX_OSERR);
}
#endif
/* start up worker threads if MT mode */
thread_init(settings.num_threads, main_base, dispatch_event_handler);
/* initialise clock event */
clock_handler(0, 0, 0);
/* create unix mode sockets after dropping privileges */
if (settings.socketpath != NULL) {
if (server_socket_unix(settings.socketpath,settings.access)) {
vperror("failed to listen on UNIX socket: %s", settings.socketpath);
exit(EX_OSERR);
}
}
/* create the listening socket, bind it, and init */
if (settings.socketpath == NULL) {
int udp_port;
const char *portnumber_filename = getenv("MEMCACHED_PORT_FILENAME");
char temp_portnumber_filename[PATH_MAX];
FILE *portnumber_file = NULL;
if (portnumber_filename != NULL) {
snprintf(temp_portnumber_filename,
sizeof(temp_portnumber_filename),
"%s.lck", portnumber_filename);
portnumber_file = fopen(temp_portnumber_filename, "a");
if (portnumber_file == NULL) {
settings.extensions.logger->log(EXTENSION_LOG_WARNING, NULL,
"Failed to open \"%s\": %s\n",
temp_portnumber_filename, strerror(errno));
}
}
if (settings.port && server_sockets(settings.port, tcp_transport,
portnumber_file)) {
vperror("failed to listen on TCP port %d", settings.port);
#ifdef INNODB_MEMCACHED
shutdown_server();
goto func_exit;
#else
exit(EX_OSERR);
#endif /* INNODB_MEMCACHED */
}
/*
* initialization order: first create the listening sockets
* (may need root on low ports), then drop root if needed,
* then daemonise if needed, then init libevent (in some cases
* descriptors created by libevent wouldn't survive forking).
*/
udp_port = settings.udpport ? settings.udpport : settings.port;
/* create the UDP listening socket and bind it */
if (settings.udpport && server_sockets(settings.udpport, udp_transport,
portnumber_file)) {
vperror("failed to listen on UDP port %d", settings.udpport);
exit(EX_OSERR);
}
if (portnumber_file) {
fclose(portnumber_file);
rename(temp_portnumber_filename, portnumber_filename);
}
}
if (pid_file != NULL) {
save_pid(pid_file);
}
/* Drop privileges no longer needed */
drop_privileges();
memcached_initialized = 1;
/* enter the event loop */
event_base_loop(main_base, 0);
if (settings.verbose) {
settings.extensions.logger->log(EXTENSION_LOG_INFO, NULL,
"Initiating shutdown\n");
}
func_exit:
if (settings.engine.v1)
settings.engine.v1->destroy(settings.engine.v0, false);
threads_shutdown();
/* remove the PID file if we're a daemon */
if (do_daemonize)
remove_pidfile(pid_file);
/* Clean up strdup() call for bind() address */
if (settings.inter)
free(settings.inter);
memcached_shutdown = 2;
memcached_initialized = 2;
return EXIT_SUCCESS;
}