X-Git-Url: https://git.saurik.com/redis.git/blobdiff_plain/4aac3ff2473b4e70dd503ff5c65891146dac30fc..d288ee655fef467a7c1f14a13af9485f5c0c0862:/src/config.c diff --git a/src/config.c b/src/config.c index 3f713e3e..7e8f8a2b 100644 --- a/src/config.c +++ b/src/config.c @@ -1,3 +1,34 @@ +/* Configuration file parsing and CONFIG GET/SET commands implementation. + * + * Copyright (c) 2009-2012, Salvatore Sanfilippo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + #include "redis.h" /*----------------------------------------------------------------------------- @@ -155,6 +186,9 @@ void loadServerConfigFromString(char *config) { loadServerConfig(argv[1],NULL); } else if (!strcasecmp(argv[0],"maxclients") && argc == 2) { server.maxclients = atoi(argv[1]); + if (server.maxclients < 1) { + err = "Invalid max clients limit"; goto loaderr; + } } else if (!strcasecmp(argv[0],"maxmemory") && argc == 2) { server.maxmemory = memtoll(argv[1],NULL); } else if (!strcasecmp(argv[0],"maxmemory-policy") && argc == 2) { @@ -202,12 +236,18 @@ void loadServerConfigFromString(char *config) { if ((server.repl_serve_stale_data = yesnotoi(argv[1])) == -1) { err = "argument must be 'yes' or 'no'"; goto loaderr; } - } else if (!strcasecmp(argv[0],"glueoutputbuf")) { - redisLog(REDIS_WARNING, "Deprecated configuration directive: \"%s\"", argv[0]); + } else if (!strcasecmp(argv[0],"slave-read-only") && argc == 2) { + if ((server.repl_slave_ro = yesnotoi(argv[1])) == -1) { + err = "argument must be 'yes' or 'no'"; goto loaderr; + } } else if (!strcasecmp(argv[0],"rdbcompression") && argc == 2) { if ((server.rdb_compression = yesnotoi(argv[1])) == -1) { err = "argument must be 'yes' or 'no'"; goto loaderr; } + } else if (!strcasecmp(argv[0],"rdbchecksum") && argc == 2) { + if ((server.rdb_checksum = yesnotoi(argv[1])) == -1) { + err = "argument must be 'yes' or 'no'"; goto loaderr; + } } else if (!strcasecmp(argv[0],"activerehashing") && argc == 2) { if ((server.activerehashing = yesnotoi(argv[1])) == -1) { err = "argument must be 'yes' or 'no'"; goto loaderr; @@ -255,6 +295,10 @@ void loadServerConfigFromString(char *config) { { server.aof_rewrite_min_size = memtoll(argv[1],NULL); } else if (!strcasecmp(argv[0],"requirepass") && argc == 2) { + if (strlen(argv[1]) > REDIS_AUTHPASS_MAX_LEN) { + err = "Password is longer than REDIS_AUTHPASS_MAX_LEN"; + goto loaderr; + } server.requirepass = zstrdup(argv[1]); } else if (!strcasecmp(argv[0],"pidfile") && argc == 2) { zfree(server.pidfile); @@ -262,10 +306,10 @@ void loadServerConfigFromString(char *config) { } else if (!strcasecmp(argv[0],"dbfilename") && argc == 2) { zfree(server.rdb_filename); server.rdb_filename = zstrdup(argv[1]); - } else if (!strcasecmp(argv[0],"hash-max-zipmap-entries") && argc == 2) { - server.hash_max_zipmap_entries = memtoll(argv[1], NULL); - } else if (!strcasecmp(argv[0],"hash-max-zipmap-value") && argc == 2) { - server.hash_max_zipmap_value = memtoll(argv[1], NULL); + } else if (!strcasecmp(argv[0],"hash-max-ziplist-entries") && argc == 2) { + server.hash_max_ziplist_entries = memtoll(argv[1], NULL); + } else if (!strcasecmp(argv[0],"hash-max-ziplist-value") && argc == 2) { + server.hash_max_ziplist_value = memtoll(argv[1], NULL); } else if (!strcasecmp(argv[0],"list-max-ziplist-entries") && argc == 2){ server.list_max_ziplist_entries = memtoll(argv[1], NULL); } else if (!strcasecmp(argv[0],"list-max-ziplist-value") && argc == 2) { @@ -300,13 +344,6 @@ void loadServerConfigFromString(char *config) { err = "Target command name already exists"; goto loaderr; } } - } else if (!strcasecmp(argv[0],"cluster-enabled") && argc == 2) { - if ((server.cluster_enabled = yesnotoi(argv[1])) == -1) { - err = "argument must be 'yes' or 'no'"; goto loaderr; - } - } else if (!strcasecmp(argv[0],"cluster-config-file") && argc == 2) { - zfree(server.cluster.configfile); - server.cluster.configfile = zstrdup(argv[1]); } else if (!strcasecmp(argv[0],"lua-time-limit") && argc == 2) { server.lua_time_limit = strtoll(argv[1],NULL,10); } else if (!strcasecmp(argv[0],"slowlog-log-slower-than") && @@ -315,6 +352,45 @@ void loadServerConfigFromString(char *config) { server.slowlog_log_slower_than = strtoll(argv[1],NULL,10); } else if (!strcasecmp(argv[0],"slowlog-max-len") && argc == 2) { server.slowlog_max_len = strtoll(argv[1],NULL,10); + } else if (!strcasecmp(argv[0],"client-output-buffer-limit") && + argc == 5) + { + int class = getClientLimitClassByName(argv[1]); + unsigned long long hard, soft; + int soft_seconds; + + if (class == -1) { + err = "Unrecognized client limit class"; + goto loaderr; + } + hard = memtoll(argv[2],NULL); + soft = memtoll(argv[3],NULL); + soft_seconds = atoi(argv[4]); + if (soft_seconds < 0) { + err = "Negative number of seconds in soft limt is invalid"; + goto loaderr; + } + server.client_obuf_limits[class].hard_limit_bytes = hard; + server.client_obuf_limits[class].soft_limit_bytes = soft; + server.client_obuf_limits[class].soft_limit_seconds = soft_seconds; + } else if (!strcasecmp(argv[0],"stop-writes-on-bgsave-error") && + argc == 2) { + if ((server.stop_writes_on_bgsave_err = yesnotoi(argv[1])) == -1) { + err = "argument must be 'yes' or 'no'"; goto loaderr; + } + } else if (!strcasecmp(argv[0],"slave-priority") && argc == 2) { + server.slave_priority = atoi(argv[1]); + } else if (!strcasecmp(argv[0],"sentinel")) { + /* argc == 1 is handled by main() as we need to enter the sentinel + * mode ASAP. */ + if (argc != 1) { + if (!server.sentinel_mode) { + err = "sentinel directive while not in sentinel mode"; + goto loaderr; + } + err = sentinelHandleConfiguration(argv+1,argc-1); + if (err) goto loaderr; + } } else { err = "Bad directive or wrong number of arguments"; goto loaderr; } @@ -383,6 +459,7 @@ void configSetCommand(redisClient *c) { zfree(server.rdb_filename); server.rdb_filename = zstrdup(o->ptr); } else if (!strcasecmp(c->argv[2]->ptr,"requirepass")) { + if (sdslen(o->ptr) > REDIS_AUTHPASS_MAX_LEN) goto badfmt; zfree(server.requirepass); server.requirepass = ((char*)o->ptr)[0] ? zstrdup(o->ptr) : NULL; } else if (!strcasecmp(c->argv[2]->ptr,"masterauth")) { @@ -392,7 +469,12 @@ void configSetCommand(redisClient *c) { if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt; server.maxmemory = ll; - if (server.maxmemory) freeMemoryIfNeeded(); + if (server.maxmemory) { + if (server.maxmemory < zmalloc_used_memory()) { + redisLog(REDIS_WARNING,"WARNING: the new maxmemory value set via CONFIG SET is smaller than the current memory usage. This will result in keys eviction and/or inability to accept new write commands depending on the maxmemory-policy."); + } + freeMemoryIfNeeded(); + } } else if (!strcasecmp(c->argv[2]->ptr,"maxmemory-policy")) { if (!strcasecmp(o->ptr,"volatile-lru")) { server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_LRU; @@ -490,17 +572,22 @@ void configSetCommand(redisClient *c) { if (yn == -1) goto badfmt; server.repl_serve_stale_data = yn; + } else if (!strcasecmp(c->argv[2]->ptr,"slave-read-only")) { + int yn = yesnotoi(o->ptr); + + if (yn == -1) goto badfmt; + server.repl_slave_ro = yn; } else if (!strcasecmp(c->argv[2]->ptr,"dir")) { if (chdir((char*)o->ptr) == -1) { addReplyErrorFormat(c,"Changing directory: %s", strerror(errno)); return; } - } else if (!strcasecmp(c->argv[2]->ptr,"hash-max-zipmap-entries")) { + } else if (!strcasecmp(c->argv[2]->ptr,"hash-max-ziplist-entries")) { if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt; - server.hash_max_zipmap_entries = ll; - } else if (!strcasecmp(c->argv[2]->ptr,"hash-max-zipmap-value")) { + server.hash_max_ziplist_entries = ll; + } else if (!strcasecmp(c->argv[2]->ptr,"hash-max-ziplist-value")) { if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt; - server.hash_max_zipmap_value = ll; + server.hash_max_ziplist_value = ll; } else if (!strcasecmp(c->argv[2]->ptr,"list-max-ziplist-entries")) { if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt; server.list_max_ziplist_entries = ll; @@ -537,6 +624,83 @@ void configSetCommand(redisClient *c) { } else { goto badfmt; } + } else if (!strcasecmp(c->argv[2]->ptr,"client-output-buffer-limit")) { + int vlen, j; + sds *v = sdssplitlen(o->ptr,sdslen(o->ptr)," ",1,&vlen); + + /* We need a multiple of 4: */ + if (vlen % 4) { + sdsfreesplitres(v,vlen); + goto badfmt; + } + + /* Sanity check of single arguments, so that we either refuse the + * whole configuration string or accept it all, even if a single + * error in a single client class is present. */ + for (j = 0; j < vlen; j++) { + char *eptr; + long val; + + if ((j % 4) == 0) { + if (getClientLimitClassByName(v[j]) == -1) { + sdsfreesplitres(v,vlen); + goto badfmt; + } + } else { + val = strtoll(v[j], &eptr, 10); + if (eptr[0] != '\0' || val < 0) { + sdsfreesplitres(v,vlen); + goto badfmt; + } + } + } + /* Finally set the new config */ + for (j = 0; j < vlen; j += 4) { + int class; + unsigned long long hard, soft; + int soft_seconds; + + class = getClientLimitClassByName(v[j]); + hard = strtoll(v[j+1],NULL,10); + soft = strtoll(v[j+2],NULL,10); + soft_seconds = strtoll(v[j+3],NULL,10); + + server.client_obuf_limits[class].hard_limit_bytes = hard; + server.client_obuf_limits[class].soft_limit_bytes = soft; + server.client_obuf_limits[class].soft_limit_seconds = soft_seconds; + } + sdsfreesplitres(v,vlen); + } else if (!strcasecmp(c->argv[2]->ptr,"stop-writes-on-bgsave-error")) { + int yn = yesnotoi(o->ptr); + + if (yn == -1) goto badfmt; + server.stop_writes_on_bgsave_err = yn; + } else if (!strcasecmp(c->argv[2]->ptr,"repl-ping-slave-period")) { + if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll <= 0) goto badfmt; + server.repl_ping_slave_period = ll; + } else if (!strcasecmp(c->argv[2]->ptr,"repl-timeout")) { + if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll <= 0) goto badfmt; + server.repl_timeout = ll; + } else if (!strcasecmp(c->argv[2]->ptr,"watchdog-period")) { + if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt; + if (ll) + enableWatchdog(ll); + else + disableWatchdog(); + } else if (!strcasecmp(c->argv[2]->ptr,"rdbcompression")) { + int yn = yesnotoi(o->ptr); + + if (yn == -1) goto badfmt; + server.rdb_compression = yn; + } else if (!strcasecmp(c->argv[2]->ptr,"rdbchecksum")) { + int yn = yesnotoi(o->ptr); + + if (yn == -1) goto badfmt; + server.rdb_checksum = yn; + } else if (!strcasecmp(c->argv[2]->ptr,"slave-priority")) { + if (getLongLongFromObject(o,&ll) == REDIS_ERR || + ll <= 0) goto badfmt; + server.slave_priority = ll; } else { addReplyErrorFormat(c,"Unsupported CONFIG parameter: %s", (char*)c->argv[2]->ptr); @@ -551,6 +715,31 @@ badfmt: /* Bad format errors */ (char*)c->argv[2]->ptr); } +#define config_get_string_field(_name,_var) do { \ + if (stringmatch(pattern,_name,0)) { \ + addReplyBulkCString(c,_name); \ + addReplyBulkCString(c,_var ? _var : ""); \ + matches++; \ + } \ +} while(0); + +#define config_get_bool_field(_name,_var) do { \ + if (stringmatch(pattern,_name,0)) { \ + addReplyBulkCString(c,_name); \ + addReplyBulkCString(c,_var ? "yes" : "no"); \ + matches++; \ + } \ +} while(0); + +#define config_get_numerical_field(_name,_var) do { \ + if (stringmatch(pattern,_name,0)) { \ + ll2string(buf,sizeof(buf),_var); \ + addReplyBulkCString(c,_name); \ + addReplyBulkCString(c,buf); \ + matches++; \ + } \ +} while(0); + void configGetCommand(redisClient *c) { robj *o = c->argv[2]; void *replylen = addDeferredMultiBulkLength(c); @@ -559,6 +748,71 @@ void configGetCommand(redisClient *c) { int matches = 0; redisAssertWithInfo(c,o,o->encoding == REDIS_ENCODING_RAW); + /* String values */ + config_get_string_field("dbfilename",server.rdb_filename); + config_get_string_field("requirepass",server.requirepass); + config_get_string_field("masterauth",server.requirepass); + config_get_string_field("bind",server.bindaddr); + config_get_string_field("unixsocket",server.unixsocket); + config_get_string_field("logfile",server.logfile); + config_get_string_field("pidfile",server.pidfile); + + /* Numerical values */ + config_get_numerical_field("maxmemory",server.maxmemory); + config_get_numerical_field("maxmemory-samples",server.maxmemory_samples); + config_get_numerical_field("timeout",server.maxidletime); + config_get_numerical_field("auto-aof-rewrite-percentage", + server.aof_rewrite_perc); + config_get_numerical_field("auto-aof-rewrite-min-size", + server.aof_rewrite_min_size); + config_get_numerical_field("hash-max-ziplist-entries", + server.hash_max_ziplist_entries); + config_get_numerical_field("hash-max-ziplist-value", + server.hash_max_ziplist_value); + config_get_numerical_field("list-max-ziplist-entries", + server.list_max_ziplist_entries); + config_get_numerical_field("list-max-ziplist-value", + server.list_max_ziplist_value); + config_get_numerical_field("set-max-intset-entries", + server.set_max_intset_entries); + config_get_numerical_field("zset-max-ziplist-entries", + server.zset_max_ziplist_entries); + config_get_numerical_field("zset-max-ziplist-value", + server.zset_max_ziplist_value); + config_get_numerical_field("lua-time-limit",server.lua_time_limit); + config_get_numerical_field("slowlog-log-slower-than", + server.slowlog_log_slower_than); + config_get_numerical_field("slowlog-max-len", + server.slowlog_max_len); + config_get_numerical_field("port",server.port); + config_get_numerical_field("databases",server.dbnum); + config_get_numerical_field("repl-ping-slave-period",server.repl_ping_slave_period); + config_get_numerical_field("repl-timeout",server.repl_timeout); + config_get_numerical_field("maxclients",server.maxclients); + config_get_numerical_field("watchdog-period",server.watchdog_period); + config_get_numerical_field("slave-priority",server.slave_priority); + + /* Bool (yes/no) values */ + config_get_bool_field("no-appendfsync-on-rewrite", + server.aof_no_fsync_on_rewrite); + config_get_bool_field("slave-serve-stale-data", + server.repl_serve_stale_data); + config_get_bool_field("slave-read-only", + server.repl_slave_ro); + config_get_bool_field("stop-writes-on-bgsave-error", + server.stop_writes_on_bgsave_err); + config_get_bool_field("daemonize", server.daemonize); + config_get_bool_field("rdbcompression", server.rdb_compression); + config_get_bool_field("rdbchecksum", server.rdb_checksum); + config_get_bool_field("activerehashing", server.activerehashing); + + /* Everything we can't handle with macros follows. */ + + if (stringmatch(pattern,"appendonly",0)) { + addReplyBulkCString(c,"appendonly"); + addReplyBulkCString(c,server.aof_state == REDIS_AOF_OFF ? "no" : "yes"); + matches++; + } if (stringmatch(pattern,"dir",0)) { char buf[1024]; @@ -569,27 +823,6 @@ void configGetCommand(redisClient *c) { addReplyBulkCString(c,buf); matches++; } - if (stringmatch(pattern,"dbfilename",0)) { - addReplyBulkCString(c,"dbfilename"); - addReplyBulkCString(c,server.rdb_filename); - matches++; - } - if (stringmatch(pattern,"requirepass",0)) { - addReplyBulkCString(c,"requirepass"); - addReplyBulkCString(c,server.requirepass); - matches++; - } - if (stringmatch(pattern,"masterauth",0)) { - addReplyBulkCString(c,"masterauth"); - addReplyBulkCString(c,server.masterauth); - matches++; - } - if (stringmatch(pattern,"maxmemory",0)) { - ll2string(buf,sizeof(buf),server.maxmemory); - addReplyBulkCString(c,"maxmemory"); - addReplyBulkCString(c,buf); - matches++; - } if (stringmatch(pattern,"maxmemory-policy",0)) { char *s; @@ -606,28 +839,6 @@ void configGetCommand(redisClient *c) { addReplyBulkCString(c,s); matches++; } - if (stringmatch(pattern,"maxmemory-samples",0)) { - ll2string(buf,sizeof(buf),server.maxmemory_samples); - addReplyBulkCString(c,"maxmemory-samples"); - addReplyBulkCString(c,buf); - matches++; - } - if (stringmatch(pattern,"timeout",0)) { - ll2string(buf,sizeof(buf),server.maxidletime); - addReplyBulkCString(c,"timeout"); - addReplyBulkCString(c,buf); - matches++; - } - if (stringmatch(pattern,"appendonly",0)) { - addReplyBulkCString(c,"appendonly"); - addReplyBulkCString(c,server.aof_state == REDIS_AOF_OFF ? "no" : "yes"); - matches++; - } - if (stringmatch(pattern,"no-appendfsync-on-rewrite",0)) { - addReplyBulkCString(c,"no-appendfsync-on-rewrite"); - addReplyBulkCString(c,server.aof_no_fsync_on_rewrite ? "yes" : "no"); - matches++; - } if (stringmatch(pattern,"appendfsync",0)) { char *policy; @@ -657,71 +868,6 @@ void configGetCommand(redisClient *c) { sdsfree(buf); matches++; } - if (stringmatch(pattern,"auto-aof-rewrite-percentage",0)) { - addReplyBulkCString(c,"auto-aof-rewrite-percentage"); - addReplyBulkLongLong(c,server.aof_rewrite_perc); - matches++; - } - if (stringmatch(pattern,"auto-aof-rewrite-min-size",0)) { - addReplyBulkCString(c,"auto-aof-rewrite-min-size"); - addReplyBulkLongLong(c,server.aof_rewrite_min_size); - matches++; - } - if (stringmatch(pattern,"slave-serve-stale-data",0)) { - addReplyBulkCString(c,"slave-serve-stale-data"); - addReplyBulkCString(c,server.repl_serve_stale_data ? "yes" : "no"); - matches++; - } - if (stringmatch(pattern,"hash-max-zipmap-entries",0)) { - addReplyBulkCString(c,"hash-max-zipmap-entries"); - addReplyBulkLongLong(c,server.hash_max_zipmap_entries); - matches++; - } - if (stringmatch(pattern,"hash-max-zipmap-value",0)) { - addReplyBulkCString(c,"hash-max-zipmap-value"); - addReplyBulkLongLong(c,server.hash_max_zipmap_value); - matches++; - } - if (stringmatch(pattern,"list-max-ziplist-entries",0)) { - addReplyBulkCString(c,"list-max-ziplist-entries"); - addReplyBulkLongLong(c,server.list_max_ziplist_entries); - matches++; - } - if (stringmatch(pattern,"list-max-ziplist-value",0)) { - addReplyBulkCString(c,"list-max-ziplist-value"); - addReplyBulkLongLong(c,server.list_max_ziplist_value); - matches++; - } - if (stringmatch(pattern,"set-max-intset-entries",0)) { - addReplyBulkCString(c,"set-max-intset-entries"); - addReplyBulkLongLong(c,server.set_max_intset_entries); - matches++; - } - if (stringmatch(pattern,"zset-max-ziplist-entries",0)) { - addReplyBulkCString(c,"zset-max-ziplist-entries"); - addReplyBulkLongLong(c,server.zset_max_ziplist_entries); - matches++; - } - if (stringmatch(pattern,"zset-max-ziplist-value",0)) { - addReplyBulkCString(c,"zset-max-ziplist-value"); - addReplyBulkLongLong(c,server.zset_max_ziplist_value); - matches++; - } - if (stringmatch(pattern,"lua-time-limit",0)) { - addReplyBulkCString(c,"lua-time-limit"); - addReplyBulkLongLong(c,server.lua_time_limit); - matches++; - } - if (stringmatch(pattern,"slowlog-log-slower-than",0)) { - addReplyBulkCString(c,"slowlog-log-slower-than"); - addReplyBulkLongLong(c,server.slowlog_log_slower_than); - matches++; - } - if (stringmatch(pattern,"slowlog-max-len",0)) { - addReplyBulkCString(c,"slowlog-max-len"); - addReplyBulkLongLong(c,server.slowlog_max_len); - matches++; - } if (stringmatch(pattern,"loglevel",0)) { char *s; @@ -736,6 +882,43 @@ void configGetCommand(redisClient *c) { addReplyBulkCString(c,s); matches++; } + if (stringmatch(pattern,"client-output-buffer-limit",0)) { + sds buf = sdsempty(); + int j; + + for (j = 0; j < REDIS_CLIENT_LIMIT_NUM_CLASSES; j++) { + buf = sdscatprintf(buf,"%s %llu %llu %ld", + getClientLimitClassName(j), + server.client_obuf_limits[j].hard_limit_bytes, + server.client_obuf_limits[j].soft_limit_bytes, + (long) server.client_obuf_limits[j].soft_limit_seconds); + if (j != REDIS_CLIENT_LIMIT_NUM_CLASSES-1) + buf = sdscatlen(buf," ",1); + } + addReplyBulkCString(c,"client-output-buffer-limit"); + addReplyBulkCString(c,buf); + sdsfree(buf); + matches++; + } + if (stringmatch(pattern,"unixsocketperm",0)) { + char buf[32]; + snprintf(buf,sizeof(buf),"%o",server.unixsocketperm); + addReplyBulkCString(c,"unixsocketperm"); + addReplyBulkCString(c,buf); + matches++; + } + if (stringmatch(pattern,"slaveof",0)) { + char buf[256]; + + addReplyBulkCString(c,"slaveof"); + if (server.masterhost) + snprintf(buf,sizeof(buf),"%s %d", + server.masterhost, server.masterport); + else + buf[0] = '\0'; + addReplyBulkCString(c,buf); + matches++; + } setDeferredMultiBulkLength(c,replylen,matches*2); } @@ -753,6 +936,9 @@ void configCommand(redisClient *c) { server.stat_numcommands = 0; server.stat_numconnections = 0; server.stat_expiredkeys = 0; + server.stat_rejected_conn = 0; + server.stat_fork_time = 0; + server.aof_delayed_fsync = 0; resetCommandTableStats(); addReply(c,shared.ok); } else {