1 /* Configuration file parsing and CONFIG GET/SET commands implementation. 
   3  * Copyright (c) 2009-2012, Salvatore Sanfilippo <antirez at gmail dot com> 
   6  * Redistribution and use in source and binary forms, with or without 
   7  * modification, are permitted provided that the following conditions are met: 
   9  *   * Redistributions of source code must retain the above copyright notice, 
  10  *     this list of conditions and the following disclaimer. 
  11  *   * Redistributions in binary form must reproduce the above copyright 
  12  *     notice, this list of conditions and the following disclaimer in the 
  13  *     documentation and/or other materials provided with the distribution. 
  14  *   * Neither the name of Redis nor the names of its contributors may be used 
  15  *     to endorse or promote products derived from this software without 
  16  *     specific prior written permission. 
  18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
  19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
  20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
  21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
  22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
  23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
  24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
  25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
  26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
  27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
  28  * POSSIBILITY OF SUCH DAMAGE. 
  34 /*----------------------------------------------------------------------------- 
  36  *----------------------------------------------------------------------------*/ 
  38 int yesnotoi(char *s
) { 
  39     if (!strcasecmp(s
,"yes")) return 1; 
  40     else if (!strcasecmp(s
,"no")) return 0; 
  44 void appendServerSaveParams(time_t seconds
, int changes
) { 
  45     server
.saveparams 
= zrealloc(server
.saveparams
,sizeof(struct saveparam
)*(server
.saveparamslen
+1)); 
  46     server
.saveparams
[server
.saveparamslen
].seconds 
= seconds
; 
  47     server
.saveparams
[server
.saveparamslen
].changes 
= changes
; 
  48     server
.saveparamslen
++; 
  51 void resetServerSaveParams() { 
  52     zfree(server
.saveparams
); 
  53     server
.saveparams 
= NULL
; 
  54     server
.saveparamslen 
= 0; 
  57 void loadServerConfigFromString(char *config
) { 
  59     int linenum 
= 0, totlines
, i
; 
  62     lines 
= sdssplitlen(config
,strlen(config
),"\n",1,&totlines
); 
  64     for (i 
= 0; i 
< totlines
; i
++) { 
  69         lines
[i
] = sdstrim(lines
[i
]," \t\r\n"); 
  71         /* Skip comments and blank lines*/ 
  72         if (lines
[i
][0] == '#' || lines
[i
][0] == '\0') continue; 
  74         /* Split into arguments */ 
  75         argv 
= sdssplitargs(lines
[i
],&argc
); 
  78         /* Execute config directives */ 
  79         if (!strcasecmp(argv
[0],"timeout") && argc 
== 2) { 
  80             server
.maxidletime 
= atoi(argv
[1]); 
  81             if (server
.maxidletime 
< 0) { 
  82                 err 
= "Invalid timeout value"; goto loaderr
; 
  84         } else if (!strcasecmp(argv
[0],"port") && argc 
== 2) { 
  85             server
.port 
= atoi(argv
[1]); 
  86             if (server
.port 
< 0 || server
.port 
> 65535) { 
  87                 err 
= "Invalid port"; goto loaderr
; 
  89         } else if (!strcasecmp(argv
[0],"bind") && argc 
== 2) { 
  90             server
.bindaddr 
= zstrdup(argv
[1]); 
  91         } else if (!strcasecmp(argv
[0],"unixsocket") && argc 
== 2) { 
  92             server
.unixsocket 
= zstrdup(argv
[1]); 
  93         } else if (!strcasecmp(argv
[0],"unixsocketperm") && argc 
== 2) { 
  95             server
.unixsocketperm 
= (mode_t
)strtol(argv
[1], NULL
, 8); 
  96             if (errno 
|| server
.unixsocketperm 
> 0777) { 
  97                 err 
= "Invalid socket file permissions"; goto loaderr
; 
  99         } else if (!strcasecmp(argv
[0],"save")) { 
 101                 int seconds 
= atoi(argv
[1]); 
 102                 int changes 
= atoi(argv
[2]); 
 103                 if (seconds 
< 1 || changes 
< 0) { 
 104                     err 
= "Invalid save parameters"; goto loaderr
; 
 106                 appendServerSaveParams(seconds
,changes
); 
 107             } else if (argc 
== 2 && !strcasecmp(argv
[1],"")) { 
 108                 resetServerSaveParams(); 
 110         } else if (!strcasecmp(argv
[0],"dir") && argc 
== 2) { 
 111             if (chdir(argv
[1]) == -1) { 
 112                 redisLog(REDIS_WARNING
,"Can't chdir to '%s': %s", 
 113                     argv
[1], strerror(errno
)); 
 116         } else if (!strcasecmp(argv
[0],"loglevel") && argc 
== 2) { 
 117             if (!strcasecmp(argv
[1],"debug")) server
.verbosity 
= REDIS_DEBUG
; 
 118             else if (!strcasecmp(argv
[1],"verbose")) server
.verbosity 
= REDIS_VERBOSE
; 
 119             else if (!strcasecmp(argv
[1],"notice")) server
.verbosity 
= REDIS_NOTICE
; 
 120             else if (!strcasecmp(argv
[1],"warning")) server
.verbosity 
= REDIS_WARNING
; 
 122                 err 
= "Invalid log level. Must be one of debug, notice, warning"; 
 125         } else if (!strcasecmp(argv
[0],"logfile") && argc 
== 2) { 
 128             server
.logfile 
= zstrdup(argv
[1]); 
 129             if (!strcasecmp(server
.logfile
,"stdout")) { 
 130                 zfree(server
.logfile
); 
 131                 server
.logfile 
= NULL
; 
 133             if (server
.logfile
) { 
 134                 /* Test if we are able to open the file. The server will not 
 135                  * be able to abort just for this problem later... */ 
 136                 logfp 
= fopen(server
.logfile
,"a"); 
 138                     err 
= sdscatprintf(sdsempty(), 
 139                         "Can't open the log file: %s", strerror(errno
)); 
 144         } else if (!strcasecmp(argv
[0],"syslog-enabled") && argc 
== 2) { 
 145             if ((server
.syslog_enabled 
= yesnotoi(argv
[1])) == -1) { 
 146                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 148         } else if (!strcasecmp(argv
[0],"syslog-ident") && argc 
== 2) { 
 149             if (server
.syslog_ident
) zfree(server
.syslog_ident
); 
 150             server
.syslog_ident 
= zstrdup(argv
[1]); 
 151         } else if (!strcasecmp(argv
[0],"syslog-facility") && argc 
== 2) { 
 155             } validSyslogFacilities
[] = { 
 157                 {"local0",  LOG_LOCAL0
}, 
 158                 {"local1",  LOG_LOCAL1
}, 
 159                 {"local2",  LOG_LOCAL2
}, 
 160                 {"local3",  LOG_LOCAL3
}, 
 161                 {"local4",  LOG_LOCAL4
}, 
 162                 {"local5",  LOG_LOCAL5
}, 
 163                 {"local6",  LOG_LOCAL6
}, 
 164                 {"local7",  LOG_LOCAL7
}, 
 169             for (i 
= 0; validSyslogFacilities
[i
].name
; i
++) { 
 170                 if (!strcasecmp(validSyslogFacilities
[i
].name
, argv
[1])) { 
 171                     server
.syslog_facility 
= validSyslogFacilities
[i
].value
; 
 176             if (!validSyslogFacilities
[i
].name
) { 
 177                 err 
= "Invalid log facility. Must be one of USER or between LOCAL0-LOCAL7"; 
 180         } else if (!strcasecmp(argv
[0],"databases") && argc 
== 2) { 
 181             server
.dbnum 
= atoi(argv
[1]); 
 182             if (server
.dbnum 
< 1) { 
 183                 err 
= "Invalid number of databases"; goto loaderr
; 
 185         } else if (!strcasecmp(argv
[0],"include") && argc 
== 2) { 
 186             loadServerConfig(argv
[1],NULL
); 
 187         } else if (!strcasecmp(argv
[0],"maxclients") && argc 
== 2) { 
 188             server
.maxclients 
= atoi(argv
[1]); 
 189             if (server
.maxclients 
< 1) { 
 190                 err 
= "Invalid max clients limit"; goto loaderr
; 
 192         } else if (!strcasecmp(argv
[0],"maxmemory") && argc 
== 2) { 
 193             server
.maxmemory 
= memtoll(argv
[1],NULL
); 
 194         } else if (!strcasecmp(argv
[0],"maxmemory-policy") && argc 
== 2) { 
 195             if (!strcasecmp(argv
[1],"volatile-lru")) { 
 196                 server
.maxmemory_policy 
= REDIS_MAXMEMORY_VOLATILE_LRU
; 
 197             } else if (!strcasecmp(argv
[1],"volatile-random")) { 
 198                 server
.maxmemory_policy 
= REDIS_MAXMEMORY_VOLATILE_RANDOM
; 
 199             } else if (!strcasecmp(argv
[1],"volatile-ttl")) { 
 200                 server
.maxmemory_policy 
= REDIS_MAXMEMORY_VOLATILE_TTL
; 
 201             } else if (!strcasecmp(argv
[1],"allkeys-lru")) { 
 202                 server
.maxmemory_policy 
= REDIS_MAXMEMORY_ALLKEYS_LRU
; 
 203             } else if (!strcasecmp(argv
[1],"allkeys-random")) { 
 204                 server
.maxmemory_policy 
= REDIS_MAXMEMORY_ALLKEYS_RANDOM
; 
 205             } else if (!strcasecmp(argv
[1],"noeviction")) { 
 206                 server
.maxmemory_policy 
= REDIS_MAXMEMORY_NO_EVICTION
; 
 208                 err 
= "Invalid maxmemory policy"; 
 211         } else if (!strcasecmp(argv
[0],"maxmemory-samples") && argc 
== 2) { 
 212             server
.maxmemory_samples 
= atoi(argv
[1]); 
 213             if (server
.maxmemory_samples 
<= 0) { 
 214                 err 
= "maxmemory-samples must be 1 or greater"; 
 217         } else if (!strcasecmp(argv
[0],"slaveof") && argc 
== 3) { 
 218             server
.masterhost 
= sdsnew(argv
[1]); 
 219             server
.masterport 
= atoi(argv
[2]); 
 220             server
.repl_state 
= REDIS_REPL_CONNECT
; 
 221         } else if (!strcasecmp(argv
[0],"repl-ping-slave-period") && argc 
== 2) { 
 222             server
.repl_ping_slave_period 
= atoi(argv
[1]); 
 223             if (server
.repl_ping_slave_period 
<= 0) { 
 224                 err 
= "repl-ping-slave-period must be 1 or greater"; 
 227         } else if (!strcasecmp(argv
[0],"repl-timeout") && argc 
== 2) { 
 228             server
.repl_timeout 
= atoi(argv
[1]); 
 229             if (server
.repl_timeout 
<= 0) { 
 230                 err 
= "repl-timeout must be 1 or greater"; 
 233         } else if (!strcasecmp(argv
[0],"masterauth") && argc 
== 2) { 
 234                 server
.masterauth 
= zstrdup(argv
[1]); 
 235         } else if (!strcasecmp(argv
[0],"slave-serve-stale-data") && argc 
== 2) { 
 236             if ((server
.repl_serve_stale_data 
= yesnotoi(argv
[1])) == -1) { 
 237                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 239         } else if (!strcasecmp(argv
[0],"slave-read-only") && argc 
== 2) { 
 240             if ((server
.repl_slave_ro 
= yesnotoi(argv
[1])) == -1) { 
 241                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 243         } else if (!strcasecmp(argv
[0],"rdbcompression") && argc 
== 2) { 
 244             if ((server
.rdb_compression 
= yesnotoi(argv
[1])) == -1) { 
 245                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 247         } else if (!strcasecmp(argv
[0],"rdbchecksum") && argc 
== 2) { 
 248             if ((server
.rdb_checksum 
= yesnotoi(argv
[1])) == -1) { 
 249                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 251         } else if (!strcasecmp(argv
[0],"activerehashing") && argc 
== 2) { 
 252             if ((server
.activerehashing 
= yesnotoi(argv
[1])) == -1) { 
 253                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 255         } else if (!strcasecmp(argv
[0],"daemonize") && argc 
== 2) { 
 256             if ((server
.daemonize 
= yesnotoi(argv
[1])) == -1) { 
 257                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 259         } else if (!strcasecmp(argv
[0],"keyarchive") && argc 
== 2) { 
 262             if ((yes 
= yesnotoi(argv
[1])) == -1) { 
 263                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 265             server
.mdb_state 
= yes 
? REDIS_MDB_ON 
: REDIS_MDB_OFF
; 
 266         } else if (!strcasecmp(argv
[0],"mdb-environment") && argc 
== 2) { 
 267             zfree(server
.mdb_environment
); 
 268             server
.mdb_environment 
= zstrdup(argv
[1]); 
 269         } else if (!strcasecmp(argv
[0],"mdb-mapsize") && argc 
== 2) { 
 270             server
.mdb_mapsize 
= memtoll(argv
[1], NULL
); 
 271         } else if (!strcasecmp(argv
[0],"appendonly") && argc 
== 2) { 
 274             if ((yes 
= yesnotoi(argv
[1])) == -1) { 
 275                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 277             server
.aof_state 
= yes 
? REDIS_AOF_ON 
: REDIS_AOF_OFF
; 
 278         } else if (!strcasecmp(argv
[0],"appendfilename") && argc 
== 2) { 
 279             zfree(server
.aof_filename
); 
 280             server
.aof_filename 
= zstrdup(argv
[1]); 
 281         } else if (!strcasecmp(argv
[0],"no-appendfsync-on-rewrite") 
 283             if ((server
.aof_no_fsync_on_rewrite
= yesnotoi(argv
[1])) == -1) { 
 284                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 286         } else if (!strcasecmp(argv
[0],"appendfsync") && argc 
== 2) { 
 287             if (!strcasecmp(argv
[1],"no")) { 
 288                 server
.aof_fsync 
= AOF_FSYNC_NO
; 
 289             } else if (!strcasecmp(argv
[1],"always")) { 
 290                 server
.aof_fsync 
= AOF_FSYNC_ALWAYS
; 
 291             } else if (!strcasecmp(argv
[1],"everysec")) { 
 292                 server
.aof_fsync 
= AOF_FSYNC_EVERYSEC
; 
 294                 err 
= "argument must be 'no', 'always' or 'everysec'"; 
 297         } else if (!strcasecmp(argv
[0],"auto-aof-rewrite-percentage") && 
 300             server
.aof_rewrite_perc 
= atoi(argv
[1]); 
 301             if (server
.aof_rewrite_perc 
< 0) { 
 302                 err 
= "Invalid negative percentage for AOF auto rewrite"; 
 305         } else if (!strcasecmp(argv
[0],"auto-aof-rewrite-min-size") && 
 308             server
.aof_rewrite_min_size 
= memtoll(argv
[1],NULL
); 
 309         } else if (!strcasecmp(argv
[0],"requirepass") && argc 
== 2) { 
 310             if (strlen(argv
[1]) > REDIS_AUTHPASS_MAX_LEN
) { 
 311                 err 
= "Password is longer than REDIS_AUTHPASS_MAX_LEN"; 
 314             server
.requirepass 
= zstrdup(argv
[1]); 
 315         } else if (!strcasecmp(argv
[0],"pidfile") && argc 
== 2) { 
 316             zfree(server
.pidfile
); 
 317             server
.pidfile 
= zstrdup(argv
[1]); 
 318         } else if (!strcasecmp(argv
[0],"dbfilename") && argc 
== 2) { 
 319             zfree(server
.rdb_filename
); 
 320             server
.rdb_filename 
= zstrdup(argv
[1]); 
 321         } else if (!strcasecmp(argv
[0],"hash-max-ziplist-entries") && argc 
== 2) { 
 322             server
.hash_max_ziplist_entries 
= memtoll(argv
[1], NULL
); 
 323         } else if (!strcasecmp(argv
[0],"hash-max-ziplist-value") && argc 
== 2) { 
 324             server
.hash_max_ziplist_value 
= memtoll(argv
[1], NULL
); 
 325         } else if (!strcasecmp(argv
[0],"list-max-ziplist-entries") && argc 
== 2){ 
 326             server
.list_max_ziplist_entries 
= memtoll(argv
[1], NULL
); 
 327         } else if (!strcasecmp(argv
[0],"list-max-ziplist-value") && argc 
== 2) { 
 328             server
.list_max_ziplist_value 
= memtoll(argv
[1], NULL
); 
 329         } else if (!strcasecmp(argv
[0],"set-max-intset-entries") && argc 
== 2) { 
 330             server
.set_max_intset_entries 
= memtoll(argv
[1], NULL
); 
 331         } else if (!strcasecmp(argv
[0],"zset-max-ziplist-entries") && argc 
== 2) { 
 332             server
.zset_max_ziplist_entries 
= memtoll(argv
[1], NULL
); 
 333         } else if (!strcasecmp(argv
[0],"zset-max-ziplist-value") && argc 
== 2) { 
 334             server
.zset_max_ziplist_value 
= memtoll(argv
[1], NULL
); 
 335         } else if (!strcasecmp(argv
[0],"rename-command") && argc 
== 3) { 
 336             struct redisCommand 
*cmd 
= lookupCommand(argv
[1]); 
 340                 err 
= "No such command in rename-command"; 
 344             /* If the target command name is the emtpy string we just 
 345              * remove it from the command table. */ 
 346             retval 
= dictDelete(server
.commands
, argv
[1]); 
 347             redisAssert(retval 
== DICT_OK
); 
 349             /* Otherwise we re-add the command under a different name. */ 
 350             if (sdslen(argv
[2]) != 0) { 
 351                 sds copy 
= sdsdup(argv
[2]); 
 353                 retval 
= dictAdd(server
.commands
, copy
, cmd
); 
 354                 if (retval 
!= DICT_OK
) { 
 356                     err 
= "Target command name already exists"; goto loaderr
; 
 359         } else if (!strcasecmp(argv
[0],"lua-time-limit") && argc 
== 2) { 
 360             server
.lua_time_limit 
= strtoll(argv
[1],NULL
,10); 
 361         } else if (!strcasecmp(argv
[0],"slowlog-log-slower-than") && 
 364             server
.slowlog_log_slower_than 
= strtoll(argv
[1],NULL
,10); 
 365         } else if (!strcasecmp(argv
[0],"slowlog-max-len") && argc 
== 2) { 
 366             server
.slowlog_max_len 
= strtoll(argv
[1],NULL
,10); 
 367         } else if (!strcasecmp(argv
[0],"client-output-buffer-limit") && 
 370             int class = getClientLimitClassByName(argv
[1]); 
 371             unsigned long long hard
, soft
; 
 375                 err 
= "Unrecognized client limit class"; 
 378             hard 
= memtoll(argv
[2],NULL
); 
 379             soft 
= memtoll(argv
[3],NULL
); 
 380             soft_seconds 
= atoi(argv
[4]); 
 381             if (soft_seconds 
< 0) { 
 382                 err 
= "Negative number of seconds in soft limt is invalid"; 
 385             server
.client_obuf_limits
[class].hard_limit_bytes 
= hard
; 
 386             server
.client_obuf_limits
[class].soft_limit_bytes 
= soft
; 
 387             server
.client_obuf_limits
[class].soft_limit_seconds 
= soft_seconds
; 
 388         } else if (!strcasecmp(argv
[0],"stop-writes-on-bgsave-error") && 
 390             if ((server
.stop_writes_on_bgsave_err 
= yesnotoi(argv
[1])) == -1) { 
 391                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 393         } else if (!strcasecmp(argv
[0],"slave-priority") && argc 
== 2) { 
 394             server
.slave_priority 
= atoi(argv
[1]); 
 395         } else if (!strcasecmp(argv
[0],"sentinel")) { 
 396             /* argc == 1 is handled by main() as we need to enter the sentinel 
 399                 if (!server
.sentinel_mode
) { 
 400                     err 
= "sentinel directive while not in sentinel mode"; 
 403                 err 
= sentinelHandleConfiguration(argv
+1,argc
-1); 
 404                 if (err
) goto loaderr
; 
 407             err 
= "Bad directive or wrong number of arguments"; goto loaderr
; 
 409         sdsfreesplitres(argv
,argc
); 
 411     sdsfreesplitres(lines
,totlines
); 
 415     fprintf(stderr
, "\n*** FATAL CONFIG FILE ERROR ***\n"); 
 416     fprintf(stderr
, "Reading the configuration file, at line %d\n", linenum
); 
 417     fprintf(stderr
, ">>> '%s'\n", lines
[i
]); 
 418     fprintf(stderr
, "%s\n", err
); 
 422 /* Load the server configuration from the specified filename. 
 423  * The function appends the additional configuration directives stored 
 424  * in the 'options' string to the config file before loading. 
 426  * Both filename and options can be NULL, in such a case are considered 
 427  * emtpy. This way loadServerConfig can be used to just load a file or 
 428  * just load a string. */ 
 429 void loadServerConfig(char *filename
, char *options
) { 
 430     sds config 
= sdsempty(); 
 431     char buf
[REDIS_CONFIGLINE_MAX
+1]; 
 433     /* Load the file content */ 
 437         if (filename
[0] == '-' && filename
[1] == '\0') { 
 440             if ((fp 
= fopen(filename
,"r")) == NULL
) { 
 441                 redisLog(REDIS_WARNING
, 
 442                     "Fatal error, can't open config file '%s'", filename
); 
 446         while(fgets(buf
,REDIS_CONFIGLINE_MAX
+1,fp
) != NULL
) 
 447             config 
= sdscat(config
,buf
); 
 448         if (fp 
!= stdin
) fclose(fp
); 
 450     /* Append the additional options */ 
 452         config 
= sdscat(config
,"\n"); 
 453         config 
= sdscat(config
,options
); 
 455     loadServerConfigFromString(config
); 
 459 /*----------------------------------------------------------------------------- 
 460  * CONFIG command for remote configuration 
 461  *----------------------------------------------------------------------------*/ 
 463 void configSetCommand(redisClient 
*c
) { 
 466     redisAssertWithInfo(c
,c
->argv
[2],c
->argv
[2]->encoding 
== REDIS_ENCODING_RAW
); 
 467     redisAssertWithInfo(c
,c
->argv
[2],c
->argv
[3]->encoding 
== REDIS_ENCODING_RAW
); 
 470     if (!strcasecmp(c
->argv
[2]->ptr
,"dbfilename")) { 
 471         zfree(server
.rdb_filename
); 
 472         server
.rdb_filename 
= zstrdup(o
->ptr
); 
 473     } else if (!strcasecmp(c
->argv
[2]->ptr
,"requirepass")) { 
 474         if (sdslen(o
->ptr
) > REDIS_AUTHPASS_MAX_LEN
) goto badfmt
; 
 475         zfree(server
.requirepass
); 
 476         server
.requirepass 
= ((char*)o
->ptr
)[0] ? zstrdup(o
->ptr
) : NULL
; 
 477     } else if (!strcasecmp(c
->argv
[2]->ptr
,"masterauth")) { 
 478         zfree(server
.masterauth
); 
 479         server
.masterauth 
= zstrdup(o
->ptr
); 
 480     } else if (!strcasecmp(c
->argv
[2]->ptr
,"maxmemory")) { 
 481         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| 
 483         server
.maxmemory 
= ll
; 
 484         if (server
.maxmemory
) { 
 485             if (server
.maxmemory 
< zmalloc_used_memory()) { 
 486                 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."); 
 488             freeMemoryIfNeeded(); 
 490     } else if (!strcasecmp(c
->argv
[2]->ptr
,"maxmemory-policy")) { 
 491         if (!strcasecmp(o
->ptr
,"volatile-lru")) { 
 492             server
.maxmemory_policy 
= REDIS_MAXMEMORY_VOLATILE_LRU
; 
 493         } else if (!strcasecmp(o
->ptr
,"volatile-random")) { 
 494             server
.maxmemory_policy 
= REDIS_MAXMEMORY_VOLATILE_RANDOM
; 
 495         } else if (!strcasecmp(o
->ptr
,"volatile-ttl")) { 
 496             server
.maxmemory_policy 
= REDIS_MAXMEMORY_VOLATILE_TTL
; 
 497         } else if (!strcasecmp(o
->ptr
,"allkeys-lru")) { 
 498             server
.maxmemory_policy 
= REDIS_MAXMEMORY_ALLKEYS_LRU
; 
 499         } else if (!strcasecmp(o
->ptr
,"allkeys-random")) { 
 500             server
.maxmemory_policy 
= REDIS_MAXMEMORY_ALLKEYS_RANDOM
; 
 501         } else if (!strcasecmp(o
->ptr
,"noeviction")) { 
 502             server
.maxmemory_policy 
= REDIS_MAXMEMORY_NO_EVICTION
; 
 506     } else if (!strcasecmp(c
->argv
[2]->ptr
,"maxmemory-samples")) { 
 507         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| 
 508             ll 
<= 0) goto badfmt
; 
 509         server
.maxmemory_samples 
= ll
; 
 510     } else if (!strcasecmp(c
->argv
[2]->ptr
,"timeout")) { 
 511         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| 
 512             ll 
< 0 || ll 
> LONG_MAX
) goto badfmt
; 
 513         server
.maxidletime 
= ll
; 
 514     } else if (!strcasecmp(c
->argv
[2]->ptr
,"appendfsync")) { 
 515         if (!strcasecmp(o
->ptr
,"no")) { 
 516             server
.aof_fsync 
= AOF_FSYNC_NO
; 
 517         } else if (!strcasecmp(o
->ptr
,"everysec")) { 
 518             server
.aof_fsync 
= AOF_FSYNC_EVERYSEC
; 
 519         } else if (!strcasecmp(o
->ptr
,"always")) { 
 520             server
.aof_fsync 
= AOF_FSYNC_ALWAYS
; 
 524     } else if (!strcasecmp(c
->argv
[2]->ptr
,"no-appendfsync-on-rewrite")) { 
 525         int yn 
= yesnotoi(o
->ptr
); 
 527         if (yn 
== -1) goto badfmt
; 
 528         server
.aof_no_fsync_on_rewrite 
= yn
; 
 529     } else if (!strcasecmp(c
->argv
[2]->ptr
,"appendonly")) { 
 530         int enable 
= yesnotoi(o
->ptr
); 
 532         if (enable 
== -1) goto badfmt
; 
 533         if (enable 
== 0 && server
.aof_state 
!= REDIS_AOF_OFF
) { 
 535         } else if (enable 
&& server
.aof_state 
== REDIS_AOF_OFF
) { 
 536             if (startAppendOnly() == REDIS_ERR
) { 
 538                     "Unable to turn on AOF. Check server logs."); 
 542     } else if (!strcasecmp(c
->argv
[2]->ptr
,"auto-aof-rewrite-percentage")) { 
 543         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 544         server
.aof_rewrite_perc 
= ll
; 
 545     } else if (!strcasecmp(c
->argv
[2]->ptr
,"auto-aof-rewrite-min-size")) { 
 546         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 547         server
.aof_rewrite_min_size 
= ll
; 
 548     } else if (!strcasecmp(c
->argv
[2]->ptr
,"save")) { 
 550         sds 
*v 
= sdssplitlen(o
->ptr
,sdslen(o
->ptr
)," ",1,&vlen
); 
 552         /* Perform sanity check before setting the new config: 
 553          * - Even number of args 
 554          * - Seconds >= 1, changes >= 0 */ 
 556             sdsfreesplitres(v
,vlen
); 
 559         for (j 
= 0; j 
< vlen
; j
++) { 
 563             val 
= strtoll(v
[j
], &eptr
, 10); 
 564             if (eptr
[0] != '\0' || 
 565                 ((j 
& 1) == 0 && val 
< 1) || 
 566                 ((j 
& 1) == 1 && val 
< 0)) { 
 567                 sdsfreesplitres(v
,vlen
); 
 571         /* Finally set the new config */ 
 572         resetServerSaveParams(); 
 573         for (j 
= 0; j 
< vlen
; j 
+= 2) { 
 577             seconds 
= strtoll(v
[j
],NULL
,10); 
 578             changes 
= strtoll(v
[j
+1],NULL
,10); 
 579             appendServerSaveParams(seconds
, changes
); 
 581         sdsfreesplitres(v
,vlen
); 
 582     } else if (!strcasecmp(c
->argv
[2]->ptr
,"slave-serve-stale-data")) { 
 583         int yn 
= yesnotoi(o
->ptr
); 
 585         if (yn 
== -1) goto badfmt
; 
 586         server
.repl_serve_stale_data 
= yn
; 
 587     } else if (!strcasecmp(c
->argv
[2]->ptr
,"slave-read-only")) { 
 588         int yn 
= yesnotoi(o
->ptr
); 
 590         if (yn 
== -1) goto badfmt
; 
 591         server
.repl_slave_ro 
= yn
; 
 592     } else if (!strcasecmp(c
->argv
[2]->ptr
,"dir")) { 
 593         if (chdir((char*)o
->ptr
) == -1) { 
 594             addReplyErrorFormat(c
,"Changing directory: %s", strerror(errno
)); 
 597     } else if (!strcasecmp(c
->argv
[2]->ptr
,"hash-max-ziplist-entries")) { 
 598         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 599         server
.hash_max_ziplist_entries 
= ll
; 
 600     } else if (!strcasecmp(c
->argv
[2]->ptr
,"hash-max-ziplist-value")) { 
 601         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 602         server
.hash_max_ziplist_value 
= ll
; 
 603     } else if (!strcasecmp(c
->argv
[2]->ptr
,"list-max-ziplist-entries")) { 
 604         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 605         server
.list_max_ziplist_entries 
= ll
; 
 606     } else if (!strcasecmp(c
->argv
[2]->ptr
,"list-max-ziplist-value")) { 
 607         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 608         server
.list_max_ziplist_value 
= ll
; 
 609     } else if (!strcasecmp(c
->argv
[2]->ptr
,"set-max-intset-entries")) { 
 610         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 611         server
.set_max_intset_entries 
= ll
; 
 612     } else if (!strcasecmp(c
->argv
[2]->ptr
,"zset-max-ziplist-entries")) { 
 613         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 614         server
.zset_max_ziplist_entries 
= ll
; 
 615     } else if (!strcasecmp(c
->argv
[2]->ptr
,"zset-max-ziplist-value")) { 
 616         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 617         server
.zset_max_ziplist_value 
= ll
; 
 618     } else if (!strcasecmp(c
->argv
[2]->ptr
,"lua-time-limit")) { 
 619         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 620         server
.lua_time_limit 
= ll
; 
 621     } else if (!strcasecmp(c
->argv
[2]->ptr
,"slowlog-log-slower-than")) { 
 622         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR
) goto badfmt
; 
 623         server
.slowlog_log_slower_than 
= ll
; 
 624     } else if (!strcasecmp(c
->argv
[2]->ptr
,"slowlog-max-len")) { 
 625         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 626         server
.slowlog_max_len 
= (unsigned)ll
; 
 627     } else if (!strcasecmp(c
->argv
[2]->ptr
,"loglevel")) { 
 628         if (!strcasecmp(o
->ptr
,"warning")) { 
 629             server
.verbosity 
= REDIS_WARNING
; 
 630         } else if (!strcasecmp(o
->ptr
,"notice")) { 
 631             server
.verbosity 
= REDIS_NOTICE
; 
 632         } else if (!strcasecmp(o
->ptr
,"verbose")) { 
 633             server
.verbosity 
= REDIS_VERBOSE
; 
 634         } else if (!strcasecmp(o
->ptr
,"debug")) { 
 635             server
.verbosity 
= REDIS_DEBUG
; 
 639     } else if (!strcasecmp(c
->argv
[2]->ptr
,"client-output-buffer-limit")) { 
 641         sds 
*v 
= sdssplitlen(o
->ptr
,sdslen(o
->ptr
)," ",1,&vlen
); 
 643         /* We need a multiple of 4: <class> <hard> <soft> <soft_seconds> */ 
 645             sdsfreesplitres(v
,vlen
); 
 649         /* Sanity check of single arguments, so that we either refuse the 
 650          * whole configuration string or accept it all, even if a single 
 651          * error in a single client class is present. */ 
 652         for (j 
= 0; j 
< vlen
; j
++) { 
 657                 if (getClientLimitClassByName(v
[j
]) == -1) { 
 658                     sdsfreesplitres(v
,vlen
); 
 662                 val 
= strtoll(v
[j
], &eptr
, 10); 
 663                 if (eptr
[0] != '\0' || val 
< 0) { 
 664                     sdsfreesplitres(v
,vlen
); 
 669         /* Finally set the new config */ 
 670         for (j 
= 0; j 
< vlen
; j 
+= 4) { 
 672             unsigned long long hard
, soft
; 
 675             class = getClientLimitClassByName(v
[j
]); 
 676             hard 
= strtoll(v
[j
+1],NULL
,10); 
 677             soft 
= strtoll(v
[j
+2],NULL
,10); 
 678             soft_seconds 
= strtoll(v
[j
+3],NULL
,10); 
 680             server
.client_obuf_limits
[class].hard_limit_bytes 
= hard
; 
 681             server
.client_obuf_limits
[class].soft_limit_bytes 
= soft
; 
 682             server
.client_obuf_limits
[class].soft_limit_seconds 
= soft_seconds
; 
 684         sdsfreesplitres(v
,vlen
); 
 685     } else if (!strcasecmp(c
->argv
[2]->ptr
,"stop-writes-on-bgsave-error")) { 
 686         int yn 
= yesnotoi(o
->ptr
); 
 688         if (yn 
== -1) goto badfmt
; 
 689         server
.stop_writes_on_bgsave_err 
= yn
; 
 690     } else if (!strcasecmp(c
->argv
[2]->ptr
,"repl-ping-slave-period")) { 
 691         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
<= 0) goto badfmt
; 
 692         server
.repl_ping_slave_period 
= ll
; 
 693     } else if (!strcasecmp(c
->argv
[2]->ptr
,"repl-timeout")) { 
 694         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
<= 0) goto badfmt
; 
 695         server
.repl_timeout 
= ll
; 
 696     } else if (!strcasecmp(c
->argv
[2]->ptr
,"watchdog-period")) { 
 697         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 702     } else if (!strcasecmp(c
->argv
[2]->ptr
,"rdbcompression")) { 
 703         int yn 
= yesnotoi(o
->ptr
); 
 705         if (yn 
== -1) goto badfmt
; 
 706         server
.rdb_compression 
= yn
; 
 707     } else if (!strcasecmp(c
->argv
[2]->ptr
,"rdbchecksum")) { 
 708         int yn 
= yesnotoi(o
->ptr
); 
 710         if (yn 
== -1) goto badfmt
; 
 711         server
.rdb_checksum 
= yn
; 
 712     } else if (!strcasecmp(c
->argv
[2]->ptr
,"slave-priority")) { 
 713         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| 
 714             ll 
<= 0) goto badfmt
; 
 715         server
.slave_priority 
= ll
; 
 717         addReplyErrorFormat(c
,"Unsupported CONFIG parameter: %s", 
 718             (char*)c
->argv
[2]->ptr
); 
 721     addReply(c
,shared
.ok
); 
 724 badfmt
: /* Bad format errors */ 
 725     addReplyErrorFormat(c
,"Invalid argument '%s' for CONFIG SET '%s'", 
 727             (char*)c
->argv
[2]->ptr
); 
 730 #define config_get_string_field(_name,_var) do { \ 
 731     if (stringmatch(pattern,_name,0)) { \ 
 732         addReplyBulkCString(c,_name); \ 
 733         addReplyBulkCString(c,_var ? _var : ""); \ 
 738 #define config_get_bool_field(_name,_var) do { \ 
 739     if (stringmatch(pattern,_name,0)) { \ 
 740         addReplyBulkCString(c,_name); \ 
 741         addReplyBulkCString(c,_var ? "yes" : "no"); \ 
 746 #define config_get_numerical_field(_name,_var) do { \ 
 747     if (stringmatch(pattern,_name,0)) { \ 
 748         ll2string(buf,sizeof(buf),_var); \ 
 749         addReplyBulkCString(c,_name); \ 
 750         addReplyBulkCString(c,buf); \ 
 755 void configGetCommand(redisClient 
*c
) { 
 756     robj 
*o 
= c
->argv
[2]; 
 757     void *replylen 
= addDeferredMultiBulkLength(c
); 
 758     char *pattern 
= o
->ptr
; 
 761     redisAssertWithInfo(c
,o
,o
->encoding 
== REDIS_ENCODING_RAW
); 
 764     config_get_string_field("dbfilename",server
.rdb_filename
); 
 765     config_get_string_field("requirepass",server
.requirepass
); 
 766     config_get_string_field("masterauth",server
.requirepass
); 
 767     config_get_string_field("bind",server
.bindaddr
); 
 768     config_get_string_field("unixsocket",server
.unixsocket
); 
 769     config_get_string_field("logfile",server
.logfile
); 
 770     config_get_string_field("pidfile",server
.pidfile
); 
 772     /* Numerical values */ 
 773     config_get_numerical_field("maxmemory",server
.maxmemory
); 
 774     config_get_numerical_field("maxmemory-samples",server
.maxmemory_samples
); 
 775     config_get_numerical_field("timeout",server
.maxidletime
); 
 776     config_get_numerical_field("auto-aof-rewrite-percentage", 
 777             server
.aof_rewrite_perc
); 
 778     config_get_numerical_field("auto-aof-rewrite-min-size", 
 779             server
.aof_rewrite_min_size
); 
 780     config_get_numerical_field("hash-max-ziplist-entries", 
 781             server
.hash_max_ziplist_entries
); 
 782     config_get_numerical_field("hash-max-ziplist-value", 
 783             server
.hash_max_ziplist_value
); 
 784     config_get_numerical_field("list-max-ziplist-entries", 
 785             server
.list_max_ziplist_entries
); 
 786     config_get_numerical_field("list-max-ziplist-value", 
 787             server
.list_max_ziplist_value
); 
 788     config_get_numerical_field("set-max-intset-entries", 
 789             server
.set_max_intset_entries
); 
 790     config_get_numerical_field("zset-max-ziplist-entries", 
 791             server
.zset_max_ziplist_entries
); 
 792     config_get_numerical_field("zset-max-ziplist-value", 
 793             server
.zset_max_ziplist_value
); 
 794     config_get_numerical_field("lua-time-limit",server
.lua_time_limit
); 
 795     config_get_numerical_field("slowlog-log-slower-than", 
 796             server
.slowlog_log_slower_than
); 
 797     config_get_numerical_field("slowlog-max-len", 
 798             server
.slowlog_max_len
); 
 799     config_get_numerical_field("port",server
.port
); 
 800     config_get_numerical_field("databases",server
.dbnum
); 
 801     config_get_numerical_field("repl-ping-slave-period",server
.repl_ping_slave_period
); 
 802     config_get_numerical_field("repl-timeout",server
.repl_timeout
); 
 803     config_get_numerical_field("maxclients",server
.maxclients
); 
 804     config_get_numerical_field("watchdog-period",server
.watchdog_period
); 
 805     config_get_numerical_field("slave-priority",server
.slave_priority
); 
 807     /* Bool (yes/no) values */ 
 808     config_get_bool_field("no-appendfsync-on-rewrite", 
 809             server
.aof_no_fsync_on_rewrite
); 
 810     config_get_bool_field("slave-serve-stale-data", 
 811             server
.repl_serve_stale_data
); 
 812     config_get_bool_field("slave-read-only", 
 813             server
.repl_slave_ro
); 
 814     config_get_bool_field("stop-writes-on-bgsave-error", 
 815             server
.stop_writes_on_bgsave_err
); 
 816     config_get_bool_field("daemonize", server
.daemonize
); 
 817     config_get_bool_field("rdbcompression", server
.rdb_compression
); 
 818     config_get_bool_field("rdbchecksum", server
.rdb_checksum
); 
 819     config_get_bool_field("activerehashing", server
.activerehashing
); 
 821     /* Everything we can't handle with macros follows. */ 
 823     if (stringmatch(pattern
,"appendonly",0)) { 
 824         addReplyBulkCString(c
,"appendonly"); 
 825         addReplyBulkCString(c
,server
.aof_state 
== REDIS_AOF_OFF 
? "no" : "yes"); 
 828     if (stringmatch(pattern
,"dir",0)) { 
 831         if (getcwd(buf
,sizeof(buf
)) == NULL
) 
 834         addReplyBulkCString(c
,"dir"); 
 835         addReplyBulkCString(c
,buf
); 
 838     if (stringmatch(pattern
,"maxmemory-policy",0)) { 
 841         switch(server
.maxmemory_policy
) { 
 842         case REDIS_MAXMEMORY_VOLATILE_LRU
: s 
= "volatile-lru"; break; 
 843         case REDIS_MAXMEMORY_VOLATILE_TTL
: s 
= "volatile-ttl"; break; 
 844         case REDIS_MAXMEMORY_VOLATILE_RANDOM
: s 
= "volatile-random"; break; 
 845         case REDIS_MAXMEMORY_ALLKEYS_LRU
: s 
= "allkeys-lru"; break; 
 846         case REDIS_MAXMEMORY_ALLKEYS_RANDOM
: s 
= "allkeys-random"; break; 
 847         case REDIS_MAXMEMORY_NO_EVICTION
: s 
= "noeviction"; break; 
 848         default: s 
= "unknown"; break; /* too harmless to panic */ 
 850         addReplyBulkCString(c
,"maxmemory-policy"); 
 851         addReplyBulkCString(c
,s
); 
 854     if (stringmatch(pattern
,"appendfsync",0)) { 
 857         switch(server
.aof_fsync
) { 
 858         case AOF_FSYNC_NO
: policy 
= "no"; break; 
 859         case AOF_FSYNC_EVERYSEC
: policy 
= "everysec"; break; 
 860         case AOF_FSYNC_ALWAYS
: policy 
= "always"; break; 
 861         default: policy 
= "unknown"; break; /* too harmless to panic */ 
 863         addReplyBulkCString(c
,"appendfsync"); 
 864         addReplyBulkCString(c
,policy
); 
 867     if (stringmatch(pattern
,"save",0)) { 
 868         sds buf 
= sdsempty(); 
 871         for (j 
= 0; j 
< server
.saveparamslen
; j
++) { 
 872             buf 
= sdscatprintf(buf
,"%ld %d", 
 873                     server
.saveparams
[j
].seconds
, 
 874                     server
.saveparams
[j
].changes
); 
 875             if (j 
!= server
.saveparamslen
-1) 
 876                 buf 
= sdscatlen(buf
," ",1); 
 878         addReplyBulkCString(c
,"save"); 
 879         addReplyBulkCString(c
,buf
); 
 883     if (stringmatch(pattern
,"loglevel",0)) { 
 886         switch(server
.verbosity
) { 
 887         case REDIS_WARNING
: s 
= "warning"; break; 
 888         case REDIS_VERBOSE
: s 
= "verbose"; break; 
 889         case REDIS_NOTICE
: s 
= "notice"; break; 
 890         case REDIS_DEBUG
: s 
= "debug"; break; 
 891         default: s 
= "unknown"; break; /* too harmless to panic */ 
 893         addReplyBulkCString(c
,"loglevel"); 
 894         addReplyBulkCString(c
,s
); 
 897     if (stringmatch(pattern
,"client-output-buffer-limit",0)) { 
 898         sds buf 
= sdsempty(); 
 901         for (j 
= 0; j 
< REDIS_CLIENT_LIMIT_NUM_CLASSES
; j
++) { 
 902             buf 
= sdscatprintf(buf
,"%s %llu %llu %ld", 
 903                     getClientLimitClassName(j
), 
 904                     server
.client_obuf_limits
[j
].hard_limit_bytes
, 
 905                     server
.client_obuf_limits
[j
].soft_limit_bytes
, 
 906                     (long) server
.client_obuf_limits
[j
].soft_limit_seconds
); 
 907             if (j 
!= REDIS_CLIENT_LIMIT_NUM_CLASSES
-1) 
 908                 buf 
= sdscatlen(buf
," ",1); 
 910         addReplyBulkCString(c
,"client-output-buffer-limit"); 
 911         addReplyBulkCString(c
,buf
); 
 915     if (stringmatch(pattern
,"unixsocketperm",0)) { 
 917         snprintf(buf
,sizeof(buf
),"%o",server
.unixsocketperm
); 
 918         addReplyBulkCString(c
,"unixsocketperm"); 
 919         addReplyBulkCString(c
,buf
); 
 922     if (stringmatch(pattern
,"slaveof",0)) { 
 925         addReplyBulkCString(c
,"slaveof"); 
 926         if (server
.masterhost
) 
 927             snprintf(buf
,sizeof(buf
),"%s %d", 
 928                 server
.masterhost
, server
.masterport
); 
 931         addReplyBulkCString(c
,buf
); 
 934     setDeferredMultiBulkLength(c
,replylen
,matches
*2); 
 937 void configCommand(redisClient 
*c
) { 
 938     if (!strcasecmp(c
->argv
[1]->ptr
,"set")) { 
 939         if (c
->argc 
!= 4) goto badarity
; 
 941     } else if (!strcasecmp(c
->argv
[1]->ptr
,"get")) { 
 942         if (c
->argc 
!= 3) goto badarity
; 
 944     } else if (!strcasecmp(c
->argv
[1]->ptr
,"resetstat")) { 
 945         if (c
->argc 
!= 2) goto badarity
; 
 946         server
.stat_keyspace_hits 
= 0; 
 947         server
.stat_keyspace_misses 
= 0; 
 948         server
.stat_numcommands 
= 0; 
 949         server
.stat_numconnections 
= 0; 
 950         server
.stat_expiredkeys 
= 0; 
 951         server
.stat_rejected_conn 
= 0; 
 952         server
.stat_fork_time 
= 0; 
 953         server
.aof_delayed_fsync 
= 0; 
 954         resetCommandTableStats(); 
 955         addReply(c
,shared
.ok
); 
 958             "CONFIG subcommand must be one of GET, SET, RESETSTAT"); 
 963     addReplyErrorFormat(c
,"Wrong number of arguments for CONFIG %s", 
 964         (char*) c
->argv
[1]->ptr
);