@@ -163,6 +163,7 @@ static void write_and_free(conn *c, char *buf, int bytes);
163163static int ensure_iov_space(conn *c);
164164static int add_iov(conn *c, const void *buf, int len);
165165static int add_msghdr(conn *c);
166+ static int try_load_config_file(const char *path, config_opt_t *opt);
166167
167168enum transmit_result {
168169 TRANSMIT_COMPLETE, /** All done writing. */
@@ -15804,6 +15805,116 @@ static bool sanitycheck(void)
1580415805 return true;
1580515806}
1580615807
15808+ static int try_load_config_file(const char *path, config_opt_t *opt)
15809+ {
15810+ char *access_mask_str = NULL;
15811+ char *protocol_str = NULL;
15812+
15813+ struct config_item main_config_items[] = {
15814+ { .key = "port", .datatype = DT_UINT32, .value.dt_uint32 = (uint32_t*)&settings.port },
15815+ { .key = "udpport", .datatype = DT_UINT32, .value.dt_uint32 = (uint32_t*)&settings.udpport },
15816+ { .key = "socketpath", .datatype = DT_STRING, .value.dt_string = &settings.socketpath },
15817+ { .key = "access", .datatype = DT_STRING, .value.dt_string = &access_mask_str },
15818+ { .key = "listen", .datatype = DT_STRING, .value.dt_string = &settings.inter },
15819+ { .key = "daemonize", .datatype = DT_BOOL, .value.dt_bool = opt->daemonize },
15820+ { .key = "maxcore", .datatype = DT_BOOL, .value.dt_bool = opt->maxcore },
15821+ { .key = "username", .datatype = DT_STRING, .value.dt_string = opt->username },
15822+ { .key = "maxconns", .datatype = DT_UINT32, .value.dt_uint32 = (uint32_t*)&settings.maxconns },
15823+ { .key = "lock_memory", .datatype = DT_BOOL, .value.dt_bool = opt->lock_memory },
15824+ { .key = "verbosity", .datatype = DT_SIZE, .value.dt_size = (size_t*)&settings.verbose },
15825+ { .key = "pid_file", .datatype = DT_STRING, .value.dt_string = opt->pid_file },
15826+ { .key = "threads", .datatype = DT_UINT32, .value.dt_uint32 = (uint32_t*)&settings.num_threads },
15827+ { .key = "reqs_per_event", .datatype = DT_UINT32, .value.dt_uint32 = (uint32_t*)&settings.reqs_per_event },
15828+ { .key = "backlog", .datatype = DT_UINT32, .value.dt_uint32 = (uint32_t*)&settings.backlog },
15829+ { .key = "protocol", .datatype = DT_STRING, .value.dt_string = &protocol_str },
15830+ { .key = "engine_path", .datatype = DT_STRING, .value.dt_string = opt->engine },
15831+
15832+ { .key = "memory_limit", .datatype = DT_SIZE, .value.dt_size = &settings.maxbytes },
15833+ { .key = "eviction", .datatype = DT_BOOL, .value.dt_bool = (bool*)&settings.evict_to_free },
15834+ { .key = "sticky_limit", .datatype = DT_SIZE, .value.dt_size = &settings.sticky_limit },
15835+ { .key = "factor", .datatype = DT_FLOAT, .value.dt_float = (float*)&settings.factor },
15836+ { .key = "chunk_size", .datatype = DT_SIZE, .value.dt_size = (size_t*)&settings.chunk_size },
15837+ { .key = "prefix_delimiter", .datatype = DT_CHAR, .value.dt_char = &settings.prefix_delimiter},
15838+ { .key = "use_cas", .datatype = DT_BOOL, .value.dt_bool = &settings.use_cas },
15839+ { .key = "item_size_max", .datatype = DT_SIZE, .value.dt_size = &settings.item_size_max },
15840+ { .key = "engine_config", .datatype = DT_STRING, .value.dt_string = (char**)opt->engine_config },
15841+ { .key = "preallocate", .datatype = DT_BOOL, .value.dt_bool = opt->preallocate },
15842+ #ifdef ENABLE_ZK_INTEGRATION
15843+ { .key = "zookeeper", .datatype = DT_STRING, .value.dt_string = (char**)&arcus_zk_cfg },
15844+ { .key = "zk_timeout", .datatype = DT_UINT32, .value.dt_uint32 = (uint32_t*)arcus_zk_to_ptr },
15845+ #ifdef PROXY_SUPPORT
15846+ { .key = "proxy_config", .datatype = DT_STRING, .value.dt_string = opt->arcus_proxy_cfg },
15847+ #endif
15848+ #endif
15849+
15850+ #ifdef SASL_ENABLED
15851+ { .key = "require_sasl", .datatype = DT_BOOL, .value.dt_bool = &settings.require_sasl },
15852+ #endif
15853+ { .key = NULL}
15854+ };
15855+
15856+ if (read_config_file(path, main_config_items, stderr) == -1) {
15857+ fprintf(stderr, "Error parsing config file. Aborting.\n");
15858+ return -1;
15859+ }
15860+
15861+ if (access_mask_str != NULL) {
15862+ settings.access = strtol(access_mask_str, NULL, 8);
15863+ free(access_mask_str);
15864+ }
15865+ if (protocol_str != NULL) {
15866+ if (strcmp(protocol_str, "auto") == 0) {
15867+ settings.binding_protocol = negotiating_prot;
15868+ } else if (strcmp(protocol_str, "binary") == 0) {
15869+ settings.binding_protocol = binary_prot;
15870+ } else if (strcmp(protocol_str, "ascii") == 0) {
15871+ settings.binding_protocol = ascii_prot;
15872+ } else {
15873+ fprintf(stderr, "Invalid value for binding protocol in config file: %s\n", protocol_str);
15874+ free(protocol_str);
15875+ return -1;
15876+ }
15877+ free(protocol_str);
15878+ }
15879+ if (settings.maxbytes <= 0) {
15880+ mc_logger->log(EXTENSION_LOG_WARNING, NULL,
15881+ "The value of memory limit must be greater than 0.\n");
15882+ return -1;
15883+ }
15884+ if (settings.sticky_limit > 0 && settings.maxbytes < settings.sticky_limit) {
15885+ mc_logger->log(EXTENSION_LOG_WARNING, NULL,
15886+ "The value of memory limit cannot be smaller than sticky_limit.\n");
15887+ return -1;
15888+ }
15889+ if (settings.item_size_max < 1024 * 20) {
15890+ mc_logger->log(EXTENSION_LOG_WARNING, NULL,
15891+ "Item max size cannot be less than 20KB.\n");
15892+ return -1;
15893+ }
15894+ if (settings.item_size_max > 1024 * 1024 * 128) {
15895+ mc_logger->log(EXTENSION_LOG_WARNING, NULL,
15896+ "Cannot set item size limit higher than 128 mb.\n");
15897+ return -1;
15898+ }
15899+ if (settings.factor <= 1.0) {
15900+ mc_logger->log(EXTENSION_LOG_WARNING, NULL,
15901+ "Factor must be greater than 1\n");
15902+ return -1;
15903+ }
15904+ if (settings.chunk_size <= 0) {
15905+ mc_logger->log(EXTENSION_LOG_WARNING, NULL,
15906+ "Chunk size must be greater than 0\n");
15907+ return -1;
15908+ }
15909+ if (settings.num_threads <= 0) {
15910+ mc_logger->log(EXTENSION_LOG_WARNING, NULL,
15911+ "Number of threads must be greater than 0\n");
15912+ return -1;
15913+ }
15914+
15915+ return 0;
15916+ }
15917+
1580715918static void settings_reload_engine_config(void)
1580815919{
1580915920 ENGINE_ERROR_CODE ret;
@@ -15898,6 +16009,35 @@ int main (int argc, char **argv)
1589816009 return EX_OSERR;
1589916010 }
1590016011
16012+ /* parse config file */
16013+ if (argc > 1 && argv[1][0] != '-') {
16014+ const char *config_file = argv[1];
16015+ config_opt_t opt = {
16016+ .daemonize = &do_daemonize,
16017+ .maxcore = (bool*)&maxcore,
16018+ .username = &username,
16019+ .lock_memory = &lock_memory,
16020+ .pid_file = &pid_file,
16021+ .engine = (char**)&engine,
16022+ .engine_config = &engine_config,
16023+ .preallocate = &preallocate,
16024+ #ifdef ENABLE_ZK_INTEGRATION
16025+ .arcus_zk_to = &arcus_zk_to,
16026+ #ifdef PROXY_SUPPORT
16027+ .arcus_proxy_cfg = &arcus_proxy_cfg,
16028+ #endif
16029+ #endif
16030+ };
16031+ if (try_load_config_file(config_file, &opt) != 0) {
16032+ fprintf(stderr, "Error parsing config file '%s'.", config_file);
16033+ exit(EXIT_FAILURE);
16034+ }
16035+
16036+ optind = 2;
16037+ } else {
16038+ optind = 1;
16039+ }
16040+
1590116041 /* process arguments */
1590216042 while (-1 != (c = getopt(argc, argv,
1590316043 "a:" /* access mask for unix socket */
0 commit comments