3 /*----------------------------------------------------------------------------- 
   5  *----------------------------------------------------------------------------*/ 
   7 int yesnotoi(char *s
) { 
   8     if (!strcasecmp(s
,"yes")) return 1; 
   9     else if (!strcasecmp(s
,"no")) return 0; 
  13 void appendServerSaveParams(time_t seconds
, int changes
) { 
  14     server
.saveparams 
= zrealloc(server
.saveparams
,sizeof(struct saveparam
)*(server
.saveparamslen
+1)); 
  15     server
.saveparams
[server
.saveparamslen
].seconds 
= seconds
; 
  16     server
.saveparams
[server
.saveparamslen
].changes 
= changes
; 
  17     server
.saveparamslen
++; 
  20 void resetServerSaveParams() { 
  21     zfree(server
.saveparams
); 
  22     server
.saveparams 
= NULL
; 
  23     server
.saveparamslen 
= 0; 
  26 void loadServerConfigFromString(char *config
) { 
  28     int linenum 
= 0, totlines
, i
; 
  31     lines 
= sdssplitlen(config
,strlen(config
),"\n",1,&totlines
); 
  33     for (i 
= 0; i 
< totlines
; i
++) { 
  38         lines
[i
] = sdstrim(lines
[i
]," \t\r\n"); 
  40         /* Skip comments and blank lines*/ 
  41         if (lines
[i
][0] == '#' || lines
[i
][0] == '\0') continue; 
  43         /* Split into arguments */ 
  44         argv 
= sdssplitargs(lines
[i
],&argc
); 
  47         /* Execute config directives */ 
  48         if (!strcasecmp(argv
[0],"timeout") && argc 
== 2) { 
  49             server
.maxidletime 
= atoi(argv
[1]); 
  50             if (server
.maxidletime 
< 0) { 
  51                 err 
= "Invalid timeout value"; goto loaderr
; 
  53         } else if (!strcasecmp(argv
[0],"port") && argc 
== 2) { 
  54             server
.port 
= atoi(argv
[1]); 
  55             if (server
.port 
< 0 || server
.port 
> 65535) { 
  56                 err 
= "Invalid port"; goto loaderr
; 
  58         } else if (!strcasecmp(argv
[0],"bind") && argc 
== 2) { 
  59             server
.bindaddr 
= zstrdup(argv
[1]); 
  60         } else if (!strcasecmp(argv
[0],"unixsocket") && argc 
== 2) { 
  61             server
.unixsocket 
= zstrdup(argv
[1]); 
  62         } else if (!strcasecmp(argv
[0],"unixsocketperm") && argc 
== 2) { 
  64             server
.unixsocketperm 
= (mode_t
)strtol(argv
[1], NULL
, 8); 
  65             if (errno 
|| server
.unixsocketperm 
> 0777) { 
  66                 err 
= "Invalid socket file permissions"; goto loaderr
; 
  68         } else if (!strcasecmp(argv
[0],"save")) { 
  70                 int seconds 
= atoi(argv
[1]); 
  71                 int changes 
= atoi(argv
[2]); 
  72                 if (seconds 
< 1 || changes 
< 0) { 
  73                     err 
= "Invalid save parameters"; goto loaderr
; 
  75                 appendServerSaveParams(seconds
,changes
); 
  76             } else if (argc 
== 2 && !strcasecmp(argv
[1],"")) { 
  77                 resetServerSaveParams(); 
  79         } else if (!strcasecmp(argv
[0],"dir") && argc 
== 2) { 
  80             if (chdir(argv
[1]) == -1) { 
  81                 redisLog(REDIS_WARNING
,"Can't chdir to '%s': %s", 
  82                     argv
[1], strerror(errno
)); 
  85         } else if (!strcasecmp(argv
[0],"loglevel") && argc 
== 2) { 
  86             if (!strcasecmp(argv
[1],"debug")) server
.verbosity 
= REDIS_DEBUG
; 
  87             else if (!strcasecmp(argv
[1],"verbose")) server
.verbosity 
= REDIS_VERBOSE
; 
  88             else if (!strcasecmp(argv
[1],"notice")) server
.verbosity 
= REDIS_NOTICE
; 
  89             else if (!strcasecmp(argv
[1],"warning")) server
.verbosity 
= REDIS_WARNING
; 
  91                 err 
= "Invalid log level. Must be one of debug, notice, warning"; 
  94         } else if (!strcasecmp(argv
[0],"logfile") && argc 
== 2) { 
  97             server
.logfile 
= zstrdup(argv
[1]); 
  98             if (!strcasecmp(server
.logfile
,"stdout")) { 
  99                 zfree(server
.logfile
); 
 100                 server
.logfile 
= NULL
; 
 102             if (server
.logfile
) { 
 103                 /* Test if we are able to open the file. The server will not 
 104                  * be able to abort just for this problem later... */ 
 105                 logfp 
= fopen(server
.logfile
,"a"); 
 107                     err 
= sdscatprintf(sdsempty(), 
 108                         "Can't open the log file: %s", strerror(errno
)); 
 113         } else if (!strcasecmp(argv
[0],"syslog-enabled") && argc 
== 2) { 
 114             if ((server
.syslog_enabled 
= yesnotoi(argv
[1])) == -1) { 
 115                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 117         } else if (!strcasecmp(argv
[0],"syslog-ident") && argc 
== 2) { 
 118             if (server
.syslog_ident
) zfree(server
.syslog_ident
); 
 119             server
.syslog_ident 
= zstrdup(argv
[1]); 
 120         } else if (!strcasecmp(argv
[0],"syslog-facility") && argc 
== 2) { 
 124             } validSyslogFacilities
[] = { 
 126                 {"local0",  LOG_LOCAL0
}, 
 127                 {"local1",  LOG_LOCAL1
}, 
 128                 {"local2",  LOG_LOCAL2
}, 
 129                 {"local3",  LOG_LOCAL3
}, 
 130                 {"local4",  LOG_LOCAL4
}, 
 131                 {"local5",  LOG_LOCAL5
}, 
 132                 {"local6",  LOG_LOCAL6
}, 
 133                 {"local7",  LOG_LOCAL7
}, 
 138             for (i 
= 0; validSyslogFacilities
[i
].name
; i
++) { 
 139                 if (!strcasecmp(validSyslogFacilities
[i
].name
, argv
[1])) { 
 140                     server
.syslog_facility 
= validSyslogFacilities
[i
].value
; 
 145             if (!validSyslogFacilities
[i
].name
) { 
 146                 err 
= "Invalid log facility. Must be one of USER or between LOCAL0-LOCAL7"; 
 149         } else if (!strcasecmp(argv
[0],"databases") && argc 
== 2) { 
 150             server
.dbnum 
= atoi(argv
[1]); 
 151             if (server
.dbnum 
< 1) { 
 152                 err 
= "Invalid number of databases"; goto loaderr
; 
 154         } else if (!strcasecmp(argv
[0],"include") && argc 
== 2) { 
 155             loadServerConfig(argv
[1],NULL
); 
 156         } else if (!strcasecmp(argv
[0],"maxclients") && argc 
== 2) { 
 157             server
.maxclients 
= atoi(argv
[1]); 
 158         } else if (!strcasecmp(argv
[0],"maxmemory") && argc 
== 2) { 
 159             server
.maxmemory 
= memtoll(argv
[1],NULL
); 
 160         } else if (!strcasecmp(argv
[0],"maxmemory-policy") && argc 
== 2) { 
 161             if (!strcasecmp(argv
[1],"volatile-lru")) { 
 162                 server
.maxmemory_policy 
= REDIS_MAXMEMORY_VOLATILE_LRU
; 
 163             } else if (!strcasecmp(argv
[1],"volatile-random")) { 
 164                 server
.maxmemory_policy 
= REDIS_MAXMEMORY_VOLATILE_RANDOM
; 
 165             } else if (!strcasecmp(argv
[1],"volatile-ttl")) { 
 166                 server
.maxmemory_policy 
= REDIS_MAXMEMORY_VOLATILE_TTL
; 
 167             } else if (!strcasecmp(argv
[1],"allkeys-lru")) { 
 168                 server
.maxmemory_policy 
= REDIS_MAXMEMORY_ALLKEYS_LRU
; 
 169             } else if (!strcasecmp(argv
[1],"allkeys-random")) { 
 170                 server
.maxmemory_policy 
= REDIS_MAXMEMORY_ALLKEYS_RANDOM
; 
 171             } else if (!strcasecmp(argv
[1],"noeviction")) { 
 172                 server
.maxmemory_policy 
= REDIS_MAXMEMORY_NO_EVICTION
; 
 174                 err 
= "Invalid maxmemory policy"; 
 177         } else if (!strcasecmp(argv
[0],"maxmemory-samples") && argc 
== 2) { 
 178             server
.maxmemory_samples 
= atoi(argv
[1]); 
 179             if (server
.maxmemory_samples 
<= 0) { 
 180                 err 
= "maxmemory-samples must be 1 or greater"; 
 183         } else if (!strcasecmp(argv
[0],"slaveof") && argc 
== 3) { 
 184             server
.masterhost 
= sdsnew(argv
[1]); 
 185             server
.masterport 
= atoi(argv
[2]); 
 186             server
.repl_state 
= REDIS_REPL_CONNECT
; 
 187         } else if (!strcasecmp(argv
[0],"repl-ping-slave-period") && argc 
== 2) { 
 188             server
.repl_ping_slave_period 
= atoi(argv
[1]); 
 189             if (server
.repl_ping_slave_period 
<= 0) { 
 190                 err 
= "repl-ping-slave-period must be 1 or greater"; 
 193         } else if (!strcasecmp(argv
[0],"repl-timeout") && argc 
== 2) { 
 194             server
.repl_timeout 
= atoi(argv
[1]); 
 195             if (server
.repl_timeout 
<= 0) { 
 196                 err 
= "repl-timeout must be 1 or greater"; 
 199         } else if (!strcasecmp(argv
[0],"masterauth") && argc 
== 2) { 
 200                 server
.masterauth 
= zstrdup(argv
[1]); 
 201         } else if (!strcasecmp(argv
[0],"slave-serve-stale-data") && argc 
== 2) { 
 202             if ((server
.repl_serve_stale_data 
= yesnotoi(argv
[1])) == -1) { 
 203                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 205         } else if (!strcasecmp(argv
[0],"slave-read-only") && argc 
== 2) { 
 206             if ((server
.repl_slave_ro 
= yesnotoi(argv
[1])) == -1) { 
 207                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 209         } else if (!strcasecmp(argv
[0],"rdbcompression") && argc 
== 2) { 
 210             if ((server
.rdb_compression 
= yesnotoi(argv
[1])) == -1) { 
 211                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 213         } else if (!strcasecmp(argv
[0],"activerehashing") && argc 
== 2) { 
 214             if ((server
.activerehashing 
= yesnotoi(argv
[1])) == -1) { 
 215                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 217         } else if (!strcasecmp(argv
[0],"daemonize") && argc 
== 2) { 
 218             if ((server
.daemonize 
= yesnotoi(argv
[1])) == -1) { 
 219                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 221         } else if (!strcasecmp(argv
[0],"appendonly") && argc 
== 2) { 
 224             if ((yes 
= yesnotoi(argv
[1])) == -1) { 
 225                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 227             server
.aof_state 
= yes 
? REDIS_AOF_ON 
: REDIS_AOF_OFF
; 
 228         } else if (!strcasecmp(argv
[0],"appendfilename") && argc 
== 2) { 
 229             zfree(server
.aof_filename
); 
 230             server
.aof_filename 
= zstrdup(argv
[1]); 
 231         } else if (!strcasecmp(argv
[0],"no-appendfsync-on-rewrite") 
 233             if ((server
.aof_no_fsync_on_rewrite
= yesnotoi(argv
[1])) == -1) { 
 234                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 236         } else if (!strcasecmp(argv
[0],"appendfsync") && argc 
== 2) { 
 237             if (!strcasecmp(argv
[1],"no")) { 
 238                 server
.aof_fsync 
= AOF_FSYNC_NO
; 
 239             } else if (!strcasecmp(argv
[1],"always")) { 
 240                 server
.aof_fsync 
= AOF_FSYNC_ALWAYS
; 
 241             } else if (!strcasecmp(argv
[1],"everysec")) { 
 242                 server
.aof_fsync 
= AOF_FSYNC_EVERYSEC
; 
 244                 err 
= "argument must be 'no', 'always' or 'everysec'"; 
 247         } else if (!strcasecmp(argv
[0],"auto-aof-rewrite-percentage") && 
 250             server
.aof_rewrite_perc 
= atoi(argv
[1]); 
 251             if (server
.aof_rewrite_perc 
< 0) { 
 252                 err 
= "Invalid negative percentage for AOF auto rewrite"; 
 255         } else if (!strcasecmp(argv
[0],"auto-aof-rewrite-min-size") && 
 258             server
.aof_rewrite_min_size 
= memtoll(argv
[1],NULL
); 
 259         } else if (!strcasecmp(argv
[0],"requirepass") && argc 
== 2) { 
 260             server
.requirepass 
= zstrdup(argv
[1]); 
 261         } else if (!strcasecmp(argv
[0],"pidfile") && argc 
== 2) { 
 262             zfree(server
.pidfile
); 
 263             server
.pidfile 
= zstrdup(argv
[1]); 
 264         } else if (!strcasecmp(argv
[0],"dbfilename") && argc 
== 2) { 
 265             zfree(server
.rdb_filename
); 
 266             server
.rdb_filename 
= zstrdup(argv
[1]); 
 267         } else if (!strcasecmp(argv
[0],"hash-max-ziplist-entries") && argc 
== 2) { 
 268             server
.hash_max_ziplist_entries 
= memtoll(argv
[1], NULL
); 
 269         } else if (!strcasecmp(argv
[0],"hash-max-ziplist-value") && argc 
== 2) { 
 270             server
.hash_max_ziplist_value 
= memtoll(argv
[1], NULL
); 
 271         } else if (!strcasecmp(argv
[0],"list-max-ziplist-entries") && argc 
== 2){ 
 272             server
.list_max_ziplist_entries 
= memtoll(argv
[1], NULL
); 
 273         } else if (!strcasecmp(argv
[0],"list-max-ziplist-value") && argc 
== 2) { 
 274             server
.list_max_ziplist_value 
= memtoll(argv
[1], NULL
); 
 275         } else if (!strcasecmp(argv
[0],"set-max-intset-entries") && argc 
== 2) { 
 276             server
.set_max_intset_entries 
= memtoll(argv
[1], NULL
); 
 277         } else if (!strcasecmp(argv
[0],"zset-max-ziplist-entries") && argc 
== 2) { 
 278             server
.zset_max_ziplist_entries 
= memtoll(argv
[1], NULL
); 
 279         } else if (!strcasecmp(argv
[0],"zset-max-ziplist-value") && argc 
== 2) { 
 280             server
.zset_max_ziplist_value 
= memtoll(argv
[1], NULL
); 
 281         } else if (!strcasecmp(argv
[0],"rename-command") && argc 
== 3) { 
 282             struct redisCommand 
*cmd 
= lookupCommand(argv
[1]); 
 286                 err 
= "No such command in rename-command"; 
 290             /* If the target command name is the emtpy string we just 
 291              * remove it from the command table. */ 
 292             retval 
= dictDelete(server
.commands
, argv
[1]); 
 293             redisAssert(retval 
== DICT_OK
); 
 295             /* Otherwise we re-add the command under a different name. */ 
 296             if (sdslen(argv
[2]) != 0) { 
 297                 sds copy 
= sdsdup(argv
[2]); 
 299                 retval 
= dictAdd(server
.commands
, copy
, cmd
); 
 300                 if (retval 
!= DICT_OK
) { 
 302                     err 
= "Target command name already exists"; goto loaderr
; 
 305         } else if (!strcasecmp(argv
[0],"lua-time-limit") && argc 
== 2) { 
 306             server
.lua_time_limit 
= strtoll(argv
[1],NULL
,10); 
 307         } else if (!strcasecmp(argv
[0],"slowlog-log-slower-than") && 
 310             server
.slowlog_log_slower_than 
= strtoll(argv
[1],NULL
,10); 
 311         } else if (!strcasecmp(argv
[0],"slowlog-max-len") && argc 
== 2) { 
 312             server
.slowlog_max_len 
= strtoll(argv
[1],NULL
,10); 
 313         } else if (!strcasecmp(argv
[0],"client-output-buffer-limit") && 
 316             int class = getClientLimitClassByName(argv
[1]); 
 317             unsigned long long hard
, soft
; 
 321                 err 
= "Unrecognized client limit class"; 
 324             hard 
= memtoll(argv
[2],NULL
); 
 325             soft 
= memtoll(argv
[3],NULL
); 
 326             soft_seconds 
= atoi(argv
[4]); 
 327             if (soft_seconds 
< 0) { 
 328                 err 
= "Negative number of seconds in soft limt is invalid"; 
 331             server
.client_obuf_limits
[class].hard_limit_bytes 
= hard
; 
 332             server
.client_obuf_limits
[class].soft_limit_bytes 
= soft
; 
 333             server
.client_obuf_limits
[class].soft_limit_seconds 
= soft_seconds
; 
 334         } else if (!strcasecmp(argv
[0],"stop-writes-on-bgsave-error") && 
 336             if ((server
.stop_writes_on_bgsave_err 
= yesnotoi(argv
[1])) == -1) { 
 337                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 340             err 
= "Bad directive or wrong number of arguments"; goto loaderr
; 
 342         sdsfreesplitres(argv
,argc
); 
 344     sdsfreesplitres(lines
,totlines
); 
 348     fprintf(stderr
, "\n*** FATAL CONFIG FILE ERROR ***\n"); 
 349     fprintf(stderr
, "Reading the configuration file, at line %d\n", linenum
); 
 350     fprintf(stderr
, ">>> '%s'\n", lines
[i
]); 
 351     fprintf(stderr
, "%s\n", err
); 
 355 /* Load the server configuration from the specified filename. 
 356  * The function appends the additional configuration directives stored 
 357  * in the 'options' string to the config file before loading. 
 359  * Both filename and options can be NULL, in such a case are considered 
 360  * emtpy. This way loadServerConfig can be used to just load a file or 
 361  * just load a string. */ 
 362 void loadServerConfig(char *filename
, char *options
) { 
 363     sds config 
= sdsempty(); 
 364     char buf
[REDIS_CONFIGLINE_MAX
+1]; 
 366     /* Load the file content */ 
 370         if (filename
[0] == '-' && filename
[1] == '\0') { 
 373             if ((fp 
= fopen(filename
,"r")) == NULL
) { 
 374                 redisLog(REDIS_WARNING
, 
 375                     "Fatal error, can't open config file '%s'", filename
); 
 379         while(fgets(buf
,REDIS_CONFIGLINE_MAX
+1,fp
) != NULL
) 
 380             config 
= sdscat(config
,buf
); 
 381         if (fp 
!= stdin
) fclose(fp
); 
 383     /* Append the additional options */ 
 385         config 
= sdscat(config
,"\n"); 
 386         config 
= sdscat(config
,options
); 
 388     loadServerConfigFromString(config
); 
 392 /*----------------------------------------------------------------------------- 
 393  * CONFIG command for remote configuration 
 394  *----------------------------------------------------------------------------*/ 
 396 void configSetCommand(redisClient 
*c
) { 
 399     redisAssertWithInfo(c
,c
->argv
[2],c
->argv
[2]->encoding 
== REDIS_ENCODING_RAW
); 
 400     redisAssertWithInfo(c
,c
->argv
[2],c
->argv
[3]->encoding 
== REDIS_ENCODING_RAW
); 
 403     if (!strcasecmp(c
->argv
[2]->ptr
,"dbfilename")) { 
 404         zfree(server
.rdb_filename
); 
 405         server
.rdb_filename 
= zstrdup(o
->ptr
); 
 406     } else if (!strcasecmp(c
->argv
[2]->ptr
,"requirepass")) { 
 407         zfree(server
.requirepass
); 
 408         server
.requirepass 
= ((char*)o
->ptr
)[0] ? zstrdup(o
->ptr
) : NULL
; 
 409     } else if (!strcasecmp(c
->argv
[2]->ptr
,"masterauth")) { 
 410         zfree(server
.masterauth
); 
 411         server
.masterauth 
= zstrdup(o
->ptr
); 
 412     } else if (!strcasecmp(c
->argv
[2]->ptr
,"maxmemory")) { 
 413         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| 
 415         server
.maxmemory 
= ll
; 
 416         if (server
.maxmemory
) freeMemoryIfNeeded(); 
 417     } else if (!strcasecmp(c
->argv
[2]->ptr
,"maxmemory-policy")) { 
 418         if (!strcasecmp(o
->ptr
,"volatile-lru")) { 
 419             server
.maxmemory_policy 
= REDIS_MAXMEMORY_VOLATILE_LRU
; 
 420         } else if (!strcasecmp(o
->ptr
,"volatile-random")) { 
 421             server
.maxmemory_policy 
= REDIS_MAXMEMORY_VOLATILE_RANDOM
; 
 422         } else if (!strcasecmp(o
->ptr
,"volatile-ttl")) { 
 423             server
.maxmemory_policy 
= REDIS_MAXMEMORY_VOLATILE_TTL
; 
 424         } else if (!strcasecmp(o
->ptr
,"allkeys-lru")) { 
 425             server
.maxmemory_policy 
= REDIS_MAXMEMORY_ALLKEYS_LRU
; 
 426         } else if (!strcasecmp(o
->ptr
,"allkeys-random")) { 
 427             server
.maxmemory_policy 
= REDIS_MAXMEMORY_ALLKEYS_RANDOM
; 
 428         } else if (!strcasecmp(o
->ptr
,"noeviction")) { 
 429             server
.maxmemory_policy 
= REDIS_MAXMEMORY_NO_EVICTION
; 
 433     } else if (!strcasecmp(c
->argv
[2]->ptr
,"maxmemory-samples")) { 
 434         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| 
 435             ll 
<= 0) goto badfmt
; 
 436         server
.maxmemory_samples 
= ll
; 
 437     } else if (!strcasecmp(c
->argv
[2]->ptr
,"timeout")) { 
 438         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| 
 439             ll 
< 0 || ll 
> LONG_MAX
) goto badfmt
; 
 440         server
.maxidletime 
= ll
; 
 441     } else if (!strcasecmp(c
->argv
[2]->ptr
,"appendfsync")) { 
 442         if (!strcasecmp(o
->ptr
,"no")) { 
 443             server
.aof_fsync 
= AOF_FSYNC_NO
; 
 444         } else if (!strcasecmp(o
->ptr
,"everysec")) { 
 445             server
.aof_fsync 
= AOF_FSYNC_EVERYSEC
; 
 446         } else if (!strcasecmp(o
->ptr
,"always")) { 
 447             server
.aof_fsync 
= AOF_FSYNC_ALWAYS
; 
 451     } else if (!strcasecmp(c
->argv
[2]->ptr
,"no-appendfsync-on-rewrite")) { 
 452         int yn 
= yesnotoi(o
->ptr
); 
 454         if (yn 
== -1) goto badfmt
; 
 455         server
.aof_no_fsync_on_rewrite 
= yn
; 
 456     } else if (!strcasecmp(c
->argv
[2]->ptr
,"appendonly")) { 
 457         int enable 
= yesnotoi(o
->ptr
); 
 459         if (enable 
== -1) goto badfmt
; 
 460         if (enable 
== 0 && server
.aof_state 
!= REDIS_AOF_OFF
) { 
 462         } else if (enable 
&& server
.aof_state 
== REDIS_AOF_OFF
) { 
 463             if (startAppendOnly() == REDIS_ERR
) { 
 465                     "Unable to turn on AOF. Check server logs."); 
 469     } else if (!strcasecmp(c
->argv
[2]->ptr
,"auto-aof-rewrite-percentage")) { 
 470         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 471         server
.aof_rewrite_perc 
= ll
; 
 472     } else if (!strcasecmp(c
->argv
[2]->ptr
,"auto-aof-rewrite-min-size")) { 
 473         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 474         server
.aof_rewrite_min_size 
= ll
; 
 475     } else if (!strcasecmp(c
->argv
[2]->ptr
,"save")) { 
 477         sds 
*v 
= sdssplitlen(o
->ptr
,sdslen(o
->ptr
)," ",1,&vlen
); 
 479         /* Perform sanity check before setting the new config: 
 480          * - Even number of args 
 481          * - Seconds >= 1, changes >= 0 */ 
 483             sdsfreesplitres(v
,vlen
); 
 486         for (j 
= 0; j 
< vlen
; j
++) { 
 490             val 
= strtoll(v
[j
], &eptr
, 10); 
 491             if (eptr
[0] != '\0' || 
 492                 ((j 
& 1) == 0 && val 
< 1) || 
 493                 ((j 
& 1) == 1 && val 
< 0)) { 
 494                 sdsfreesplitres(v
,vlen
); 
 498         /* Finally set the new config */ 
 499         resetServerSaveParams(); 
 500         for (j 
= 0; j 
< vlen
; j 
+= 2) { 
 504             seconds 
= strtoll(v
[j
],NULL
,10); 
 505             changes 
= strtoll(v
[j
+1],NULL
,10); 
 506             appendServerSaveParams(seconds
, changes
); 
 508         sdsfreesplitres(v
,vlen
); 
 509     } else if (!strcasecmp(c
->argv
[2]->ptr
,"slave-serve-stale-data")) { 
 510         int yn 
= yesnotoi(o
->ptr
); 
 512         if (yn 
== -1) goto badfmt
; 
 513         server
.repl_serve_stale_data 
= yn
; 
 514     } else if (!strcasecmp(c
->argv
[2]->ptr
,"slave-read-only")) { 
 515         int yn 
= yesnotoi(o
->ptr
); 
 517         if (yn 
== -1) goto badfmt
; 
 518         server
.repl_slave_ro 
= yn
; 
 519     } else if (!strcasecmp(c
->argv
[2]->ptr
,"dir")) { 
 520         if (chdir((char*)o
->ptr
) == -1) { 
 521             addReplyErrorFormat(c
,"Changing directory: %s", strerror(errno
)); 
 524     } else if (!strcasecmp(c
->argv
[2]->ptr
,"hash-max-ziplist-entries")) { 
 525         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 526         server
.hash_max_ziplist_entries 
= ll
; 
 527     } else if (!strcasecmp(c
->argv
[2]->ptr
,"hash-max-ziplist-value")) { 
 528         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 529         server
.hash_max_ziplist_value 
= ll
; 
 530     } else if (!strcasecmp(c
->argv
[2]->ptr
,"list-max-ziplist-entries")) { 
 531         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 532         server
.list_max_ziplist_entries 
= ll
; 
 533     } else if (!strcasecmp(c
->argv
[2]->ptr
,"list-max-ziplist-value")) { 
 534         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 535         server
.list_max_ziplist_value 
= ll
; 
 536     } else if (!strcasecmp(c
->argv
[2]->ptr
,"set-max-intset-entries")) { 
 537         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 538         server
.set_max_intset_entries 
= ll
; 
 539     } else if (!strcasecmp(c
->argv
[2]->ptr
,"zset-max-ziplist-entries")) { 
 540         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 541         server
.zset_max_ziplist_entries 
= ll
; 
 542     } else if (!strcasecmp(c
->argv
[2]->ptr
,"zset-max-ziplist-value")) { 
 543         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 544         server
.zset_max_ziplist_value 
= ll
; 
 545     } else if (!strcasecmp(c
->argv
[2]->ptr
,"lua-time-limit")) { 
 546         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 547         server
.lua_time_limit 
= ll
; 
 548     } else if (!strcasecmp(c
->argv
[2]->ptr
,"slowlog-log-slower-than")) { 
 549         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR
) goto badfmt
; 
 550         server
.slowlog_log_slower_than 
= ll
; 
 551     } else if (!strcasecmp(c
->argv
[2]->ptr
,"slowlog-max-len")) { 
 552         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 553         server
.slowlog_max_len 
= (unsigned)ll
; 
 554     } else if (!strcasecmp(c
->argv
[2]->ptr
,"loglevel")) { 
 555         if (!strcasecmp(o
->ptr
,"warning")) { 
 556             server
.verbosity 
= REDIS_WARNING
; 
 557         } else if (!strcasecmp(o
->ptr
,"notice")) { 
 558             server
.verbosity 
= REDIS_NOTICE
; 
 559         } else if (!strcasecmp(o
->ptr
,"verbose")) { 
 560             server
.verbosity 
= REDIS_VERBOSE
; 
 561         } else if (!strcasecmp(o
->ptr
,"debug")) { 
 562             server
.verbosity 
= REDIS_DEBUG
; 
 566     } else if (!strcasecmp(c
->argv
[2]->ptr
,"client-output-buffer-limit")) { 
 568         sds 
*v 
= sdssplitlen(o
->ptr
,sdslen(o
->ptr
)," ",1,&vlen
); 
 570         /* We need a multiple of 4: <class> <hard> <soft> <soft_seconds> */ 
 572             sdsfreesplitres(v
,vlen
); 
 576         /* Sanity check of single arguments, so that we either refuse the 
 577          * whole configuration string or accept it all, even if a single 
 578          * error in a single client class is present. */ 
 579         for (j 
= 0; j 
< vlen
; j
++) { 
 584                 if (getClientLimitClassByName(v
[j
]) == -1) { 
 585                     sdsfreesplitres(v
,vlen
); 
 589                 val 
= strtoll(v
[j
], &eptr
, 10); 
 590                 if (eptr
[0] != '\0' || val 
< 0) { 
 591                     sdsfreesplitres(v
,vlen
); 
 596         /* Finally set the new config */ 
 597         for (j 
= 0; j 
< vlen
; j 
+= 4) { 
 599             unsigned long long hard
, soft
; 
 602             class = getClientLimitClassByName(v
[j
]); 
 603             hard 
= strtoll(v
[j
+1],NULL
,10); 
 604             soft 
= strtoll(v
[j
+2],NULL
,10); 
 605             soft_seconds 
= strtoll(v
[j
+3],NULL
,10); 
 607             server
.client_obuf_limits
[class].hard_limit_bytes 
= hard
; 
 608             server
.client_obuf_limits
[class].soft_limit_bytes 
= soft
; 
 609             server
.client_obuf_limits
[class].soft_limit_seconds 
= soft_seconds
; 
 611         sdsfreesplitres(v
,vlen
); 
 612     } else if (!strcasecmp(c
->argv
[2]->ptr
,"stop-writes-on-bgsave-error")) { 
 613         int yn 
= yesnotoi(o
->ptr
); 
 615         if (yn 
== -1) goto badfmt
; 
 616         server
.stop_writes_on_bgsave_err 
= yn
; 
 617     } else if (!strcasecmp(c
->argv
[2]->ptr
,"repl-ping-slave-period")) { 
 618         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
<= 0) goto badfmt
; 
 619         server
.repl_ping_slave_period 
= ll
; 
 620     } else if (!strcasecmp(c
->argv
[2]->ptr
,"repl-timeout")) { 
 621         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
<= 0) goto badfmt
; 
 622         server
.repl_timeout 
= ll
; 
 624         addReplyErrorFormat(c
,"Unsupported CONFIG parameter: %s", 
 625             (char*)c
->argv
[2]->ptr
); 
 628     addReply(c
,shared
.ok
); 
 631 badfmt
: /* Bad format errors */ 
 632     addReplyErrorFormat(c
,"Invalid argument '%s' for CONFIG SET '%s'", 
 634             (char*)c
->argv
[2]->ptr
); 
 637 #define config_get_string_field(_name,_var) do { \ 
 638     if (stringmatch(pattern,_name,0)) { \ 
 639         addReplyBulkCString(c,_name); \ 
 640         addReplyBulkCString(c,_var ? _var : ""); \ 
 645 #define config_get_bool_field(_name,_var) do { \ 
 646     if (stringmatch(pattern,_name,0)) { \ 
 647         addReplyBulkCString(c,_name); \ 
 648         addReplyBulkCString(c,_var ? "yes" : "no"); \ 
 653 #define config_get_numerical_field(_name,_var) do { \ 
 654     if (stringmatch(pattern,_name,0)) { \ 
 655         ll2string(buf,sizeof(buf),_var); \ 
 656         addReplyBulkCString(c,_name); \ 
 657         addReplyBulkCString(c,buf); \ 
 662 void configGetCommand(redisClient 
*c
) { 
 663     robj 
*o 
= c
->argv
[2]; 
 664     void *replylen 
= addDeferredMultiBulkLength(c
); 
 665     char *pattern 
= o
->ptr
; 
 668     redisAssertWithInfo(c
,o
,o
->encoding 
== REDIS_ENCODING_RAW
); 
 671     config_get_string_field("dbfilename",server
.rdb_filename
); 
 672     config_get_string_field("requirepass",server
.requirepass
); 
 673     config_get_string_field("masterauth",server
.requirepass
); 
 674     config_get_string_field("bind",server
.bindaddr
); 
 675     config_get_string_field("unixsocket",server
.unixsocket
); 
 676     config_get_string_field("logfile",server
.logfile
); 
 677     config_get_string_field("pidfile",server
.pidfile
); 
 679     /* Numerical values */ 
 680     config_get_numerical_field("maxmemory",server
.maxmemory
); 
 681     config_get_numerical_field("maxmemory-samples",server
.maxmemory_samples
); 
 682     config_get_numerical_field("timeout",server
.maxidletime
); 
 683     config_get_numerical_field("auto-aof-rewrite-percentage", 
 684             server
.aof_rewrite_perc
); 
 685     config_get_numerical_field("auto-aof-rewrite-min-size", 
 686             server
.aof_rewrite_min_size
); 
 687     config_get_numerical_field("hash-max-ziplist-entries", 
 688             server
.hash_max_ziplist_entries
); 
 689     config_get_numerical_field("hash-max-ziplist-value", 
 690             server
.hash_max_ziplist_value
); 
 691     config_get_numerical_field("list-max-ziplist-entries", 
 692             server
.list_max_ziplist_entries
); 
 693     config_get_numerical_field("list-max-ziplist-value", 
 694             server
.list_max_ziplist_value
); 
 695     config_get_numerical_field("set-max-intset-entries", 
 696             server
.set_max_intset_entries
); 
 697     config_get_numerical_field("zset-max-ziplist-entries", 
 698             server
.zset_max_ziplist_entries
); 
 699     config_get_numerical_field("zset-max-ziplist-value", 
 700             server
.zset_max_ziplist_value
); 
 701     config_get_numerical_field("lua-time-limit",server
.lua_time_limit
); 
 702     config_get_numerical_field("slowlog-log-slower-than", 
 703             server
.slowlog_log_slower_than
); 
 704     config_get_numerical_field("slowlog-max-len", 
 705             server
.slowlog_max_len
); 
 706     config_get_numerical_field("port",server
.port
); 
 707     config_get_numerical_field("databases",server
.dbnum
); 
 708     config_get_numerical_field("repl-ping-slave-period",server
.repl_ping_slave_period
); 
 709     config_get_numerical_field("repl-timeout",server
.repl_timeout
); 
 710     config_get_numerical_field("maxclients",server
.maxclients
); 
 712     /* Bool (yes/no) values */ 
 713     config_get_bool_field("no-appendfsync-on-rewrite", 
 714             server
.aof_no_fsync_on_rewrite
); 
 715     config_get_bool_field("slave-serve-stale-data", 
 716             server
.repl_serve_stale_data
); 
 717     config_get_bool_field("slave-read-only", 
 718             server
.repl_slave_ro
); 
 719     config_get_bool_field("stop-writes-on-bgsave-error", 
 720             server
.stop_writes_on_bgsave_err
); 
 721     config_get_bool_field("daemonize", server
.daemonize
); 
 722     config_get_bool_field("rdbcompression", server
.rdb_compression
); 
 723     config_get_bool_field("activerehashing", server
.activerehashing
); 
 725     /* Everything we can't handle with macros follows. */ 
 727     if (stringmatch(pattern
,"appendonly",0)) { 
 728         addReplyBulkCString(c
,"appendonly"); 
 729         addReplyBulkCString(c
,server
.aof_state 
== REDIS_AOF_OFF 
? "no" : "yes"); 
 732     if (stringmatch(pattern
,"dir",0)) { 
 735         if (getcwd(buf
,sizeof(buf
)) == NULL
) 
 738         addReplyBulkCString(c
,"dir"); 
 739         addReplyBulkCString(c
,buf
); 
 742     if (stringmatch(pattern
,"maxmemory-policy",0)) { 
 745         switch(server
.maxmemory_policy
) { 
 746         case REDIS_MAXMEMORY_VOLATILE_LRU
: s 
= "volatile-lru"; break; 
 747         case REDIS_MAXMEMORY_VOLATILE_TTL
: s 
= "volatile-ttl"; break; 
 748         case REDIS_MAXMEMORY_VOLATILE_RANDOM
: s 
= "volatile-random"; break; 
 749         case REDIS_MAXMEMORY_ALLKEYS_LRU
: s 
= "allkeys-lru"; break; 
 750         case REDIS_MAXMEMORY_ALLKEYS_RANDOM
: s 
= "allkeys-random"; break; 
 751         case REDIS_MAXMEMORY_NO_EVICTION
: s 
= "noeviction"; break; 
 752         default: s 
= "unknown"; break; /* too harmless to panic */ 
 754         addReplyBulkCString(c
,"maxmemory-policy"); 
 755         addReplyBulkCString(c
,s
); 
 758     if (stringmatch(pattern
,"appendfsync",0)) { 
 761         switch(server
.aof_fsync
) { 
 762         case AOF_FSYNC_NO
: policy 
= "no"; break; 
 763         case AOF_FSYNC_EVERYSEC
: policy 
= "everysec"; break; 
 764         case AOF_FSYNC_ALWAYS
: policy 
= "always"; break; 
 765         default: policy 
= "unknown"; break; /* too harmless to panic */ 
 767         addReplyBulkCString(c
,"appendfsync"); 
 768         addReplyBulkCString(c
,policy
); 
 771     if (stringmatch(pattern
,"save",0)) { 
 772         sds buf 
= sdsempty(); 
 775         for (j 
= 0; j 
< server
.saveparamslen
; j
++) { 
 776             buf 
= sdscatprintf(buf
,"%ld %d", 
 777                     server
.saveparams
[j
].seconds
, 
 778                     server
.saveparams
[j
].changes
); 
 779             if (j 
!= server
.saveparamslen
-1) 
 780                 buf 
= sdscatlen(buf
," ",1); 
 782         addReplyBulkCString(c
,"save"); 
 783         addReplyBulkCString(c
,buf
); 
 787     if (stringmatch(pattern
,"loglevel",0)) { 
 790         switch(server
.verbosity
) { 
 791         case REDIS_WARNING
: s 
= "warning"; break; 
 792         case REDIS_VERBOSE
: s 
= "verbose"; break; 
 793         case REDIS_NOTICE
: s 
= "notice"; break; 
 794         case REDIS_DEBUG
: s 
= "debug"; break; 
 795         default: s 
= "unknown"; break; /* too harmless to panic */ 
 797         addReplyBulkCString(c
,"loglevel"); 
 798         addReplyBulkCString(c
,s
); 
 801     if (stringmatch(pattern
,"client-output-buffer-limit",0)) { 
 802         sds buf 
= sdsempty(); 
 805         for (j 
= 0; j 
< REDIS_CLIENT_LIMIT_NUM_CLASSES
; j
++) { 
 806             buf 
= sdscatprintf(buf
,"%s %llu %llu %ld", 
 807                     getClientLimitClassName(j
), 
 808                     server
.client_obuf_limits
[j
].hard_limit_bytes
, 
 809                     server
.client_obuf_limits
[j
].soft_limit_bytes
, 
 810                     (long) server
.client_obuf_limits
[j
].soft_limit_seconds
); 
 811             if (j 
!= REDIS_CLIENT_LIMIT_NUM_CLASSES
-1) 
 812                 buf 
= sdscatlen(buf
," ",1); 
 814         addReplyBulkCString(c
,"client-output-buffer-limit"); 
 815         addReplyBulkCString(c
,buf
); 
 819     if (stringmatch(pattern
,"unixsocketperm",0)) { 
 821         snprintf(buf
,sizeof(buf
),"%o",server
.unixsocketperm
); 
 822         addReplyBulkCString(c
,"unixsocketperm"); 
 823         addReplyBulkCString(c
,buf
); 
 826     if (stringmatch(pattern
,"slaveof",0)) { 
 829         addReplyBulkCString(c
,"slaveof"); 
 830         if (server
.masterhost
) 
 831             snprintf(buf
,sizeof(buf
),"%s %d", 
 832                 server
.masterhost
, server
.masterport
); 
 835         addReplyBulkCString(c
,buf
); 
 838     setDeferredMultiBulkLength(c
,replylen
,matches
*2); 
 841 void configCommand(redisClient 
*c
) { 
 842     if (!strcasecmp(c
->argv
[1]->ptr
,"set")) { 
 843         if (c
->argc 
!= 4) goto badarity
; 
 845     } else if (!strcasecmp(c
->argv
[1]->ptr
,"get")) { 
 846         if (c
->argc 
!= 3) goto badarity
; 
 848     } else if (!strcasecmp(c
->argv
[1]->ptr
,"resetstat")) { 
 849         if (c
->argc 
!= 2) goto badarity
; 
 850         server
.stat_keyspace_hits 
= 0; 
 851         server
.stat_keyspace_misses 
= 0; 
 852         server
.stat_numcommands 
= 0; 
 853         server
.stat_numconnections 
= 0; 
 854         server
.stat_expiredkeys 
= 0; 
 855         server
.aof_delayed_fsync 
= 0; 
 856         resetCommandTableStats(); 
 857         addReply(c
,shared
.ok
); 
 860             "CONFIG subcommand must be one of GET, SET, RESETSTAT"); 
 865     addReplyErrorFormat(c
,"Wrong number of arguments for CONFIG %s", 
 866         (char*) c
->argv
[1]->ptr
);