]> git.saurik.com Git - redis.git/blob - src/config.c
acda67bb74c98870f228f6c290897c53c5f5aca0
[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.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 if ((server.appendonly = yesnotoi(argv[1])) == -1) {
217 err = "argument must be 'yes' or 'no'"; goto loaderr;
218 }
219 } else if (!strcasecmp(argv[0],"appendfilename") && argc == 2) {
220 zfree(server.appendfilename);
221 server.appendfilename = zstrdup(argv[1]);
222 } else if (!strcasecmp(argv[0],"no-appendfsync-on-rewrite")
223 && argc == 2) {
224 if ((server.no_appendfsync_on_rewrite= yesnotoi(argv[1])) == -1) {
225 err = "argument must be 'yes' or 'no'"; goto loaderr;
226 }
227 } else if (!strcasecmp(argv[0],"appendfsync") && argc == 2) {
228 if (!strcasecmp(argv[1],"no")) {
229 server.appendfsync = APPENDFSYNC_NO;
230 } else if (!strcasecmp(argv[1],"always")) {
231 server.appendfsync = APPENDFSYNC_ALWAYS;
232 } else if (!strcasecmp(argv[1],"everysec")) {
233 server.appendfsync = APPENDFSYNC_EVERYSEC;
234 } else {
235 err = "argument must be 'no', 'always' or 'everysec'";
236 goto loaderr;
237 }
238 } else if (!strcasecmp(argv[0],"auto-aof-rewrite-percentage") &&
239 argc == 2)
240 {
241 server.auto_aofrewrite_perc = atoi(argv[1]);
242 if (server.auto_aofrewrite_perc < 0) {
243 err = "Invalid negative percentage for AOF auto rewrite";
244 goto loaderr;
245 }
246 } else if (!strcasecmp(argv[0],"auto-aof-rewrite-min-size") &&
247 argc == 2)
248 {
249 server.auto_aofrewrite_min_size = memtoll(argv[1],NULL);
250 } else if (!strcasecmp(argv[0],"requirepass") && argc == 2) {
251 server.requirepass = zstrdup(argv[1]);
252 } else if (!strcasecmp(argv[0],"pidfile") && argc == 2) {
253 zfree(server.pidfile);
254 server.pidfile = zstrdup(argv[1]);
255 } else if (!strcasecmp(argv[0],"dbfilename") && argc == 2) {
256 zfree(server.dbfilename);
257 server.dbfilename = zstrdup(argv[1]);
258 } else if (!strcasecmp(argv[0],"hash-max-zipmap-entries") && argc == 2) {
259 server.hash_max_zipmap_entries = memtoll(argv[1], NULL);
260 } else if (!strcasecmp(argv[0],"hash-max-zipmap-value") && argc == 2) {
261 server.hash_max_zipmap_value = memtoll(argv[1], NULL);
262 } else if (!strcasecmp(argv[0],"list-max-ziplist-entries") && argc == 2){
263 server.list_max_ziplist_entries = memtoll(argv[1], NULL);
264 } else if (!strcasecmp(argv[0],"list-max-ziplist-value") && argc == 2) {
265 server.list_max_ziplist_value = memtoll(argv[1], NULL);
266 } else if (!strcasecmp(argv[0],"set-max-intset-entries") && argc == 2) {
267 server.set_max_intset_entries = memtoll(argv[1], NULL);
268 } else if (!strcasecmp(argv[0],"zset-max-ziplist-entries") && argc == 2) {
269 server.zset_max_ziplist_entries = memtoll(argv[1], NULL);
270 } else if (!strcasecmp(argv[0],"zset-max-ziplist-value") && argc == 2) {
271 server.zset_max_ziplist_value = memtoll(argv[1], NULL);
272 } else if (!strcasecmp(argv[0],"rename-command") && argc == 3) {
273 struct redisCommand *cmd = lookupCommand(argv[1]);
274 int retval;
275
276 if (!cmd) {
277 err = "No such command in rename-command";
278 goto loaderr;
279 }
280
281 /* If the target command name is the emtpy string we just
282 * remove it from the command table. */
283 retval = dictDelete(server.commands, argv[1]);
284 redisAssert(retval == DICT_OK);
285
286 /* Otherwise we re-add the command under a different name. */
287 if (sdslen(argv[2]) != 0) {
288 sds copy = sdsdup(argv[2]);
289
290 retval = dictAdd(server.commands, copy, cmd);
291 if (retval != DICT_OK) {
292 sdsfree(copy);
293 err = "Target command name already exists"; goto loaderr;
294 }
295 }
296 } else if (!strcasecmp(argv[0],"cluster-enabled") && argc == 2) {
297 if ((server.cluster_enabled = yesnotoi(argv[1])) == -1) {
298 err = "argument must be 'yes' or 'no'"; goto loaderr;
299 }
300 } else if (!strcasecmp(argv[0],"cluster-config-file") && argc == 2) {
301 zfree(server.cluster.configfile);
302 server.cluster.configfile = zstrdup(argv[1]);
303 } else if (!strcasecmp(argv[0],"lua-time-limit") && argc == 2) {
304 server.lua_time_limit = strtoll(argv[1],NULL,10);
305 } else if (!strcasecmp(argv[0],"slowlog-log-slower-than") &&
306 argc == 2)
307 {
308 server.slowlog_log_slower_than = strtoll(argv[1],NULL,10);
309 } else if (!strcasecmp(argv[0],"slowlog-max-len") && argc == 2) {
310 server.slowlog_max_len = strtoll(argv[1],NULL,10);
311 } else {
312 err = "Bad directive or wrong number of arguments"; goto loaderr;
313 }
314 sdsfreesplitres(argv,argc);
315 }
316 sdsfreesplitres(lines,totlines);
317 return;
318
319 loaderr:
320 fprintf(stderr, "\n*** FATAL CONFIG FILE ERROR ***\n");
321 fprintf(stderr, "Reading the configuration file, at line %d\n", linenum);
322 fprintf(stderr, ">>> '%s'\n", lines[i]);
323 fprintf(stderr, "%s\n", err);
324 exit(1);
325 }
326
327 /* Load the server configuration from the specified filename.
328 * The function appends the additional configuration directives stored
329 * in the 'options' string to the config file before loading.
330 *
331 * Both filename and options can be NULL, in such a case are considered
332 * emtpy. This way loadServerConfig can be used to just load a file or
333 * just load a string. */
334 void loadServerConfig(char *filename, char *options) {
335 sds config = sdsempty();
336 char buf[REDIS_CONFIGLINE_MAX+1];
337
338 /* Load the file content */
339 if (filename) {
340 FILE *fp;
341
342 if (filename[0] == '-' && filename[1] == '\0') {
343 fp = stdin;
344 } else {
345 if ((fp = fopen(filename,"r")) == NULL) {
346 redisLog(REDIS_WARNING,
347 "Fatal error, can't open config file '%s'", filename);
348 exit(1);
349 }
350 }
351 while(fgets(buf,REDIS_CONFIGLINE_MAX+1,fp) != NULL)
352 config = sdscat(config,buf);
353 if (fp != stdin) fclose(fp);
354 }
355 /* Append the additional options */
356 if (options) {
357 config = sdscat(config,"\n");
358 config = sdscat(config,options);
359 }
360 loadServerConfigFromString(config);
361 sdsfree(config);
362 }
363
364 /*-----------------------------------------------------------------------------
365 * CONFIG command for remote configuration
366 *----------------------------------------------------------------------------*/
367
368 void configSetCommand(redisClient *c) {
369 robj *o;
370 long long ll;
371 redisAssertWithInfo(c,c->argv[2],c->argv[2]->encoding == REDIS_ENCODING_RAW);
372 redisAssertWithInfo(c,c->argv[2],c->argv[3]->encoding == REDIS_ENCODING_RAW);
373 o = c->argv[3];
374
375 if (!strcasecmp(c->argv[2]->ptr,"dbfilename")) {
376 zfree(server.dbfilename);
377 server.dbfilename = zstrdup(o->ptr);
378 } else if (!strcasecmp(c->argv[2]->ptr,"requirepass")) {
379 zfree(server.requirepass);
380 server.requirepass = ((char*)o->ptr)[0] ? zstrdup(o->ptr) : NULL;
381 } else if (!strcasecmp(c->argv[2]->ptr,"masterauth")) {
382 zfree(server.masterauth);
383 server.masterauth = zstrdup(o->ptr);
384 } else if (!strcasecmp(c->argv[2]->ptr,"maxmemory")) {
385 if (getLongLongFromObject(o,&ll) == REDIS_ERR ||
386 ll < 0) goto badfmt;
387 server.maxmemory = ll;
388 if (server.maxmemory) freeMemoryIfNeeded();
389 } else if (!strcasecmp(c->argv[2]->ptr,"maxmemory-policy")) {
390 if (!strcasecmp(o->ptr,"volatile-lru")) {
391 server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_LRU;
392 } else if (!strcasecmp(o->ptr,"volatile-random")) {
393 server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_RANDOM;
394 } else if (!strcasecmp(o->ptr,"volatile-ttl")) {
395 server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_TTL;
396 } else if (!strcasecmp(o->ptr,"allkeys-lru")) {
397 server.maxmemory_policy = REDIS_MAXMEMORY_ALLKEYS_LRU;
398 } else if (!strcasecmp(o->ptr,"allkeys-random")) {
399 server.maxmemory_policy = REDIS_MAXMEMORY_ALLKEYS_RANDOM;
400 } else if (!strcasecmp(o->ptr,"noeviction")) {
401 server.maxmemory_policy = REDIS_MAXMEMORY_NO_EVICTION;
402 } else {
403 goto badfmt;
404 }
405 } else if (!strcasecmp(c->argv[2]->ptr,"maxmemory-samples")) {
406 if (getLongLongFromObject(o,&ll) == REDIS_ERR ||
407 ll <= 0) goto badfmt;
408 server.maxmemory_samples = ll;
409 } else if (!strcasecmp(c->argv[2]->ptr,"timeout")) {
410 if (getLongLongFromObject(o,&ll) == REDIS_ERR ||
411 ll < 0 || ll > LONG_MAX) goto badfmt;
412 server.maxidletime = ll;
413 } else if (!strcasecmp(c->argv[2]->ptr,"appendfsync")) {
414 if (!strcasecmp(o->ptr,"no")) {
415 server.appendfsync = APPENDFSYNC_NO;
416 } else if (!strcasecmp(o->ptr,"everysec")) {
417 server.appendfsync = APPENDFSYNC_EVERYSEC;
418 } else if (!strcasecmp(o->ptr,"always")) {
419 server.appendfsync = APPENDFSYNC_ALWAYS;
420 } else {
421 goto badfmt;
422 }
423 } else if (!strcasecmp(c->argv[2]->ptr,"no-appendfsync-on-rewrite")) {
424 int yn = yesnotoi(o->ptr);
425
426 if (yn == -1) goto badfmt;
427 server.no_appendfsync_on_rewrite = yn;
428 } else if (!strcasecmp(c->argv[2]->ptr,"appendonly")) {
429 int old = server.appendonly;
430 int new = yesnotoi(o->ptr);
431
432 if (new == -1) goto badfmt;
433 if (old != new) {
434 if (new == 0) {
435 stopAppendOnly();
436 } else {
437 if (startAppendOnly() == REDIS_ERR) {
438 addReplyError(c,
439 "Unable to turn on AOF. Check server logs.");
440 return;
441 }
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
544 badfmt: /* 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
550 void 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.appendonly ? "yes" : "no");
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
738 void 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
760 badarity:
761 addReplyErrorFormat(c,"Wrong number of arguments for CONFIG %s",
762 (char*) c->argv[1]->ptr);
763 }