int main()

in plugin/innodb_memcached/daemon_memcached/daemon/memcached.c [7073:8025]


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;

    memcached_initialized = 0;

    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);
    }

#ifdef INNODB_MEMCACHED
    my_thread_init();
#endif

    if(!init_engine(engine_handle,engine_config,settings.extensions.logger)) {
#ifdef INNODB_MEMCACHED
	my_thread_end();
        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
		my_thread_end();
		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);

#ifdef INNODB_MEMCACHED
    /* free event base */
    if (main_base) {
        event_base_free(main_base);
        main_base = NULL;
    }
    my_thread_end();
#endif

    memcached_shutdown = 2;
    memcached_initialized = 2;

    return EXIT_SUCCESS;
}