]> git.saurik.com Git - redis.git/blame_incremental - src/config.c
AOF refactoring, now with three states: ON, OFF, WAIT_REWRITE.
[redis.git] / src / config.c
... / ...
CommitLineData
1#include "redis.h"
2
3/*-----------------------------------------------------------------------------
4 * Config file parsing
5 *----------------------------------------------------------------------------*/
6
7int yesnotoi(char *s) {
8 if (!strcasecmp(s,"yes")) return 1;
9 else if (!strcasecmp(s,"no")) return 0;
10 else return -1;
11}
12
13void 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++;
18}
19
20void resetServerSaveParams() {
21 zfree(server.saveparams);
22 server.saveparams = NULL;
23 server.saveparamslen = 0;
24}
25
26void loadServerConfigFromString(char *config) {
27 char *err = NULL;
28 int linenum = 0, totlines, i;
29 sds *lines;
30
31 lines = sdssplitlen(config,strlen(config),"\n",1,&totlines);
32
33 for (i = 0; i < totlines; i++) {
34 sds *argv;
35 int argc;
36
37 linenum = i+1;
38 lines[i] = sdstrim(lines[i]," \t\r\n");
39
40 /* Skip comments and blank lines*/
41 if (lines[i][0] == '#' || lines[i][0] == '\0') continue;
42
43 /* Split into arguments */
44 argv = sdssplitargs(lines[i],&argc);
45 sdstolower(argv[0]);
46
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;
52 }
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;
57 }
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) {
63 errno = 0;
64 server.unixsocketperm = (mode_t)strtol(argv[1], NULL, 8);
65 if (errno || server.unixsocketperm > 0777) {
66 err = "Invalid socket file permissions"; goto loaderr;
67 }
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;
73 }
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));
79 exit(1);
80 }
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;
86 else {
87 err = "Invalid log level. Must be one of debug, notice, warning";
88 goto loaderr;
89 }
90 } else if (!strcasecmp(argv[0],"logfile") && argc == 2) {
91 FILE *logfp;
92
93 server.logfile = zstrdup(argv[1]);
94 if (!strcasecmp(server.logfile,"stdout")) {
95 zfree(server.logfile);
96 server.logfile = NULL;
97 }
98 if (server.logfile) {
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");
102 if (logfp == NULL) {
103 err = sdscatprintf(sdsempty(),
104 "Can't open the log file: %s", strerror(errno));
105 goto loaderr;
106 }
107 fclose(logfp);
108 }
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;
112 }
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) {
117 struct {
118 const char *name;
119 const int value;
120 } validSyslogFacilities[] = {
121 {"user", LOG_USER},
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},
130 {NULL, 0}
131 };
132 int i;
133
134 for (i = 0; validSyslogFacilities[i].name; i++) {
135 if (!strcasecmp(validSyslogFacilities[i].name, argv[1])) {
136 server.syslog_facility = validSyslogFacilities[i].value;
137 break;
138 }
139 }
140
141 if (!validSyslogFacilities[i].name) {
142 err = "Invalid log facility. Must be one of USER or between LOCAL0-LOCAL7";
143 goto loaderr;
144 }
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;
149 }
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;
169 } else {
170 err = "Invalid maxmemory policy";
171 goto loaderr;
172 }
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";
177 goto loaderr;
178 }
179 } else if (!strcasecmp(argv[0],"slaveof") && argc == 3) {
180 server.masterhost = sdsnew(argv[1]);
181 server.masterport = atoi(argv[2]);
182 server.replstate = 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";
187 goto loaderr;
188 }
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";
193 goto loaderr;
194 }
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;
200 }
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.rdbcompression = yesnotoi(argv[1])) == -1) {
205 err = "argument must be 'yes' or 'no'"; goto loaderr;
206 }
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;
210 }
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;
214 }
215 } else if (!strcasecmp(argv[0],"appendonly") && argc == 2) {
216 int yes;
217
218 if ((yes = yesnotoi(argv[1])) == -1) {
219 err = "argument must be 'yes' or 'no'"; goto loaderr;
220 }
221 server.aof_state = yes ? REDIS_AOF_ON : REDIS_AOF_OFF;
222 } else if (!strcasecmp(argv[0],"appendfilename") && argc == 2) {
223 zfree(server.appendfilename);
224 server.appendfilename = zstrdup(argv[1]);
225 } else if (!strcasecmp(argv[0],"no-appendfsync-on-rewrite")
226 && argc == 2) {
227 if ((server.no_appendfsync_on_rewrite= yesnotoi(argv[1])) == -1) {
228 err = "argument must be 'yes' or 'no'"; goto loaderr;
229 }
230 } else if (!strcasecmp(argv[0],"appendfsync") && argc == 2) {
231 if (!strcasecmp(argv[1],"no")) {
232 server.appendfsync = APPENDFSYNC_NO;
233 } else if (!strcasecmp(argv[1],"always")) {
234 server.appendfsync = APPENDFSYNC_ALWAYS;
235 } else if (!strcasecmp(argv[1],"everysec")) {
236 server.appendfsync = APPENDFSYNC_EVERYSEC;
237 } else {
238 err = "argument must be 'no', 'always' or 'everysec'";
239 goto loaderr;
240 }
241 } else if (!strcasecmp(argv[0],"auto-aof-rewrite-percentage") &&
242 argc == 2)
243 {
244 server.auto_aofrewrite_perc = atoi(argv[1]);
245 if (server.auto_aofrewrite_perc < 0) {
246 err = "Invalid negative percentage for AOF auto rewrite";
247 goto loaderr;
248 }
249 } else if (!strcasecmp(argv[0],"auto-aof-rewrite-min-size") &&
250 argc == 2)
251 {
252 server.auto_aofrewrite_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.dbfilename);
260 server.dbfilename = 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]);
277 int retval;
278
279 if (!cmd) {
280 err = "No such command in rename-command";
281 goto loaderr;
282 }
283
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);
288
289 /* Otherwise we re-add the command under a different name. */
290 if (sdslen(argv[2]) != 0) {
291 sds copy = sdsdup(argv[2]);
292
293 retval = dictAdd(server.commands, copy, cmd);
294 if (retval != DICT_OK) {
295 sdsfree(copy);
296 err = "Target command name already exists"; goto loaderr;
297 }
298 }
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;
302 }
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") &&
309 argc == 2)
310 {
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);
314 } else {
315 err = "Bad directive or wrong number of arguments"; goto loaderr;
316 }
317 sdsfreesplitres(argv,argc);
318 }
319 sdsfreesplitres(lines,totlines);
320 return;
321
322loaderr:
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);
327 exit(1);
328}
329
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.
333 *
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. */
337void loadServerConfig(char *filename, char *options) {
338 sds config = sdsempty();
339 char buf[REDIS_CONFIGLINE_MAX+1];
340
341 /* Load the file content */
342 if (filename) {
343 FILE *fp;
344
345 if (filename[0] == '-' && filename[1] == '\0') {
346 fp = stdin;
347 } else {
348 if ((fp = fopen(filename,"r")) == NULL) {
349 redisLog(REDIS_WARNING,
350 "Fatal error, can't open config file '%s'", filename);
351 exit(1);
352 }
353 }
354 while(fgets(buf,REDIS_CONFIGLINE_MAX+1,fp) != NULL)
355 config = sdscat(config,buf);
356 if (fp != stdin) fclose(fp);
357 }
358 /* Append the additional options */
359 if (options) {
360 config = sdscat(config,"\n");
361 config = sdscat(config,options);
362 }
363 loadServerConfigFromString(config);
364 sdsfree(config);
365}
366
367/*-----------------------------------------------------------------------------
368 * CONFIG command for remote configuration
369 *----------------------------------------------------------------------------*/
370
371void configSetCommand(redisClient *c) {
372 robj *o;
373 long long ll;
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);
376 o = c->argv[3];
377
378 if (!strcasecmp(c->argv[2]->ptr,"dbfilename")) {
379 zfree(server.dbfilename);
380 server.dbfilename = 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 ||
389 ll < 0) goto badfmt;
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;
405 } else {
406 goto badfmt;
407 }
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.appendfsync = APPENDFSYNC_NO;
419 } else if (!strcasecmp(o->ptr,"everysec")) {
420 server.appendfsync = APPENDFSYNC_EVERYSEC;
421 } else if (!strcasecmp(o->ptr,"always")) {
422 server.appendfsync = APPENDFSYNC_ALWAYS;
423 } else {
424 goto badfmt;
425 }
426 } else if (!strcasecmp(c->argv[2]->ptr,"no-appendfsync-on-rewrite")) {
427 int yn = yesnotoi(o->ptr);
428
429 if (yn == -1) goto badfmt;
430 server.no_appendfsync_on_rewrite = yn;
431 } else if (!strcasecmp(c->argv[2]->ptr,"appendonly")) {
432 int enable = yesnotoi(o->ptr);
433
434 if (enable == -1) goto badfmt;
435 if (enable == 0 && server.aof_state != REDIS_AOF_OFF) {
436 stopAppendOnly();
437 } else if (enable && server.aof_state == REDIS_AOF_OFF) {
438 if (startAppendOnly() == REDIS_ERR) {
439 addReplyError(c,
440 "Unable to turn on AOF. Check server logs.");
441 return;
442 }
443 }
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.auto_aofrewrite_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.auto_aofrewrite_min_size = ll;
450 } else if (!strcasecmp(c->argv[2]->ptr,"save")) {
451 int vlen, j;
452 sds *v = sdssplitlen(o->ptr,sdslen(o->ptr)," ",1,&vlen);
453
454 /* Perform sanity check before setting the new config:
455 * - Even number of args
456 * - Seconds >= 1, changes >= 0 */
457 if (vlen & 1) {
458 sdsfreesplitres(v,vlen);
459 goto badfmt;
460 }
461 for (j = 0; j < vlen; j++) {
462 char *eptr;
463 long val;
464
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);
470 goto badfmt;
471 }
472 }
473 /* Finally set the new config */
474 resetServerSaveParams();
475 for (j = 0; j < vlen; j += 2) {
476 time_t seconds;
477 int changes;
478
479 seconds = strtoll(v[j],NULL,10);
480 changes = strtoll(v[j+1],NULL,10);
481 appendServerSaveParams(seconds, changes);
482 }
483 sdsfreesplitres(v,vlen);
484 } else if (!strcasecmp(c->argv[2]->ptr,"slave-serve-stale-data")) {
485 int yn = yesnotoi(o->ptr);
486
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));
492 return;
493 }
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;
533 } else {
534 goto badfmt;
535 }
536 } else {
537 addReplyErrorFormat(c,"Unsupported CONFIG parameter: %s",
538 (char*)c->argv[2]->ptr);
539 return;
540 }
541 addReply(c,shared.ok);
542 return;
543
544badfmt: /* Bad format errors */
545 addReplyErrorFormat(c,"Invalid argument '%s' for CONFIG SET '%s'",
546 (char*)o->ptr,
547 (char*)c->argv[2]->ptr);
548}
549
550void configGetCommand(redisClient *c) {
551 robj *o = c->argv[2];
552 void *replylen = addDeferredMultiBulkLength(c);
553 char *pattern = o->ptr;
554 char buf[128];
555 int matches = 0;
556 redisAssertWithInfo(c,o,o->encoding == REDIS_ENCODING_RAW);
557
558 if (stringmatch(pattern,"dir",0)) {
559 char buf[1024];
560
561 if (getcwd(buf,sizeof(buf)) == NULL)
562 buf[0] = '\0';
563
564 addReplyBulkCString(c,"dir");
565 addReplyBulkCString(c,buf);
566 matches++;
567 }
568 if (stringmatch(pattern,"dbfilename",0)) {
569 addReplyBulkCString(c,"dbfilename");
570 addReplyBulkCString(c,server.dbfilename);
571 matches++;
572 }
573 if (stringmatch(pattern,"requirepass",0)) {
574 addReplyBulkCString(c,"requirepass");
575 addReplyBulkCString(c,server.requirepass);
576 matches++;
577 }
578 if (stringmatch(pattern,"masterauth",0)) {
579 addReplyBulkCString(c,"masterauth");
580 addReplyBulkCString(c,server.masterauth);
581 matches++;
582 }
583 if (stringmatch(pattern,"maxmemory",0)) {
584 ll2string(buf,sizeof(buf),server.maxmemory);
585 addReplyBulkCString(c,"maxmemory");
586 addReplyBulkCString(c,buf);
587 matches++;
588 }
589 if (stringmatch(pattern,"maxmemory-policy",0)) {
590 char *s;
591
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 */
600 }
601 addReplyBulkCString(c,"maxmemory-policy");
602 addReplyBulkCString(c,s);
603 matches++;
604 }
605 if (stringmatch(pattern,"maxmemory-samples",0)) {
606 ll2string(buf,sizeof(buf),server.maxmemory_samples);
607 addReplyBulkCString(c,"maxmemory-samples");
608 addReplyBulkCString(c,buf);
609 matches++;
610 }
611 if (stringmatch(pattern,"timeout",0)) {
612 ll2string(buf,sizeof(buf),server.maxidletime);
613 addReplyBulkCString(c,"timeout");
614 addReplyBulkCString(c,buf);
615 matches++;
616 }
617 if (stringmatch(pattern,"appendonly",0)) {
618 addReplyBulkCString(c,"appendonly");
619 addReplyBulkCString(c,server.aof_state == REDIS_AOF_OFF ? "no" : "yes");
620 matches++;
621 }
622 if (stringmatch(pattern,"no-appendfsync-on-rewrite",0)) {
623 addReplyBulkCString(c,"no-appendfsync-on-rewrite");
624 addReplyBulkCString(c,server.no_appendfsync_on_rewrite ? "yes" : "no");
625 matches++;
626 }
627 if (stringmatch(pattern,"appendfsync",0)) {
628 char *policy;
629
630 switch(server.appendfsync) {
631 case APPENDFSYNC_NO: policy = "no"; break;
632 case APPENDFSYNC_EVERYSEC: policy = "everysec"; break;
633 case APPENDFSYNC_ALWAYS: policy = "always"; break;
634 default: policy = "unknown"; break; /* too harmless to panic */
635 }
636 addReplyBulkCString(c,"appendfsync");
637 addReplyBulkCString(c,policy);
638 matches++;
639 }
640 if (stringmatch(pattern,"save",0)) {
641 sds buf = sdsempty();
642 int j;
643
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);
650 }
651 addReplyBulkCString(c,"save");
652 addReplyBulkCString(c,buf);
653 sdsfree(buf);
654 matches++;
655 }
656 if (stringmatch(pattern,"auto-aof-rewrite-percentage",0)) {
657 addReplyBulkCString(c,"auto-aof-rewrite-percentage");
658 addReplyBulkLongLong(c,server.auto_aofrewrite_perc);
659 matches++;
660 }
661 if (stringmatch(pattern,"auto-aof-rewrite-min-size",0)) {
662 addReplyBulkCString(c,"auto-aof-rewrite-min-size");
663 addReplyBulkLongLong(c,server.auto_aofrewrite_min_size);
664 matches++;
665 }
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");
669 matches++;
670 }
671 if (stringmatch(pattern,"hash-max-zipmap-entries",0)) {
672 addReplyBulkCString(c,"hash-max-zipmap-entries");
673 addReplyBulkLongLong(c,server.hash_max_zipmap_entries);
674 matches++;
675 }
676 if (stringmatch(pattern,"hash-max-zipmap-value",0)) {
677 addReplyBulkCString(c,"hash-max-zipmap-value");
678 addReplyBulkLongLong(c,server.hash_max_zipmap_value);
679 matches++;
680 }
681 if (stringmatch(pattern,"list-max-ziplist-entries",0)) {
682 addReplyBulkCString(c,"list-max-ziplist-entries");
683 addReplyBulkLongLong(c,server.list_max_ziplist_entries);
684 matches++;
685 }
686 if (stringmatch(pattern,"list-max-ziplist-value",0)) {
687 addReplyBulkCString(c,"list-max-ziplist-value");
688 addReplyBulkLongLong(c,server.list_max_ziplist_value);
689 matches++;
690 }
691 if (stringmatch(pattern,"set-max-intset-entries",0)) {
692 addReplyBulkCString(c,"set-max-intset-entries");
693 addReplyBulkLongLong(c,server.set_max_intset_entries);
694 matches++;
695 }
696 if (stringmatch(pattern,"zset-max-ziplist-entries",0)) {
697 addReplyBulkCString(c,"zset-max-ziplist-entries");
698 addReplyBulkLongLong(c,server.zset_max_ziplist_entries);
699 matches++;
700 }
701 if (stringmatch(pattern,"zset-max-ziplist-value",0)) {
702 addReplyBulkCString(c,"zset-max-ziplist-value");
703 addReplyBulkLongLong(c,server.zset_max_ziplist_value);
704 matches++;
705 }
706 if (stringmatch(pattern,"lua-time-limit",0)) {
707 addReplyBulkCString(c,"lua-time-limit");
708 addReplyBulkLongLong(c,server.lua_time_limit);
709 matches++;
710 }
711 if (stringmatch(pattern,"slowlog-log-slower-than",0)) {
712 addReplyBulkCString(c,"slowlog-log-slower-than");
713 addReplyBulkLongLong(c,server.slowlog_log_slower_than);
714 matches++;
715 }
716 if (stringmatch(pattern,"slowlog-max-len",0)) {
717 addReplyBulkCString(c,"slowlog-max-len");
718 addReplyBulkLongLong(c,server.slowlog_max_len);
719 matches++;
720 }
721 if (stringmatch(pattern,"loglevel",0)) {
722 char *s;
723
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 */
730 }
731 addReplyBulkCString(c,"loglevel");
732 addReplyBulkCString(c,s);
733 matches++;
734 }
735 setDeferredMultiBulkLength(c,replylen,matches*2);
736}
737
738void configCommand(redisClient *c) {
739 if (!strcasecmp(c->argv[1]->ptr,"set")) {
740 if (c->argc != 4) goto badarity;
741 configSetCommand(c);
742 } else if (!strcasecmp(c->argv[1]->ptr,"get")) {
743 if (c->argc != 3) goto badarity;
744 configGetCommand(c);
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);
754 } else {
755 addReplyError(c,
756 "CONFIG subcommand must be one of GET, SET, RESETSTAT");
757 }
758 return;
759
760badarity:
761 addReplyErrorFormat(c,"Wrong number of arguments for CONFIG %s",
762 (char*) c->argv[1]->ptr);
763}