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") && argc 
== 3) { 
  69             int seconds 
= atoi(argv
[1]); 
  70             int changes 
= atoi(argv
[2]); 
  71             if (seconds 
< 1 || changes 
< 0) { 
  72                 err 
= "Invalid save parameters"; goto loaderr
; 
  74             appendServerSaveParams(seconds
,changes
); 
  75         } else if (!strcasecmp(argv
[0],"dir") && argc 
== 2) { 
  76             if (chdir(argv
[1]) == -1) { 
  77                 redisLog(REDIS_WARNING
,"Can't chdir to '%s': %s", 
  78                     argv
[1], strerror(errno
)); 
  81         } else if (!strcasecmp(argv
[0],"loglevel") && argc 
== 2) { 
  82             if (!strcasecmp(argv
[1],"debug")) server
.verbosity 
= REDIS_DEBUG
; 
  83             else if (!strcasecmp(argv
[1],"verbose")) server
.verbosity 
= REDIS_VERBOSE
; 
  84             else if (!strcasecmp(argv
[1],"notice")) server
.verbosity 
= REDIS_NOTICE
; 
  85             else if (!strcasecmp(argv
[1],"warning")) server
.verbosity 
= REDIS_WARNING
; 
  87                 err 
= "Invalid log level. Must be one of debug, notice, warning"; 
  90         } else if (!strcasecmp(argv
[0],"logfile") && argc 
== 2) { 
  93             server
.logfile 
= zstrdup(argv
[1]); 
  94             if (!strcasecmp(server
.logfile
,"stdout")) { 
  95                 zfree(server
.logfile
); 
  96                 server
.logfile 
= NULL
; 
  99                 /* Test if we are able to open the file. The server will not 
 100                  * be able to abort just for this problem later... */ 
 101                 logfp 
= fopen(server
.logfile
,"a"); 
 103                     err 
= sdscatprintf(sdsempty(), 
 104                         "Can't open the log file: %s", strerror(errno
)); 
 109         } else if (!strcasecmp(argv
[0],"syslog-enabled") && argc 
== 2) { 
 110             if ((server
.syslog_enabled 
= yesnotoi(argv
[1])) == -1) { 
 111                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 113         } else if (!strcasecmp(argv
[0],"syslog-ident") && argc 
== 2) { 
 114             if (server
.syslog_ident
) zfree(server
.syslog_ident
); 
 115             server
.syslog_ident 
= zstrdup(argv
[1]); 
 116         } else if (!strcasecmp(argv
[0],"syslog-facility") && argc 
== 2) { 
 120             } validSyslogFacilities
[] = { 
 122                 {"local0",  LOG_LOCAL0
}, 
 123                 {"local1",  LOG_LOCAL1
}, 
 124                 {"local2",  LOG_LOCAL2
}, 
 125                 {"local3",  LOG_LOCAL3
}, 
 126                 {"local4",  LOG_LOCAL4
}, 
 127                 {"local5",  LOG_LOCAL5
}, 
 128                 {"local6",  LOG_LOCAL6
}, 
 129                 {"local7",  LOG_LOCAL7
}, 
 134             for (i 
= 0; validSyslogFacilities
[i
].name
; i
++) { 
 135                 if (!strcasecmp(validSyslogFacilities
[i
].name
, argv
[1])) { 
 136                     server
.syslog_facility 
= validSyslogFacilities
[i
].value
; 
 141             if (!validSyslogFacilities
[i
].name
) { 
 142                 err 
= "Invalid log facility. Must be one of USER or between LOCAL0-LOCAL7"; 
 145         } else if (!strcasecmp(argv
[0],"databases") && argc 
== 2) { 
 146             server
.dbnum 
= atoi(argv
[1]); 
 147             if (server
.dbnum 
< 1) { 
 148                 err 
= "Invalid number of databases"; goto loaderr
; 
 150         } else if (!strcasecmp(argv
[0],"include") && argc 
== 2) { 
 151             loadServerConfig(argv
[1],NULL
); 
 152         } else if (!strcasecmp(argv
[0],"maxclients") && argc 
== 2) { 
 153             server
.maxclients 
= atoi(argv
[1]); 
 154         } else if (!strcasecmp(argv
[0],"maxmemory") && argc 
== 2) { 
 155             server
.maxmemory 
= memtoll(argv
[1],NULL
); 
 156         } else if (!strcasecmp(argv
[0],"maxmemory-policy") && argc 
== 2) { 
 157             if (!strcasecmp(argv
[1],"volatile-lru")) { 
 158                 server
.maxmemory_policy 
= REDIS_MAXMEMORY_VOLATILE_LRU
; 
 159             } else if (!strcasecmp(argv
[1],"volatile-random")) { 
 160                 server
.maxmemory_policy 
= REDIS_MAXMEMORY_VOLATILE_RANDOM
; 
 161             } else if (!strcasecmp(argv
[1],"volatile-ttl")) { 
 162                 server
.maxmemory_policy 
= REDIS_MAXMEMORY_VOLATILE_TTL
; 
 163             } else if (!strcasecmp(argv
[1],"allkeys-lru")) { 
 164                 server
.maxmemory_policy 
= REDIS_MAXMEMORY_ALLKEYS_LRU
; 
 165             } else if (!strcasecmp(argv
[1],"allkeys-random")) { 
 166                 server
.maxmemory_policy 
= REDIS_MAXMEMORY_ALLKEYS_RANDOM
; 
 167             } else if (!strcasecmp(argv
[1],"noeviction")) { 
 168                 server
.maxmemory_policy 
= REDIS_MAXMEMORY_NO_EVICTION
; 
 170                 err 
= "Invalid maxmemory policy"; 
 173         } else if (!strcasecmp(argv
[0],"maxmemory-samples") && argc 
== 2) { 
 174             server
.maxmemory_samples 
= atoi(argv
[1]); 
 175             if (server
.maxmemory_samples 
<= 0) { 
 176                 err 
= "maxmemory-samples must be 1 or greater"; 
 179         } else if (!strcasecmp(argv
[0],"slaveof") && argc 
== 3) { 
 180             server
.masterhost 
= sdsnew(argv
[1]); 
 181             server
.masterport 
= atoi(argv
[2]); 
 182             server
.repl_state 
= REDIS_REPL_CONNECT
; 
 183         } else if (!strcasecmp(argv
[0],"repl-ping-slave-period") && argc 
== 2) { 
 184             server
.repl_ping_slave_period 
= atoi(argv
[1]); 
 185             if (server
.repl_ping_slave_period 
<= 0) { 
 186                 err 
= "repl-ping-slave-period must be 1 or greater"; 
 189         } else if (!strcasecmp(argv
[0],"repl-timeout") && argc 
== 2) { 
 190             server
.repl_timeout 
= atoi(argv
[1]); 
 191             if (server
.repl_timeout 
<= 0) { 
 192                 err 
= "repl-timeout must be 1 or greater"; 
 195         } else if (!strcasecmp(argv
[0],"masterauth") && argc 
== 2) { 
 196                 server
.masterauth 
= zstrdup(argv
[1]); 
 197         } else if (!strcasecmp(argv
[0],"slave-serve-stale-data") && argc 
== 2) { 
 198             if ((server
.repl_serve_stale_data 
= yesnotoi(argv
[1])) == -1) { 
 199                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 201         } else if (!strcasecmp(argv
[0],"glueoutputbuf")) { 
 202             redisLog(REDIS_WARNING
, "Deprecated configuration directive: \"%s\"", argv
[0]); 
 203         } else if (!strcasecmp(argv
[0],"rdbcompression") && argc 
== 2) { 
 204             if ((server
.rdb_compression 
= yesnotoi(argv
[1])) == -1) { 
 205                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 207         } else if (!strcasecmp(argv
[0],"activerehashing") && argc 
== 2) { 
 208             if ((server
.activerehashing 
= yesnotoi(argv
[1])) == -1) { 
 209                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 211         } else if (!strcasecmp(argv
[0],"daemonize") && argc 
== 2) { 
 212             if ((server
.daemonize 
= yesnotoi(argv
[1])) == -1) { 
 213                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 215         } else if (!strcasecmp(argv
[0],"appendonly") && argc 
== 2) { 
 218             if ((yes 
= yesnotoi(argv
[1])) == -1) { 
 219                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 221             server
.aof_state 
= yes 
? REDIS_AOF_ON 
: REDIS_AOF_OFF
; 
 222         } else if (!strcasecmp(argv
[0],"appendfilename") && argc 
== 2) { 
 223             zfree(server
.aof_filename
); 
 224             server
.aof_filename 
= zstrdup(argv
[1]); 
 225         } else if (!strcasecmp(argv
[0],"no-appendfsync-on-rewrite") 
 227             if ((server
.aof_no_fsync_on_rewrite
= yesnotoi(argv
[1])) == -1) { 
 228                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 230         } else if (!strcasecmp(argv
[0],"appendfsync") && argc 
== 2) { 
 231             if (!strcasecmp(argv
[1],"no")) { 
 232                 server
.aof_fsync 
= AOF_FSYNC_NO
; 
 233             } else if (!strcasecmp(argv
[1],"always")) { 
 234                 server
.aof_fsync 
= AOF_FSYNC_ALWAYS
; 
 235             } else if (!strcasecmp(argv
[1],"everysec")) { 
 236                 server
.aof_fsync 
= AOF_FSYNC_EVERYSEC
; 
 238                 err 
= "argument must be 'no', 'always' or 'everysec'"; 
 241         } else if (!strcasecmp(argv
[0],"auto-aof-rewrite-percentage") && 
 244             server
.aof_rewrite_perc 
= atoi(argv
[1]); 
 245             if (server
.aof_rewrite_perc 
< 0) { 
 246                 err 
= "Invalid negative percentage for AOF auto rewrite"; 
 249         } else if (!strcasecmp(argv
[0],"auto-aof-rewrite-min-size") && 
 252             server
.aof_rewrite_min_size 
= memtoll(argv
[1],NULL
); 
 253         } else if (!strcasecmp(argv
[0],"requirepass") && argc 
== 2) { 
 254             server
.requirepass 
= zstrdup(argv
[1]); 
 255         } else if (!strcasecmp(argv
[0],"pidfile") && argc 
== 2) { 
 256             zfree(server
.pidfile
); 
 257             server
.pidfile 
= zstrdup(argv
[1]); 
 258         } else if (!strcasecmp(argv
[0],"dbfilename") && argc 
== 2) { 
 259             zfree(server
.rdb_filename
); 
 260             server
.rdb_filename 
= zstrdup(argv
[1]); 
 261         } else if (!strcasecmp(argv
[0],"hash-max-zipmap-entries") && argc 
== 2) { 
 262             server
.hash_max_zipmap_entries 
= memtoll(argv
[1], NULL
); 
 263         } else if (!strcasecmp(argv
[0],"hash-max-zipmap-value") && argc 
== 2) { 
 264             server
.hash_max_zipmap_value 
= memtoll(argv
[1], NULL
); 
 265         } else if (!strcasecmp(argv
[0],"list-max-ziplist-entries") && argc 
== 2){ 
 266             server
.list_max_ziplist_entries 
= memtoll(argv
[1], NULL
); 
 267         } else if (!strcasecmp(argv
[0],"list-max-ziplist-value") && argc 
== 2) { 
 268             server
.list_max_ziplist_value 
= memtoll(argv
[1], NULL
); 
 269         } else if (!strcasecmp(argv
[0],"set-max-intset-entries") && argc 
== 2) { 
 270             server
.set_max_intset_entries 
= memtoll(argv
[1], NULL
); 
 271         } else if (!strcasecmp(argv
[0],"zset-max-ziplist-entries") && argc 
== 2) { 
 272             server
.zset_max_ziplist_entries 
= memtoll(argv
[1], NULL
); 
 273         } else if (!strcasecmp(argv
[0],"zset-max-ziplist-value") && argc 
== 2) { 
 274             server
.zset_max_ziplist_value 
= memtoll(argv
[1], NULL
); 
 275         } else if (!strcasecmp(argv
[0],"rename-command") && argc 
== 3) { 
 276             struct redisCommand 
*cmd 
= lookupCommand(argv
[1]); 
 280                 err 
= "No such command in rename-command"; 
 284             /* If the target command name is the emtpy string we just 
 285              * remove it from the command table. */ 
 286             retval 
= dictDelete(server
.commands
, argv
[1]); 
 287             redisAssert(retval 
== DICT_OK
); 
 289             /* Otherwise we re-add the command under a different name. */ 
 290             if (sdslen(argv
[2]) != 0) { 
 291                 sds copy 
= sdsdup(argv
[2]); 
 293                 retval 
= dictAdd(server
.commands
, copy
, cmd
); 
 294                 if (retval 
!= DICT_OK
) { 
 296                     err 
= "Target command name already exists"; goto loaderr
; 
 299         } else if (!strcasecmp(argv
[0],"cluster-enabled") && argc 
== 2) { 
 300             if ((server
.cluster_enabled 
= yesnotoi(argv
[1])) == -1) { 
 301                 err 
= "argument must be 'yes' or 'no'"; goto loaderr
; 
 303         } else if (!strcasecmp(argv
[0],"cluster-config-file") && argc 
== 2) { 
 304             zfree(server
.cluster
.configfile
); 
 305             server
.cluster
.configfile 
= zstrdup(argv
[1]); 
 306         } else if (!strcasecmp(argv
[0],"lua-time-limit") && argc 
== 2) { 
 307             server
.lua_time_limit 
= strtoll(argv
[1],NULL
,10); 
 308         } else if (!strcasecmp(argv
[0],"slowlog-log-slower-than") && 
 311             server
.slowlog_log_slower_than 
= strtoll(argv
[1],NULL
,10); 
 312         } else if (!strcasecmp(argv
[0],"slowlog-max-len") && argc 
== 2) { 
 313             server
.slowlog_max_len 
= strtoll(argv
[1],NULL
,10); 
 315             err 
= "Bad directive or wrong number of arguments"; goto loaderr
; 
 317         sdsfreesplitres(argv
,argc
); 
 319     sdsfreesplitres(lines
,totlines
); 
 323     fprintf(stderr
, "\n*** FATAL CONFIG FILE ERROR ***\n"); 
 324     fprintf(stderr
, "Reading the configuration file, at line %d\n", linenum
); 
 325     fprintf(stderr
, ">>> '%s'\n", lines
[i
]); 
 326     fprintf(stderr
, "%s\n", err
); 
 330 /* Load the server configuration from the specified filename. 
 331  * The function appends the additional configuration directives stored 
 332  * in the 'options' string to the config file before loading. 
 334  * Both filename and options can be NULL, in such a case are considered 
 335  * emtpy. This way loadServerConfig can be used to just load a file or 
 336  * just load a string. */ 
 337 void loadServerConfig(char *filename
, char *options
) { 
 338     sds config 
= sdsempty(); 
 339     char buf
[REDIS_CONFIGLINE_MAX
+1]; 
 341     /* Load the file content */ 
 345         if (filename
[0] == '-' && filename
[1] == '\0') { 
 348             if ((fp 
= fopen(filename
,"r")) == NULL
) { 
 349                 redisLog(REDIS_WARNING
, 
 350                     "Fatal error, can't open config file '%s'", filename
); 
 354         while(fgets(buf
,REDIS_CONFIGLINE_MAX
+1,fp
) != NULL
) 
 355             config 
= sdscat(config
,buf
); 
 356         if (fp 
!= stdin
) fclose(fp
); 
 358     /* Append the additional options */ 
 360         config 
= sdscat(config
,"\n"); 
 361         config 
= sdscat(config
,options
); 
 363     loadServerConfigFromString(config
); 
 367 /*----------------------------------------------------------------------------- 
 368  * CONFIG command for remote configuration 
 369  *----------------------------------------------------------------------------*/ 
 371 void configSetCommand(redisClient 
*c
) { 
 374     redisAssertWithInfo(c
,c
->argv
[2],c
->argv
[2]->encoding 
== REDIS_ENCODING_RAW
); 
 375     redisAssertWithInfo(c
,c
->argv
[2],c
->argv
[3]->encoding 
== REDIS_ENCODING_RAW
); 
 378     if (!strcasecmp(c
->argv
[2]->ptr
,"dbfilename")) { 
 379         zfree(server
.rdb_filename
); 
 380         server
.rdb_filename 
= zstrdup(o
->ptr
); 
 381     } else if (!strcasecmp(c
->argv
[2]->ptr
,"requirepass")) { 
 382         zfree(server
.requirepass
); 
 383         server
.requirepass 
= ((char*)o
->ptr
)[0] ? zstrdup(o
->ptr
) : NULL
; 
 384     } else if (!strcasecmp(c
->argv
[2]->ptr
,"masterauth")) { 
 385         zfree(server
.masterauth
); 
 386         server
.masterauth 
= zstrdup(o
->ptr
); 
 387     } else if (!strcasecmp(c
->argv
[2]->ptr
,"maxmemory")) { 
 388         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| 
 390         server
.maxmemory 
= ll
; 
 391         if (server
.maxmemory
) freeMemoryIfNeeded(); 
 392     } else if (!strcasecmp(c
->argv
[2]->ptr
,"maxmemory-policy")) { 
 393         if (!strcasecmp(o
->ptr
,"volatile-lru")) { 
 394             server
.maxmemory_policy 
= REDIS_MAXMEMORY_VOLATILE_LRU
; 
 395         } else if (!strcasecmp(o
->ptr
,"volatile-random")) { 
 396             server
.maxmemory_policy 
= REDIS_MAXMEMORY_VOLATILE_RANDOM
; 
 397         } else if (!strcasecmp(o
->ptr
,"volatile-ttl")) { 
 398             server
.maxmemory_policy 
= REDIS_MAXMEMORY_VOLATILE_TTL
; 
 399         } else if (!strcasecmp(o
->ptr
,"allkeys-lru")) { 
 400             server
.maxmemory_policy 
= REDIS_MAXMEMORY_ALLKEYS_LRU
; 
 401         } else if (!strcasecmp(o
->ptr
,"allkeys-random")) { 
 402             server
.maxmemory_policy 
= REDIS_MAXMEMORY_ALLKEYS_RANDOM
; 
 403         } else if (!strcasecmp(o
->ptr
,"noeviction")) { 
 404             server
.maxmemory_policy 
= REDIS_MAXMEMORY_NO_EVICTION
; 
 408     } else if (!strcasecmp(c
->argv
[2]->ptr
,"maxmemory-samples")) { 
 409         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| 
 410             ll 
<= 0) goto badfmt
; 
 411         server
.maxmemory_samples 
= ll
; 
 412     } else if (!strcasecmp(c
->argv
[2]->ptr
,"timeout")) { 
 413         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| 
 414             ll 
< 0 || ll 
> LONG_MAX
) goto badfmt
; 
 415         server
.maxidletime 
= ll
; 
 416     } else if (!strcasecmp(c
->argv
[2]->ptr
,"appendfsync")) { 
 417         if (!strcasecmp(o
->ptr
,"no")) { 
 418             server
.aof_fsync 
= AOF_FSYNC_NO
; 
 419         } else if (!strcasecmp(o
->ptr
,"everysec")) { 
 420             server
.aof_fsync 
= AOF_FSYNC_EVERYSEC
; 
 421         } else if (!strcasecmp(o
->ptr
,"always")) { 
 422             server
.aof_fsync 
= AOF_FSYNC_ALWAYS
; 
 426     } else if (!strcasecmp(c
->argv
[2]->ptr
,"no-appendfsync-on-rewrite")) { 
 427         int yn 
= yesnotoi(o
->ptr
); 
 429         if (yn 
== -1) goto badfmt
; 
 430         server
.aof_no_fsync_on_rewrite 
= yn
; 
 431     } else if (!strcasecmp(c
->argv
[2]->ptr
,"appendonly")) { 
 432         int enable 
= yesnotoi(o
->ptr
); 
 434         if (enable 
== -1) goto badfmt
; 
 435         if (enable 
== 0 && server
.aof_state 
!= REDIS_AOF_OFF
) { 
 437         } else if (enable 
&& server
.aof_state 
== REDIS_AOF_OFF
) { 
 438             if (startAppendOnly() == REDIS_ERR
) { 
 440                     "Unable to turn on AOF. Check server logs."); 
 444     } else if (!strcasecmp(c
->argv
[2]->ptr
,"auto-aof-rewrite-percentage")) { 
 445         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 446         server
.aof_rewrite_perc 
= ll
; 
 447     } else if (!strcasecmp(c
->argv
[2]->ptr
,"auto-aof-rewrite-min-size")) { 
 448         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 449         server
.aof_rewrite_min_size 
= ll
; 
 450     } else if (!strcasecmp(c
->argv
[2]->ptr
,"save")) { 
 452         sds 
*v 
= sdssplitlen(o
->ptr
,sdslen(o
->ptr
)," ",1,&vlen
); 
 454         /* Perform sanity check before setting the new config: 
 455          * - Even number of args 
 456          * - Seconds >= 1, changes >= 0 */ 
 458             sdsfreesplitres(v
,vlen
); 
 461         for (j 
= 0; j 
< vlen
; j
++) { 
 465             val 
= strtoll(v
[j
], &eptr
, 10); 
 466             if (eptr
[0] != '\0' || 
 467                 ((j 
& 1) == 0 && val 
< 1) || 
 468                 ((j 
& 1) == 1 && val 
< 0)) { 
 469                 sdsfreesplitres(v
,vlen
); 
 473         /* Finally set the new config */ 
 474         resetServerSaveParams(); 
 475         for (j 
= 0; j 
< vlen
; j 
+= 2) { 
 479             seconds 
= strtoll(v
[j
],NULL
,10); 
 480             changes 
= strtoll(v
[j
+1],NULL
,10); 
 481             appendServerSaveParams(seconds
, changes
); 
 483         sdsfreesplitres(v
,vlen
); 
 484     } else if (!strcasecmp(c
->argv
[2]->ptr
,"slave-serve-stale-data")) { 
 485         int yn 
= yesnotoi(o
->ptr
); 
 487         if (yn 
== -1) goto badfmt
; 
 488         server
.repl_serve_stale_data 
= yn
; 
 489     } else if (!strcasecmp(c
->argv
[2]->ptr
,"dir")) { 
 490         if (chdir((char*)o
->ptr
) == -1) { 
 491             addReplyErrorFormat(c
,"Changing directory: %s", strerror(errno
)); 
 494     } else if (!strcasecmp(c
->argv
[2]->ptr
,"hash-max-zipmap-entries")) { 
 495         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 496         server
.hash_max_zipmap_entries 
= ll
; 
 497     } else if (!strcasecmp(c
->argv
[2]->ptr
,"hash-max-zipmap-value")) { 
 498         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 499         server
.hash_max_zipmap_value 
= ll
; 
 500     } else if (!strcasecmp(c
->argv
[2]->ptr
,"list-max-ziplist-entries")) { 
 501         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 502         server
.list_max_ziplist_entries 
= ll
; 
 503     } else if (!strcasecmp(c
->argv
[2]->ptr
,"list-max-ziplist-value")) { 
 504         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 505         server
.list_max_ziplist_value 
= ll
; 
 506     } else if (!strcasecmp(c
->argv
[2]->ptr
,"set-max-intset-entries")) { 
 507         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 508         server
.set_max_intset_entries 
= ll
; 
 509     } else if (!strcasecmp(c
->argv
[2]->ptr
,"zset-max-ziplist-entries")) { 
 510         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 511         server
.zset_max_ziplist_entries 
= ll
; 
 512     } else if (!strcasecmp(c
->argv
[2]->ptr
,"zset-max-ziplist-value")) { 
 513         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 514         server
.zset_max_ziplist_value 
= ll
; 
 515     } else if (!strcasecmp(c
->argv
[2]->ptr
,"lua-time-limit")) { 
 516         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 517         server
.lua_time_limit 
= ll
; 
 518     } else if (!strcasecmp(c
->argv
[2]->ptr
,"slowlog-log-slower-than")) { 
 519         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR
) goto badfmt
; 
 520         server
.slowlog_log_slower_than 
= ll
; 
 521     } else if (!strcasecmp(c
->argv
[2]->ptr
,"slowlog-max-len")) { 
 522         if (getLongLongFromObject(o
,&ll
) == REDIS_ERR 
|| ll 
< 0) goto badfmt
; 
 523         server
.slowlog_max_len 
= (unsigned)ll
; 
 524     } else if (!strcasecmp(c
->argv
[2]->ptr
,"loglevel")) { 
 525         if (!strcasecmp(o
->ptr
,"warning")) { 
 526             server
.verbosity 
= REDIS_WARNING
; 
 527         } else if (!strcasecmp(o
->ptr
,"notice")) { 
 528             server
.verbosity 
= REDIS_NOTICE
; 
 529         } else if (!strcasecmp(o
->ptr
,"verbose")) { 
 530             server
.verbosity 
= REDIS_VERBOSE
; 
 531         } else if (!strcasecmp(o
->ptr
,"debug")) { 
 532             server
.verbosity 
= REDIS_DEBUG
; 
 537         addReplyErrorFormat(c
,"Unsupported CONFIG parameter: %s", 
 538             (char*)c
->argv
[2]->ptr
); 
 541     addReply(c
,shared
.ok
); 
 544 badfmt
: /* Bad format errors */ 
 545     addReplyErrorFormat(c
,"Invalid argument '%s' for CONFIG SET '%s'", 
 547             (char*)c
->argv
[2]->ptr
); 
 550 void configGetCommand(redisClient 
*c
) { 
 551     robj 
*o 
= c
->argv
[2]; 
 552     void *replylen 
= addDeferredMultiBulkLength(c
); 
 553     char *pattern 
= o
->ptr
; 
 556     redisAssertWithInfo(c
,o
,o
->encoding 
== REDIS_ENCODING_RAW
); 
 558     if (stringmatch(pattern
,"dir",0)) { 
 561         if (getcwd(buf
,sizeof(buf
)) == NULL
) 
 564         addReplyBulkCString(c
,"dir"); 
 565         addReplyBulkCString(c
,buf
); 
 568     if (stringmatch(pattern
,"dbfilename",0)) { 
 569         addReplyBulkCString(c
,"dbfilename"); 
 570         addReplyBulkCString(c
,server
.rdb_filename
); 
 573     if (stringmatch(pattern
,"requirepass",0)) { 
 574         addReplyBulkCString(c
,"requirepass"); 
 575         addReplyBulkCString(c
,server
.requirepass
); 
 578     if (stringmatch(pattern
,"masterauth",0)) { 
 579         addReplyBulkCString(c
,"masterauth"); 
 580         addReplyBulkCString(c
,server
.masterauth
); 
 583     if (stringmatch(pattern
,"maxmemory",0)) { 
 584         ll2string(buf
,sizeof(buf
),server
.maxmemory
); 
 585         addReplyBulkCString(c
,"maxmemory"); 
 586         addReplyBulkCString(c
,buf
); 
 589     if (stringmatch(pattern
,"maxmemory-policy",0)) { 
 592         switch(server
.maxmemory_policy
) { 
 593         case REDIS_MAXMEMORY_VOLATILE_LRU
: s 
= "volatile-lru"; break; 
 594         case REDIS_MAXMEMORY_VOLATILE_TTL
: s 
= "volatile-ttl"; break; 
 595         case REDIS_MAXMEMORY_VOLATILE_RANDOM
: s 
= "volatile-random"; break; 
 596         case REDIS_MAXMEMORY_ALLKEYS_LRU
: s 
= "allkeys-lru"; break; 
 597         case REDIS_MAXMEMORY_ALLKEYS_RANDOM
: s 
= "allkeys-random"; break; 
 598         case REDIS_MAXMEMORY_NO_EVICTION
: s 
= "noeviction"; break; 
 599         default: s 
= "unknown"; break; /* too harmless to panic */ 
 601         addReplyBulkCString(c
,"maxmemory-policy"); 
 602         addReplyBulkCString(c
,s
); 
 605     if (stringmatch(pattern
,"maxmemory-samples",0)) { 
 606         ll2string(buf
,sizeof(buf
),server
.maxmemory_samples
); 
 607         addReplyBulkCString(c
,"maxmemory-samples"); 
 608         addReplyBulkCString(c
,buf
); 
 611     if (stringmatch(pattern
,"timeout",0)) { 
 612         ll2string(buf
,sizeof(buf
),server
.maxidletime
); 
 613         addReplyBulkCString(c
,"timeout"); 
 614         addReplyBulkCString(c
,buf
); 
 617     if (stringmatch(pattern
,"appendonly",0)) { 
 618         addReplyBulkCString(c
,"appendonly"); 
 619         addReplyBulkCString(c
,server
.aof_state 
== REDIS_AOF_OFF 
? "no" : "yes"); 
 622     if (stringmatch(pattern
,"no-appendfsync-on-rewrite",0)) { 
 623         addReplyBulkCString(c
,"no-appendfsync-on-rewrite"); 
 624         addReplyBulkCString(c
,server
.aof_no_fsync_on_rewrite 
? "yes" : "no"); 
 627     if (stringmatch(pattern
,"appendfsync",0)) { 
 630         switch(server
.aof_fsync
) { 
 631         case AOF_FSYNC_NO
: policy 
= "no"; break; 
 632         case AOF_FSYNC_EVERYSEC
: policy 
= "everysec"; break; 
 633         case AOF_FSYNC_ALWAYS
: policy 
= "always"; break; 
 634         default: policy 
= "unknown"; break; /* too harmless to panic */ 
 636         addReplyBulkCString(c
,"appendfsync"); 
 637         addReplyBulkCString(c
,policy
); 
 640     if (stringmatch(pattern
,"save",0)) { 
 641         sds buf 
= sdsempty(); 
 644         for (j 
= 0; j 
< server
.saveparamslen
; j
++) { 
 645             buf 
= sdscatprintf(buf
,"%ld %d", 
 646                     server
.saveparams
[j
].seconds
, 
 647                     server
.saveparams
[j
].changes
); 
 648             if (j 
!= server
.saveparamslen
-1) 
 649                 buf 
= sdscatlen(buf
," ",1); 
 651         addReplyBulkCString(c
,"save"); 
 652         addReplyBulkCString(c
,buf
); 
 656     if (stringmatch(pattern
,"auto-aof-rewrite-percentage",0)) { 
 657         addReplyBulkCString(c
,"auto-aof-rewrite-percentage"); 
 658         addReplyBulkLongLong(c
,server
.aof_rewrite_perc
); 
 661     if (stringmatch(pattern
,"auto-aof-rewrite-min-size",0)) { 
 662         addReplyBulkCString(c
,"auto-aof-rewrite-min-size"); 
 663         addReplyBulkLongLong(c
,server
.aof_rewrite_min_size
); 
 666     if (stringmatch(pattern
,"slave-serve-stale-data",0)) { 
 667         addReplyBulkCString(c
,"slave-serve-stale-data"); 
 668         addReplyBulkCString(c
,server
.repl_serve_stale_data 
? "yes" : "no"); 
 671     if (stringmatch(pattern
,"hash-max-zipmap-entries",0)) { 
 672         addReplyBulkCString(c
,"hash-max-zipmap-entries"); 
 673         addReplyBulkLongLong(c
,server
.hash_max_zipmap_entries
); 
 676     if (stringmatch(pattern
,"hash-max-zipmap-value",0)) { 
 677         addReplyBulkCString(c
,"hash-max-zipmap-value"); 
 678         addReplyBulkLongLong(c
,server
.hash_max_zipmap_value
); 
 681     if (stringmatch(pattern
,"list-max-ziplist-entries",0)) { 
 682         addReplyBulkCString(c
,"list-max-ziplist-entries"); 
 683         addReplyBulkLongLong(c
,server
.list_max_ziplist_entries
); 
 686     if (stringmatch(pattern
,"list-max-ziplist-value",0)) { 
 687         addReplyBulkCString(c
,"list-max-ziplist-value"); 
 688         addReplyBulkLongLong(c
,server
.list_max_ziplist_value
); 
 691     if (stringmatch(pattern
,"set-max-intset-entries",0)) { 
 692         addReplyBulkCString(c
,"set-max-intset-entries"); 
 693         addReplyBulkLongLong(c
,server
.set_max_intset_entries
); 
 696     if (stringmatch(pattern
,"zset-max-ziplist-entries",0)) { 
 697         addReplyBulkCString(c
,"zset-max-ziplist-entries"); 
 698         addReplyBulkLongLong(c
,server
.zset_max_ziplist_entries
); 
 701     if (stringmatch(pattern
,"zset-max-ziplist-value",0)) { 
 702         addReplyBulkCString(c
,"zset-max-ziplist-value"); 
 703         addReplyBulkLongLong(c
,server
.zset_max_ziplist_value
); 
 706     if (stringmatch(pattern
,"lua-time-limit",0)) { 
 707         addReplyBulkCString(c
,"lua-time-limit"); 
 708         addReplyBulkLongLong(c
,server
.lua_time_limit
); 
 711     if (stringmatch(pattern
,"slowlog-log-slower-than",0)) { 
 712         addReplyBulkCString(c
,"slowlog-log-slower-than"); 
 713         addReplyBulkLongLong(c
,server
.slowlog_log_slower_than
); 
 716     if (stringmatch(pattern
,"slowlog-max-len",0)) { 
 717         addReplyBulkCString(c
,"slowlog-max-len"); 
 718         addReplyBulkLongLong(c
,server
.slowlog_max_len
); 
 721     if (stringmatch(pattern
,"loglevel",0)) { 
 724         switch(server
.verbosity
) { 
 725         case REDIS_WARNING
: s 
= "warning"; break; 
 726         case REDIS_VERBOSE
: s 
= "verbose"; break; 
 727         case REDIS_NOTICE
: s 
= "notice"; break; 
 728         case REDIS_DEBUG
: s 
= "debug"; break; 
 729         default: s 
= "unknown"; break; /* too harmless to panic */ 
 731         addReplyBulkCString(c
,"loglevel"); 
 732         addReplyBulkCString(c
,s
); 
 735     setDeferredMultiBulkLength(c
,replylen
,matches
*2); 
 738 void configCommand(redisClient 
*c
) { 
 739     if (!strcasecmp(c
->argv
[1]->ptr
,"set")) { 
 740         if (c
->argc 
!= 4) goto badarity
; 
 742     } else if (!strcasecmp(c
->argv
[1]->ptr
,"get")) { 
 743         if (c
->argc 
!= 3) goto badarity
; 
 745     } else if (!strcasecmp(c
->argv
[1]->ptr
,"resetstat")) { 
 746         if (c
->argc 
!= 2) goto badarity
; 
 747         server
.stat_keyspace_hits 
= 0; 
 748         server
.stat_keyspace_misses 
= 0; 
 749         server
.stat_numcommands 
= 0; 
 750         server
.stat_numconnections 
= 0; 
 751         server
.stat_expiredkeys 
= 0; 
 752         resetCommandTableStats(); 
 753         addReply(c
,shared
.ok
); 
 756             "CONFIG subcommand must be one of GET, SET, RESETSTAT"); 
 761     addReplyErrorFormat(c
,"Wrong number of arguments for CONFIG %s", 
 762         (char*) c
->argv
[1]->ptr
);