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],"glueoutputbuf")) { 
 206             redisLog(REDIS_WARNING
, "Deprecated configuration directive: \"%s\"", argv
[0]); 
 207         } else if (!strcasecmp(argv
[0],"rdbcompression") && argc 
== 2) { 
 208             if ((server
.rdb_compression 
= yesnotoi(argv
[1])) == -1) { 
 209                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 211         } else if (!strcasecmp(argv
[0],"activerehashing") && argc 
== 2) { 
 212             if ((server
.activerehashing 
= yesnotoi(argv
[1])) == -1) { 
 213                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 215         } else if (!strcasecmp(argv
[0],"daemonize") && argc 
== 2) { 
 216             if ((server
.daemonize 
= yesnotoi(argv
[1])) == -1) { 
 217                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 219         } else if (!strcasecmp(argv
[0],"appendonly") && argc 
== 2) { 
 222             if ((yes 
= yesnotoi(argv
[1])) == -1) { 
 223                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 225             server
.aof_state 
= yes 
? REDIS_AOF_ON 
: REDIS_AOF_OFF
; 
 226         } else if (!strcasecmp(argv
[0],"appendfilename") && argc 
== 2) { 
 227             zfree(server
.aof_filename
); 
 228             server
.aof_filename 
= zstrdup(argv
[1]); 
 229         } else if (!strcasecmp(argv
[0],"no-appendfsync-on-rewrite") 
 231             if ((server
.aof_no_fsync_on_rewrite
= yesnotoi(argv
[1])) == -1) { 
 232                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 234         } else if (!strcasecmp(argv
[0],"appendfsync") && argc 
== 2) { 
 235             if (!strcasecmp(argv
[1],"no")) { 
 236                 server
.aof_fsync 
= AOF_FSYNC_NO
; 
 237             } else if (!strcasecmp(argv
[1],"always")) { 
 238                 server
.aof_fsync 
= AOF_FSYNC_ALWAYS
; 
 239             } else if (!strcasecmp(argv
[1],"everysec")) { 
 240                 server
.aof_fsync 
= AOF_FSYNC_EVERYSEC
; 
 242                 err 
= "argument must be 'no', 'always' or 'everysec'"; 
 245         } else if (!strcasecmp(argv
[0],"auto-aof-rewrite-percentage") && 
 248             server
.aof_rewrite_perc 
= atoi(argv
[1]); 
 249             if (server
.aof_rewrite_perc 
< 0) { 
 250                 err 
= "Invalid negative percentage for AOF auto rewrite"; 
 253         } else if (!strcasecmp(argv
[0],"auto-aof-rewrite-min-size") && 
 256             server
.aof_rewrite_min_size 
= memtoll(argv
[1],NULL
); 
 257         } else if (!strcasecmp(argv
[0],"requirepass") && argc 
== 2) { 
 258             server
.requirepass 
= zstrdup(argv
[1]); 
 259         } else if (!strcasecmp(argv
[0],"pidfile") && argc 
== 2) { 
 260             zfree(server
.pidfile
); 
 261             server
.pidfile 
= zstrdup(argv
[1]); 
 262         } else if (!strcasecmp(argv
[0],"dbfilename") && argc 
== 2) { 
 263             zfree(server
.rdb_filename
); 
 264             server
.rdb_filename 
= zstrdup(argv
[1]); 
 265         } else if (!strcasecmp(argv
[0],"hash-max-zipmap-entries") && argc 
== 2) { 
 266             server
.hash_max_zipmap_entries 
= memtoll(argv
[1], NULL
); 
 267         } else if (!strcasecmp(argv
[0],"hash-max-zipmap-value") && argc 
== 2) { 
 268             server
.hash_max_zipmap_value 
= memtoll(argv
[1], NULL
); 
 269         } else if (!strcasecmp(argv
[0],"list-max-ziplist-entries") && argc 
== 2){ 
 270             server
.list_max_ziplist_entries 
= memtoll(argv
[1], NULL
); 
 271         } else if (!strcasecmp(argv
[0],"list-max-ziplist-value") && argc 
== 2) { 
 272             server
.list_max_ziplist_value 
= memtoll(argv
[1], NULL
); 
 273         } else if (!strcasecmp(argv
[0],"set-max-intset-entries") && argc 
== 2) { 
 274             server
.set_max_intset_entries 
= memtoll(argv
[1], NULL
); 
 275         } else if (!strcasecmp(argv
[0],"zset-max-ziplist-entries") && argc 
== 2) { 
 276             server
.zset_max_ziplist_entries 
= memtoll(argv
[1], NULL
); 
 277         } else if (!strcasecmp(argv
[0],"zset-max-ziplist-value") && argc 
== 2) { 
 278             server
.zset_max_ziplist_value 
= memtoll(argv
[1], NULL
); 
 279         } else if (!strcasecmp(argv
[0],"rename-command") && argc 
== 3) { 
 280             struct redisCommand 
*cmd 
= lookupCommand(argv
[1]); 
 284                 err 
= "No such command in rename-command"; 
 288             /* If the target command name is the emtpy string we just 
 289              * remove it from the command table. */ 
 290             retval 
= dictDelete(server
.commands
, argv
[1]); 
 291             redisAssert(retval 
== DICT_OK
); 
 293             /* Otherwise we re-add the command under a different name. */ 
 294             if (sdslen(argv
[2]) != 0) { 
 295                 sds copy 
= sdsdup(argv
[2]); 
 297                 retval 
= dictAdd(server
.commands
, copy
, cmd
); 
 298                 if (retval 
!= DICT_OK
) { 
 300                     err 
= "Target command name already exists"; goto loaderr
; 
 303         } else if (!strcasecmp(argv
[0],"cluster-enabled") && argc 
== 2) { 
 304             if ((server
.cluster_enabled 
= yesnotoi(argv
[1])) == -1) { 
 305                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 307         } else if (!strcasecmp(argv
[0],"cluster-config-file") && argc 
== 2) { 
 308             zfree(server
.cluster
.configfile
); 
 309             server
.cluster
.configfile 
= zstrdup(argv
[1]); 
 310         } else if (!strcasecmp(argv
[0],"lua-time-limit") && argc 
== 2) { 
 311             server
.lua_time_limit 
= strtoll(argv
[1],NULL
,10); 
 312         } else if (!strcasecmp(argv
[0],"slowlog-log-slower-than") && 
 315             server
.slowlog_log_slower_than 
= strtoll(argv
[1],NULL
,10); 
 316         } else if (!strcasecmp(argv
[0],"slowlog-max-len") && argc 
== 2) { 
 317             server
.slowlog_max_len 
= strtoll(argv
[1],NULL
,10); 
 318         } else if (!strcasecmp(argv
[0],"client-output-buffer-limit") && 
 321             int class = getClientLimitClassByName(argv
[1]); 
 322             unsigned long long hard
, soft
; 
 326                 err 
= "Unrecognized client limit class"; 
 329             hard 
= memtoll(argv
[2],NULL
); 
 330             soft 
= memtoll(argv
[3],NULL
); 
 331             soft_seconds 
= atoi(argv
[4]); 
 332             if (soft_seconds 
< 0) { 
 333                 err 
= "Negative number of seconds in soft limt is invalid"; 
 336             server
.client_obuf_limits
[class].hard_limit_bytes 
= hard
; 
 337             server
.client_obuf_limits
[class].soft_limit_bytes 
= soft
; 
 338             server
.client_obuf_limits
[class].soft_limit_seconds 
= soft_seconds
; 
 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
,"dir")) { 
 515         if (chdir((char*)o
->ptr
) == -1) { 
 516             addReplyErrorFormat(c
,"Changing directory: %s", strerror(errno
)); 
 519     } else if (!strcasecmp(c
->argv
[2]->ptr
,"hash-max-zipmap-entries")) { 
 520         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 521         server
.hash_max_zipmap_entries 
= ll
; 
 522     } else if (!strcasecmp(c
->argv
[2]->ptr
,"hash-max-zipmap-value")) { 
 523         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 524         server
.hash_max_zipmap_value 
= ll
; 
 525     } else if (!strcasecmp(c
->argv
[2]->ptr
,"list-max-ziplist-entries")) { 
 526         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 527         server
.list_max_ziplist_entries 
= ll
; 
 528     } else if (!strcasecmp(c
->argv
[2]->ptr
,"list-max-ziplist-value")) { 
 529         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 530         server
.list_max_ziplist_value 
= ll
; 
 531     } else if (!strcasecmp(c
->argv
[2]->ptr
,"set-max-intset-entries")) { 
 532         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 533         server
.set_max_intset_entries 
= ll
; 
 534     } else if (!strcasecmp(c
->argv
[2]->ptr
,"zset-max-ziplist-entries")) { 
 535         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 536         server
.zset_max_ziplist_entries 
= ll
; 
 537     } else if (!strcasecmp(c
->argv
[2]->ptr
,"zset-max-ziplist-value")) { 
 538         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 539         server
.zset_max_ziplist_value 
= ll
; 
 540     } else if (!strcasecmp(c
->argv
[2]->ptr
,"lua-time-limit")) { 
 541         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 542         server
.lua_time_limit 
= ll
; 
 543     } else if (!strcasecmp(c
->argv
[2]->ptr
,"slowlog-log-slower-than")) { 
 544         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR
) goto badfmt
; 
 545         server
.slowlog_log_slower_than 
= ll
; 
 546     } else if (!strcasecmp(c
->argv
[2]->ptr
,"slowlog-max-len")) { 
 547         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 548         server
.slowlog_max_len 
= (unsigned)ll
; 
 549     } else if (!strcasecmp(c
->argv
[2]->ptr
,"loglevel")) { 
 550         if (!strcasecmp(o
->ptr
,"warning")) { 
 551             server
.verbosity 
= REDIS_WARNING
; 
 552         } else if (!strcasecmp(o
->ptr
,"notice")) { 
 553             server
.verbosity 
= REDIS_NOTICE
; 
 554         } else if (!strcasecmp(o
->ptr
,"verbose")) { 
 555             server
.verbosity 
= REDIS_VERBOSE
; 
 556         } else if (!strcasecmp(o
->ptr
,"debug")) { 
 557             server
.verbosity 
= REDIS_DEBUG
; 
 561     } else if (!strcasecmp(c
->argv
[2]->ptr
,"client-output-buffer-limit")) { 
 563         sds 
*v 
= sdssplitlen(o
->ptr
,sdslen(o
->ptr
)," ",1,&vlen
); 
 565         /* We need a multiple of 4: <class> <hard> <soft> <soft_seconds> */ 
 567             sdsfreesplitres(v
,vlen
); 
 571         /* Sanity check of single arguments, so that we either refuse the 
 572          * whole configuration string or accept it all, even if a single 
 573          * error in a single client class is present. */ 
 574         for (j 
= 0; j 
< vlen
; j
++) { 
 579                 if (getClientLimitClassByName(v
[j
]) == -1) { 
 580                     sdsfreesplitres(v
,vlen
); 
 584                 val 
= strtoll(v
[j
], &eptr
, 10); 
 585                 if (eptr
[0] != '\0' || val 
< 0) { 
 586                     sdsfreesplitres(v
,vlen
); 
 591         /* Finally set the new config */ 
 592         for (j 
= 0; j 
< vlen
; j 
+= 4) { 
 594             unsigned long long hard
, soft
; 
 597             class = getClientLimitClassByName(v
[j
]); 
 598             hard 
= strtoll(v
[j
+1],NULL
,10); 
 599             soft 
= strtoll(v
[j
+2],NULL
,10); 
 600             soft_seconds 
= strtoll(v
[j
+3],NULL
,10); 
 602             server
.client_obuf_limits
[class].hard_limit_bytes 
= hard
; 
 603             server
.client_obuf_limits
[class].soft_limit_bytes 
= soft
; 
 604             server
.client_obuf_limits
[class].soft_limit_seconds 
= soft_seconds
; 
 606         sdsfreesplitres(v
,vlen
); 
 609         addReplyErrorFormat(c
,"Unsupported CONFIG parameter: %s", 
 610             (char*)c
->argv
[2]->ptr
); 
 613     addReply(c
,shared
.ok
); 
 616 badfmt
: /* Bad format errors */ 
 617     addReplyErrorFormat(c
,"Invalid argument '%s' for CONFIG SET '%s'", 
 619             (char*)c
->argv
[2]->ptr
); 
 622 void configGetCommand(redisClient 
*c
) { 
 623     robj 
*o 
= c
->argv
[2]; 
 624     void *replylen 
= addDeferredMultiBulkLength(c
); 
 625     char *pattern 
= o
->ptr
; 
 628     redisAssertWithInfo(c
,o
,o
->encoding 
== REDIS_ENCODING_RAW
); 
 630     if (stringmatch(pattern
,"dir",0)) { 
 633         if (getcwd(buf
,sizeof(buf
)) == NULL
) 
 636         addReplyBulkCString(c
,"dir"); 
 637         addReplyBulkCString(c
,buf
); 
 640     if (stringmatch(pattern
,"dbfilename",0)) { 
 641         addReplyBulkCString(c
,"dbfilename"); 
 642         addReplyBulkCString(c
,server
.rdb_filename
); 
 645     if (stringmatch(pattern
,"requirepass",0)) { 
 646         addReplyBulkCString(c
,"requirepass"); 
 647         addReplyBulkCString(c
,server
.requirepass
); 
 650     if (stringmatch(pattern
,"masterauth",0)) { 
 651         addReplyBulkCString(c
,"masterauth"); 
 652         addReplyBulkCString(c
,server
.masterauth
); 
 655     if (stringmatch(pattern
,"maxmemory",0)) { 
 656         ll2string(buf
,sizeof(buf
),server
.maxmemory
); 
 657         addReplyBulkCString(c
,"maxmemory"); 
 658         addReplyBulkCString(c
,buf
); 
 661     if (stringmatch(pattern
,"maxmemory-policy",0)) { 
 664         switch(server
.maxmemory_policy
) { 
 665         case REDIS_MAXMEMORY_VOLATILE_LRU
: s 
= "volatile-lru"; break; 
 666         case REDIS_MAXMEMORY_VOLATILE_TTL
: s 
= "volatile-ttl"; break; 
 667         case REDIS_MAXMEMORY_VOLATILE_RANDOM
: s 
= "volatile-random"; break; 
 668         case REDIS_MAXMEMORY_ALLKEYS_LRU
: s 
= "allkeys-lru"; break; 
 669         case REDIS_MAXMEMORY_ALLKEYS_RANDOM
: s 
= "allkeys-random"; break; 
 670         case REDIS_MAXMEMORY_NO_EVICTION
: s 
= "noeviction"; break; 
 671         default: s 
= "unknown"; break; /* too harmless to panic */ 
 673         addReplyBulkCString(c
,"maxmemory-policy"); 
 674         addReplyBulkCString(c
,s
); 
 677     if (stringmatch(pattern
,"maxmemory-samples",0)) { 
 678         ll2string(buf
,sizeof(buf
),server
.maxmemory_samples
); 
 679         addReplyBulkCString(c
,"maxmemory-samples"); 
 680         addReplyBulkCString(c
,buf
); 
 683     if (stringmatch(pattern
,"timeout",0)) { 
 684         ll2string(buf
,sizeof(buf
),server
.maxidletime
); 
 685         addReplyBulkCString(c
,"timeout"); 
 686         addReplyBulkCString(c
,buf
); 
 689     if (stringmatch(pattern
,"appendonly",0)) { 
 690         addReplyBulkCString(c
,"appendonly"); 
 691         addReplyBulkCString(c
,server
.aof_state 
== REDIS_AOF_OFF 
? "no" : "yes"); 
 694     if (stringmatch(pattern
,"no-appendfsync-on-rewrite",0)) { 
 695         addReplyBulkCString(c
,"no-appendfsync-on-rewrite"); 
 696         addReplyBulkCString(c
,server
.aof_no_fsync_on_rewrite 
? "yes" : "no"); 
 699     if (stringmatch(pattern
,"appendfsync",0)) { 
 702         switch(server
.aof_fsync
) { 
 703         case AOF_FSYNC_NO
: policy 
= "no"; break; 
 704         case AOF_FSYNC_EVERYSEC
: policy 
= "everysec"; break; 
 705         case AOF_FSYNC_ALWAYS
: policy 
= "always"; break; 
 706         default: policy 
= "unknown"; break; /* too harmless to panic */ 
 708         addReplyBulkCString(c
,"appendfsync"); 
 709         addReplyBulkCString(c
,policy
); 
 712     if (stringmatch(pattern
,"save",0)) { 
 713         sds buf 
= sdsempty(); 
 716         for (j 
= 0; j 
< server
.saveparamslen
; j
++) { 
 717             buf 
= sdscatprintf(buf
,"%ld %d", 
 718                     server
.saveparams
[j
].seconds
, 
 719                     server
.saveparams
[j
].changes
); 
 720             if (j 
!= server
.saveparamslen
-1) 
 721                 buf 
= sdscatlen(buf
," ",1); 
 723         addReplyBulkCString(c
,"save"); 
 724         addReplyBulkCString(c
,buf
); 
 728     if (stringmatch(pattern
,"auto-aof-rewrite-percentage",0)) { 
 729         addReplyBulkCString(c
,"auto-aof-rewrite-percentage"); 
 730         addReplyBulkLongLong(c
,server
.aof_rewrite_perc
); 
 733     if (stringmatch(pattern
,"auto-aof-rewrite-min-size",0)) { 
 734         addReplyBulkCString(c
,"auto-aof-rewrite-min-size"); 
 735         addReplyBulkLongLong(c
,server
.aof_rewrite_min_size
); 
 738     if (stringmatch(pattern
,"slave-serve-stale-data",0)) { 
 739         addReplyBulkCString(c
,"slave-serve-stale-data"); 
 740         addReplyBulkCString(c
,server
.repl_serve_stale_data 
? "yes" : "no"); 
 743     if (stringmatch(pattern
,"hash-max-zipmap-entries",0)) { 
 744         addReplyBulkCString(c
,"hash-max-zipmap-entries"); 
 745         addReplyBulkLongLong(c
,server
.hash_max_zipmap_entries
); 
 748     if (stringmatch(pattern
,"hash-max-zipmap-value",0)) { 
 749         addReplyBulkCString(c
,"hash-max-zipmap-value"); 
 750         addReplyBulkLongLong(c
,server
.hash_max_zipmap_value
); 
 753     if (stringmatch(pattern
,"list-max-ziplist-entries",0)) { 
 754         addReplyBulkCString(c
,"list-max-ziplist-entries"); 
 755         addReplyBulkLongLong(c
,server
.list_max_ziplist_entries
); 
 758     if (stringmatch(pattern
,"list-max-ziplist-value",0)) { 
 759         addReplyBulkCString(c
,"list-max-ziplist-value"); 
 760         addReplyBulkLongLong(c
,server
.list_max_ziplist_value
); 
 763     if (stringmatch(pattern
,"set-max-intset-entries",0)) { 
 764         addReplyBulkCString(c
,"set-max-intset-entries"); 
 765         addReplyBulkLongLong(c
,server
.set_max_intset_entries
); 
 768     if (stringmatch(pattern
,"zset-max-ziplist-entries",0)) { 
 769         addReplyBulkCString(c
,"zset-max-ziplist-entries"); 
 770         addReplyBulkLongLong(c
,server
.zset_max_ziplist_entries
); 
 773     if (stringmatch(pattern
,"zset-max-ziplist-value",0)) { 
 774         addReplyBulkCString(c
,"zset-max-ziplist-value"); 
 775         addReplyBulkLongLong(c
,server
.zset_max_ziplist_value
); 
 778     if (stringmatch(pattern
,"lua-time-limit",0)) { 
 779         addReplyBulkCString(c
,"lua-time-limit"); 
 780         addReplyBulkLongLong(c
,server
.lua_time_limit
); 
 783     if (stringmatch(pattern
,"slowlog-log-slower-than",0)) { 
 784         addReplyBulkCString(c
,"slowlog-log-slower-than"); 
 785         addReplyBulkLongLong(c
,server
.slowlog_log_slower_than
); 
 788     if (stringmatch(pattern
,"slowlog-max-len",0)) { 
 789         addReplyBulkCString(c
,"slowlog-max-len"); 
 790         addReplyBulkLongLong(c
,server
.slowlog_max_len
); 
 793     if (stringmatch(pattern
,"loglevel",0)) { 
 796         switch(server
.verbosity
) { 
 797         case REDIS_WARNING
: s 
= "warning"; break; 
 798         case REDIS_VERBOSE
: s 
= "verbose"; break; 
 799         case REDIS_NOTICE
: s 
= "notice"; break; 
 800         case REDIS_DEBUG
: s 
= "debug"; break; 
 801         default: s 
= "unknown"; break; /* too harmless to panic */ 
 803         addReplyBulkCString(c
,"loglevel"); 
 804         addReplyBulkCString(c
,s
); 
 807     if (stringmatch(pattern
,"client-output-buffer-limit",0)) { 
 808         sds buf 
= sdsempty(); 
 811         for (j 
= 0; j 
< REDIS_CLIENT_LIMIT_NUM_CLASSES
; j
++) { 
 812             buf 
= sdscatprintf(buf
,"%s %llu %llu %ld", 
 813                     getClientLimitClassName(j
), 
 814                     server
.client_obuf_limits
[j
].hard_limit_bytes
, 
 815                     server
.client_obuf_limits
[j
].soft_limit_bytes
, 
 816                     (long) server
.client_obuf_limits
[j
].soft_limit_seconds
); 
 817             if (j 
!= REDIS_CLIENT_LIMIT_NUM_CLASSES
-1) 
 818                 buf 
= sdscatlen(buf
," ",1); 
 820         addReplyBulkCString(c
,"client-output-buffer-limit"); 
 821         addReplyBulkCString(c
,buf
); 
 825     setDeferredMultiBulkLength(c
,replylen
,matches
*2); 
 828 void configCommand(redisClient 
*c
) { 
 829     if (!strcasecmp(c
->argv
[1]->ptr
,"set")) { 
 830         if (c
->argc 
!= 4) goto badarity
; 
 832     } else if (!strcasecmp(c
->argv
[1]->ptr
,"get")) { 
 833         if (c
->argc 
!= 3) goto badarity
; 
 835     } else if (!strcasecmp(c
->argv
[1]->ptr
,"resetstat")) { 
 836         if (c
->argc 
!= 2) goto badarity
; 
 837         server
.stat_keyspace_hits 
= 0; 
 838         server
.stat_keyspace_misses 
= 0; 
 839         server
.stat_numcommands 
= 0; 
 840         server
.stat_numconnections 
= 0; 
 841         server
.stat_expiredkeys 
= 0; 
 842         resetCommandTableStats(); 
 843         addReply(c
,shared
.ok
); 
 846             "CONFIG subcommand must be one of GET, SET, RESETSTAT"); 
 851     addReplyErrorFormat(c
,"Wrong number of arguments for CONFIG %s", 
 852         (char*) c
->argv
[1]->ptr
);