]> git.saurik.com Git - redis.git/blob - src/config.c
Update default configuration
[redis.git] / src / config.c
1 #include "redis.h"
2
3 /*-----------------------------------------------------------------------------
4 * Config file parsing
5 *----------------------------------------------------------------------------*/
6
7 int yesnotoi(char *s) {
8 if (!strcasecmp(s,"yes")) return 1;
9 else if (!strcasecmp(s,"no")) return 0;
10 else return -1;
11 }
12
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++;
18 }
19
20 void resetServerSaveParams() {
21 zfree(server.saveparams);
22 server.saveparams = NULL;
23 server.saveparamslen = 0;
24 }
25
26 void 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.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";
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.rdb_compression = 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.aof_filename);
224 server.aof_filename = zstrdup(argv[1]);
225 } else if (!strcasecmp(argv[0],"no-appendfsync-on-rewrite")
226 && argc == 2) {
227 if ((server.aof_no_fsync_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.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;
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.aof_rewrite_perc = atoi(argv[1]);
245 if (server.aof_rewrite_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.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 redisLog(REDIS_WARNING, "Deprecated configuration directive: \"%s\"", argv[0]);
263 server.hash_max_ziplist_entries = memtoll(argv[1], NULL);
264 } else if (!strcasecmp(argv[0],"hash-max-zipmap-value") && argc == 2) {
265 redisLog(REDIS_WARNING, "Deprecated configuration directive: \"%s\"", argv[0]);
266 server.hash_max_ziplist_value = memtoll(argv[1], NULL);
267 } else if (!strcasecmp(argv[0],"hash-max-ziplist-entries") && argc == 2) {
268 server.hash_max_ziplist_entries = memtoll(argv[1], NULL);
269 } else if (!strcasecmp(argv[0],"hash-max-ziplist-value") && argc == 2) {
270 server.hash_max_ziplist_value = memtoll(argv[1], NULL);
271 } else if (!strcasecmp(argv[0],"list-max-ziplist-entries") && argc == 2){
272 server.list_max_ziplist_entries = memtoll(argv[1], NULL);
273 } else if (!strcasecmp(argv[0],"list-max-ziplist-value") && argc == 2) {
274 server.list_max_ziplist_value = memtoll(argv[1], NULL);
275 } else if (!strcasecmp(argv[0],"set-max-intset-entries") && argc == 2) {
276 server.set_max_intset_entries = memtoll(argv[1], NULL);
277 } else if (!strcasecmp(argv[0],"zset-max-ziplist-entries") && argc == 2) {
278 server.zset_max_ziplist_entries = memtoll(argv[1], NULL);
279 } else if (!strcasecmp(argv[0],"zset-max-ziplist-value") && argc == 2) {
280 server.zset_max_ziplist_value = memtoll(argv[1], NULL);
281 } else if (!strcasecmp(argv[0],"rename-command") && argc == 3) {
282 struct redisCommand *cmd = lookupCommand(argv[1]);
283 int retval;
284
285 if (!cmd) {
286 err = "No such command in rename-command";
287 goto loaderr;
288 }
289
290 /* If the target command name is the emtpy string we just
291 * remove it from the command table. */
292 retval = dictDelete(server.commands, argv[1]);
293 redisAssert(retval == DICT_OK);
294
295 /* Otherwise we re-add the command under a different name. */
296 if (sdslen(argv[2]) != 0) {
297 sds copy = sdsdup(argv[2]);
298
299 retval = dictAdd(server.commands, copy, cmd);
300 if (retval != DICT_OK) {
301 sdsfree(copy);
302 err = "Target command name already exists"; goto loaderr;
303 }
304 }
305 } else if (!strcasecmp(argv[0],"cluster-enabled") && argc == 2) {
306 if ((server.cluster_enabled = yesnotoi(argv[1])) == -1) {
307 err = "argument must be 'yes' or 'no'"; goto loaderr;
308 }
309 } else if (!strcasecmp(argv[0],"cluster-config-file") && argc == 2) {
310 zfree(server.cluster.configfile);
311 server.cluster.configfile = zstrdup(argv[1]);
312 } else if (!strcasecmp(argv[0],"lua-time-limit") && argc == 2) {
313 server.lua_time_limit = strtoll(argv[1],NULL,10);
314 } else if (!strcasecmp(argv[0],"slowlog-log-slower-than") &&
315 argc == 2)
316 {
317 server.slowlog_log_slower_than = strtoll(argv[1],NULL,10);
318 } else if (!strcasecmp(argv[0],"slowlog-max-len") && argc == 2) {
319 server.slowlog_max_len = strtoll(argv[1],NULL,10);
320 } else {
321 err = "Bad directive or wrong number of arguments"; goto loaderr;
322 }
323 sdsfreesplitres(argv,argc);
324 }
325 sdsfreesplitres(lines,totlines);
326 return;
327
328 loaderr:
329 fprintf(stderr, "\n*** FATAL CONFIG FILE ERROR ***\n");
330 fprintf(stderr, "Reading the configuration file, at line %d\n", linenum);
331 fprintf(stderr, ">>> '%s'\n", lines[i]);
332 fprintf(stderr, "%s\n", err);
333 exit(1);
334 }
335
336 /* Load the server configuration from the specified filename.
337 * The function appends the additional configuration directives stored
338 * in the 'options' string to the config file before loading.
339 *
340 * Both filename and options can be NULL, in such a case are considered
341 * emtpy. This way loadServerConfig can be used to just load a file or
342 * just load a string. */
343 void loadServerConfig(char *filename, char *options) {
344 sds config = sdsempty();
345 char buf[REDIS_CONFIGLINE_MAX+1];
346
347 /* Load the file content */
348 if (filename) {
349 FILE *fp;
350
351 if (filename[0] == '-' && filename[1] == '\0') {
352 fp = stdin;
353 } else {
354 if ((fp = fopen(filename,"r")) == NULL) {
355 redisLog(REDIS_WARNING,
356 "Fatal error, can't open config file '%s'", filename);
357 exit(1);
358 }
359 }
360 while(fgets(buf,REDIS_CONFIGLINE_MAX+1,fp) != NULL)
361 config = sdscat(config,buf);
362 if (fp != stdin) fclose(fp);
363 }
364 /* Append the additional options */
365 if (options) {
366 config = sdscat(config,"\n");
367 config = sdscat(config,options);
368 }
369 loadServerConfigFromString(config);
370 sdsfree(config);
371 }
372
373 /*-----------------------------------------------------------------------------
374 * CONFIG command for remote configuration
375 *----------------------------------------------------------------------------*/
376
377 void configSetCommand(redisClient *c) {
378 robj *o;
379 long long ll;
380 redisAssertWithInfo(c,c->argv[2],c->argv[2]->encoding == REDIS_ENCODING_RAW);
381 redisAssertWithInfo(c,c->argv[2],c->argv[3]->encoding == REDIS_ENCODING_RAW);
382 o = c->argv[3];
383
384 if (!strcasecmp(c->argv[2]->ptr,"dbfilename")) {
385 zfree(server.rdb_filename);
386 server.rdb_filename = zstrdup(o->ptr);
387 } else if (!strcasecmp(c->argv[2]->ptr,"requirepass")) {
388 zfree(server.requirepass);
389 server.requirepass = ((char*)o->ptr)[0] ? zstrdup(o->ptr) : NULL;
390 } else if (!strcasecmp(c->argv[2]->ptr,"masterauth")) {
391 zfree(server.masterauth);
392 server.masterauth = zstrdup(o->ptr);
393 } else if (!strcasecmp(c->argv[2]->ptr,"maxmemory")) {
394 if (getLongLongFromObject(o,&ll) == REDIS_ERR ||
395 ll < 0) goto badfmt;
396 server.maxmemory = ll;
397 if (server.maxmemory) freeMemoryIfNeeded();
398 } else if (!strcasecmp(c->argv[2]->ptr,"maxmemory-policy")) {
399 if (!strcasecmp(o->ptr,"volatile-lru")) {
400 server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_LRU;
401 } else if (!strcasecmp(o->ptr,"volatile-random")) {
402 server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_RANDOM;
403 } else if (!strcasecmp(o->ptr,"volatile-ttl")) {
404 server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_TTL;
405 } else if (!strcasecmp(o->ptr,"allkeys-lru")) {
406 server.maxmemory_policy = REDIS_MAXMEMORY_ALLKEYS_LRU;
407 } else if (!strcasecmp(o->ptr,"allkeys-random")) {
408 server.maxmemory_policy = REDIS_MAXMEMORY_ALLKEYS_RANDOM;
409 } else if (!strcasecmp(o->ptr,"noeviction")) {
410 server.maxmemory_policy = REDIS_MAXMEMORY_NO_EVICTION;
411 } else {
412 goto badfmt;
413 }
414 } else if (!strcasecmp(c->argv[2]->ptr,"maxmemory-samples")) {
415 if (getLongLongFromObject(o,&ll) == REDIS_ERR ||
416 ll <= 0) goto badfmt;
417 server.maxmemory_samples = ll;
418 } else if (!strcasecmp(c->argv[2]->ptr,"timeout")) {
419 if (getLongLongFromObject(o,&ll) == REDIS_ERR ||
420 ll < 0 || ll > LONG_MAX) goto badfmt;
421 server.maxidletime = ll;
422 } else if (!strcasecmp(c->argv[2]->ptr,"appendfsync")) {
423 if (!strcasecmp(o->ptr,"no")) {
424 server.aof_fsync = AOF_FSYNC_NO;
425 } else if (!strcasecmp(o->ptr,"everysec")) {
426 server.aof_fsync = AOF_FSYNC_EVERYSEC;
427 } else if (!strcasecmp(o->ptr,"always")) {
428 server.aof_fsync = AOF_FSYNC_ALWAYS;
429 } else {
430 goto badfmt;
431 }
432 } else if (!strcasecmp(c->argv[2]->ptr,"no-appendfsync-on-rewrite")) {
433 int yn = yesnotoi(o->ptr);
434
435 if (yn == -1) goto badfmt;
436 server.aof_no_fsync_on_rewrite = yn;
437 } else if (!strcasecmp(c->argv[2]->ptr,"appendonly")) {
438 int enable = yesnotoi(o->ptr);
439
440 if (enable == -1) goto badfmt;
441 if (enable == 0 && server.aof_state != REDIS_AOF_OFF) {
442 stopAppendOnly();
443 } else if (enable && server.aof_state == REDIS_AOF_OFF) {
444 if (startAppendOnly() == REDIS_ERR) {
445 addReplyError(c,
446 "Unable to turn on AOF. Check server logs.");
447 return;
448 }
449 }
450 } else if (!strcasecmp(c->argv[2]->ptr,"auto-aof-rewrite-percentage")) {
451 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
452 server.aof_rewrite_perc = ll;
453 } else if (!strcasecmp(c->argv[2]->ptr,"auto-aof-rewrite-min-size")) {
454 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
455 server.aof_rewrite_min_size = ll;
456 } else if (!strcasecmp(c->argv[2]->ptr,"save")) {
457 int vlen, j;
458 sds *v = sdssplitlen(o->ptr,sdslen(o->ptr)," ",1,&vlen);
459
460 /* Perform sanity check before setting the new config:
461 * - Even number of args
462 * - Seconds >= 1, changes >= 0 */
463 if (vlen & 1) {
464 sdsfreesplitres(v,vlen);
465 goto badfmt;
466 }
467 for (j = 0; j < vlen; j++) {
468 char *eptr;
469 long val;
470
471 val = strtoll(v[j], &eptr, 10);
472 if (eptr[0] != '\0' ||
473 ((j & 1) == 0 && val < 1) ||
474 ((j & 1) == 1 && val < 0)) {
475 sdsfreesplitres(v,vlen);
476 goto badfmt;
477 }
478 }
479 /* Finally set the new config */
480 resetServerSaveParams();
481 for (j = 0; j < vlen; j += 2) {
482 time_t seconds;
483 int changes;
484
485 seconds = strtoll(v[j],NULL,10);
486 changes = strtoll(v[j+1],NULL,10);
487 appendServerSaveParams(seconds, changes);
488 }
489 sdsfreesplitres(v,vlen);
490 } else if (!strcasecmp(c->argv[2]->ptr,"slave-serve-stale-data")) {
491 int yn = yesnotoi(o->ptr);
492
493 if (yn == -1) goto badfmt;
494 server.repl_serve_stale_data = yn;
495 } else if (!strcasecmp(c->argv[2]->ptr,"dir")) {
496 if (chdir((char*)o->ptr) == -1) {
497 addReplyErrorFormat(c,"Changing directory: %s", strerror(errno));
498 return;
499 }
500 } else if (!strcasecmp(c->argv[2]->ptr,"hash-max-ziplist-entries")) {
501 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
502 server.hash_max_ziplist_entries = ll;
503 } else if (!strcasecmp(c->argv[2]->ptr,"hash-max-ziplist-value")) {
504 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
505 server.hash_max_ziplist_value = ll;
506 } else if (!strcasecmp(c->argv[2]->ptr,"list-max-ziplist-entries")) {
507 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
508 server.list_max_ziplist_entries = ll;
509 } else if (!strcasecmp(c->argv[2]->ptr,"list-max-ziplist-value")) {
510 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
511 server.list_max_ziplist_value = ll;
512 } else if (!strcasecmp(c->argv[2]->ptr,"set-max-intset-entries")) {
513 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
514 server.set_max_intset_entries = ll;
515 } else if (!strcasecmp(c->argv[2]->ptr,"zset-max-ziplist-entries")) {
516 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
517 server.zset_max_ziplist_entries = ll;
518 } else if (!strcasecmp(c->argv[2]->ptr,"zset-max-ziplist-value")) {
519 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
520 server.zset_max_ziplist_value = ll;
521 } else if (!strcasecmp(c->argv[2]->ptr,"lua-time-limit")) {
522 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
523 server.lua_time_limit = ll;
524 } else if (!strcasecmp(c->argv[2]->ptr,"slowlog-log-slower-than")) {
525 if (getLongLongFromObject(o,&ll) == REDIS_ERR) goto badfmt;
526 server.slowlog_log_slower_than = ll;
527 } else if (!strcasecmp(c->argv[2]->ptr,"slowlog-max-len")) {
528 if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
529 server.slowlog_max_len = (unsigned)ll;
530 } else if (!strcasecmp(c->argv[2]->ptr,"loglevel")) {
531 if (!strcasecmp(o->ptr,"warning")) {
532 server.verbosity = REDIS_WARNING;
533 } else if (!strcasecmp(o->ptr,"notice")) {
534 server.verbosity = REDIS_NOTICE;
535 } else if (!strcasecmp(o->ptr,"verbose")) {
536 server.verbosity = REDIS_VERBOSE;
537 } else if (!strcasecmp(o->ptr,"debug")) {
538 server.verbosity = REDIS_DEBUG;
539 } else {
540 goto badfmt;
541 }
542 } else {
543 addReplyErrorFormat(c,"Unsupported CONFIG parameter: %s",
544 (char*)c->argv[2]->ptr);
545 return;
546 }
547 addReply(c,shared.ok);
548 return;
549
550 badfmt: /* Bad format errors */
551 addReplyErrorFormat(c,"Invalid argument '%s' for CONFIG SET '%s'",
552 (char*)o->ptr,
553 (char*)c->argv[2]->ptr);
554 }
555
556 void configGetCommand(redisClient *c) {
557 robj *o = c->argv[2];
558 void *replylen = addDeferredMultiBulkLength(c);
559 char *pattern = o->ptr;
560 char buf[128];
561 int matches = 0;
562 redisAssertWithInfo(c,o,o->encoding == REDIS_ENCODING_RAW);
563
564 if (stringmatch(pattern,"dir",0)) {
565 char buf[1024];
566
567 if (getcwd(buf,sizeof(buf)) == NULL)
568 buf[0] = '\0';
569
570 addReplyBulkCString(c,"dir");
571 addReplyBulkCString(c,buf);
572 matches++;
573 }
574 if (stringmatch(pattern,"dbfilename",0)) {
575 addReplyBulkCString(c,"dbfilename");
576 addReplyBulkCString(c,server.rdb_filename);
577 matches++;
578 }
579 if (stringmatch(pattern,"requirepass",0)) {
580 addReplyBulkCString(c,"requirepass");
581 addReplyBulkCString(c,server.requirepass);
582 matches++;
583 }
584 if (stringmatch(pattern,"masterauth",0)) {
585 addReplyBulkCString(c,"masterauth");
586 addReplyBulkCString(c,server.masterauth);
587 matches++;
588 }
589 if (stringmatch(pattern,"maxmemory",0)) {
590 ll2string(buf,sizeof(buf),server.maxmemory);
591 addReplyBulkCString(c,"maxmemory");
592 addReplyBulkCString(c,buf);
593 matches++;
594 }
595 if (stringmatch(pattern,"maxmemory-policy",0)) {
596 char *s;
597
598 switch(server.maxmemory_policy) {
599 case REDIS_MAXMEMORY_VOLATILE_LRU: s = "volatile-lru"; break;
600 case REDIS_MAXMEMORY_VOLATILE_TTL: s = "volatile-ttl"; break;
601 case REDIS_MAXMEMORY_VOLATILE_RANDOM: s = "volatile-random"; break;
602 case REDIS_MAXMEMORY_ALLKEYS_LRU: s = "allkeys-lru"; break;
603 case REDIS_MAXMEMORY_ALLKEYS_RANDOM: s = "allkeys-random"; break;
604 case REDIS_MAXMEMORY_NO_EVICTION: s = "noeviction"; break;
605 default: s = "unknown"; break; /* too harmless to panic */
606 }
607 addReplyBulkCString(c,"maxmemory-policy");
608 addReplyBulkCString(c,s);
609 matches++;
610 }
611 if (stringmatch(pattern,"maxmemory-samples",0)) {
612 ll2string(buf,sizeof(buf),server.maxmemory_samples);
613 addReplyBulkCString(c,"maxmemory-samples");
614 addReplyBulkCString(c,buf);
615 matches++;
616 }
617 if (stringmatch(pattern,"timeout",0)) {
618 ll2string(buf,sizeof(buf),server.maxidletime);
619 addReplyBulkCString(c,"timeout");
620 addReplyBulkCString(c,buf);
621 matches++;
622 }
623 if (stringmatch(pattern,"appendonly",0)) {
624 addReplyBulkCString(c,"appendonly");
625 addReplyBulkCString(c,server.aof_state == REDIS_AOF_OFF ? "no" : "yes");
626 matches++;
627 }
628 if (stringmatch(pattern,"no-appendfsync-on-rewrite",0)) {
629 addReplyBulkCString(c,"no-appendfsync-on-rewrite");
630 addReplyBulkCString(c,server.aof_no_fsync_on_rewrite ? "yes" : "no");
631 matches++;
632 }
633 if (stringmatch(pattern,"appendfsync",0)) {
634 char *policy;
635
636 switch(server.aof_fsync) {
637 case AOF_FSYNC_NO: policy = "no"; break;
638 case AOF_FSYNC_EVERYSEC: policy = "everysec"; break;
639 case AOF_FSYNC_ALWAYS: policy = "always"; break;
640 default: policy = "unknown"; break; /* too harmless to panic */
641 }
642 addReplyBulkCString(c,"appendfsync");
643 addReplyBulkCString(c,policy);
644 matches++;
645 }
646 if (stringmatch(pattern,"save",0)) {
647 sds buf = sdsempty();
648 int j;
649
650 for (j = 0; j < server.saveparamslen; j++) {
651 buf = sdscatprintf(buf,"%ld %d",
652 server.saveparams[j].seconds,
653 server.saveparams[j].changes);
654 if (j != server.saveparamslen-1)
655 buf = sdscatlen(buf," ",1);
656 }
657 addReplyBulkCString(c,"save");
658 addReplyBulkCString(c,buf);
659 sdsfree(buf);
660 matches++;
661 }
662 if (stringmatch(pattern,"auto-aof-rewrite-percentage",0)) {
663 addReplyBulkCString(c,"auto-aof-rewrite-percentage");
664 addReplyBulkLongLong(c,server.aof_rewrite_perc);
665 matches++;
666 }
667 if (stringmatch(pattern,"auto-aof-rewrite-min-size",0)) {
668 addReplyBulkCString(c,"auto-aof-rewrite-min-size");
669 addReplyBulkLongLong(c,server.aof_rewrite_min_size);
670 matches++;
671 }
672 if (stringmatch(pattern,"slave-serve-stale-data",0)) {
673 addReplyBulkCString(c,"slave-serve-stale-data");
674 addReplyBulkCString(c,server.repl_serve_stale_data ? "yes" : "no");
675 matches++;
676 }
677 if (stringmatch(pattern,"hash-max-ziplist-entries",0)) {
678 addReplyBulkCString(c,"hash-max-ziplist-entries");
679 addReplyBulkLongLong(c,server.hash_max_ziplist_entries);
680 matches++;
681 }
682 if (stringmatch(pattern,"hash-max-ziplist-value",0)) {
683 addReplyBulkCString(c,"hash-max-ziplist-value");
684 addReplyBulkLongLong(c,server.hash_max_ziplist_value);
685 matches++;
686 }
687 if (stringmatch(pattern,"list-max-ziplist-entries",0)) {
688 addReplyBulkCString(c,"list-max-ziplist-entries");
689 addReplyBulkLongLong(c,server.list_max_ziplist_entries);
690 matches++;
691 }
692 if (stringmatch(pattern,"list-max-ziplist-value",0)) {
693 addReplyBulkCString(c,"list-max-ziplist-value");
694 addReplyBulkLongLong(c,server.list_max_ziplist_value);
695 matches++;
696 }
697 if (stringmatch(pattern,"set-max-intset-entries",0)) {
698 addReplyBulkCString(c,"set-max-intset-entries");
699 addReplyBulkLongLong(c,server.set_max_intset_entries);
700 matches++;
701 }
702 if (stringmatch(pattern,"zset-max-ziplist-entries",0)) {
703 addReplyBulkCString(c,"zset-max-ziplist-entries");
704 addReplyBulkLongLong(c,server.zset_max_ziplist_entries);
705 matches++;
706 }
707 if (stringmatch(pattern,"zset-max-ziplist-value",0)) {
708 addReplyBulkCString(c,"zset-max-ziplist-value");
709 addReplyBulkLongLong(c,server.zset_max_ziplist_value);
710 matches++;
711 }
712 if (stringmatch(pattern,"lua-time-limit",0)) {
713 addReplyBulkCString(c,"lua-time-limit");
714 addReplyBulkLongLong(c,server.lua_time_limit);
715 matches++;
716 }
717 if (stringmatch(pattern,"slowlog-log-slower-than",0)) {
718 addReplyBulkCString(c,"slowlog-log-slower-than");
719 addReplyBulkLongLong(c,server.slowlog_log_slower_than);
720 matches++;
721 }
722 if (stringmatch(pattern,"slowlog-max-len",0)) {
723 addReplyBulkCString(c,"slowlog-max-len");
724 addReplyBulkLongLong(c,server.slowlog_max_len);
725 matches++;
726 }
727 if (stringmatch(pattern,"loglevel",0)) {
728 char *s;
729
730 switch(server.verbosity) {
731 case REDIS_WARNING: s = "warning"; break;
732 case REDIS_VERBOSE: s = "verbose"; break;
733 case REDIS_NOTICE: s = "notice"; break;
734 case REDIS_DEBUG: s = "debug"; break;
735 default: s = "unknown"; break; /* too harmless to panic */
736 }
737 addReplyBulkCString(c,"loglevel");
738 addReplyBulkCString(c,s);
739 matches++;
740 }
741 setDeferredMultiBulkLength(c,replylen,matches*2);
742 }
743
744 void configCommand(redisClient *c) {
745 if (!strcasecmp(c->argv[1]->ptr,"set")) {
746 if (c->argc != 4) goto badarity;
747 configSetCommand(c);
748 } else if (!strcasecmp(c->argv[1]->ptr,"get")) {
749 if (c->argc != 3) goto badarity;
750 configGetCommand(c);
751 } else if (!strcasecmp(c->argv[1]->ptr,"resetstat")) {
752 if (c->argc != 2) goto badarity;
753 server.stat_keyspace_hits = 0;
754 server.stat_keyspace_misses = 0;
755 server.stat_numcommands = 0;
756 server.stat_numconnections = 0;
757 server.stat_expiredkeys = 0;
758 resetCommandTableStats();
759 addReply(c,shared.ok);
760 } else {
761 addReplyError(c,
762 "CONFIG subcommand must be one of GET, SET, RESETSTAT");
763 }
764 return;
765
766 badarity:
767 addReplyErrorFormat(c,"Wrong number of arguments for CONFIG %s",
768 (char*) c->argv[1]->ptr);
769 }