LCOV - code coverage report
Current view: directory - redis/src - config.c (source / functions) Found Hit Coverage
Test: redis.info Lines: 590 215 36.4 %
Date: 2012-04-04 Functions: 8 7 87.5 %
Colors: not hit hit

       1                 : #include "redis.h"
       2                 : 
       3                 : /*-----------------------------------------------------------------------------
       4                 :  * Config file parsing
       5                 :  *----------------------------------------------------------------------------*/
       6                 : 
       7             320 : int yesnotoi(char *s) {
       8             320 :     if (!strcasecmp(s,"yes")) return 1;
       9             154 :     else if (!strcasecmp(s,"no")) return 0;
      10               0 :     else return -1;
      11                 : }
      12                 : 
      13             212 : void appendServerSaveParams(time_t seconds, int changes) {
      14             212 :     server.saveparams = zrealloc(server.saveparams,sizeof(struct saveparam)*(server.saveparamslen+1));
      15             212 :     server.saveparams[server.saveparamslen].seconds = seconds;
      16             212 :     server.saveparams[server.saveparamslen].changes = changes;
      17             212 :     server.saveparamslen++;
      18             212 : }
      19                 : 
      20             106 : void resetServerSaveParams() {
      21             106 :     zfree(server.saveparams);
      22             106 :     server.saveparams = NULL;
      23             106 :     server.saveparamslen = 0;
      24             106 : }
      25                 : 
      26              53 : void loadServerConfigFromString(char *config) {
      27              53 :     char *err = NULL;
      28              53 :     int linenum = 0, totlines, i;
      29                 :     sds *lines;
      30                 : 
      31              53 :     lines = sdssplitlen(config,strlen(config),"\n",1,&totlines);
      32                 : 
      33            1280 :     for (i = 0; i < totlines; i++) {
      34                 :         sds *argv;
      35                 :         int argc;
      36                 : 
      37            1227 :         linenum = i+1;
      38            1227 :         lines[i] = sdstrim(lines[i]," \t\r\n");
      39                 : 
      40                 :         /* Skip comments and blank lines*/
      41            1227 :         if (lines[i][0] == '#' || lines[i][0] == '\0') continue;
      42                 : 
      43                 :         /* Split into arguments */
      44            1121 :         argv = sdssplitargs(lines[i],&argc);
      45            1121 :         sdstolower(argv[0]);
      46                 : 
      47                 :         /* Execute config directives */
      48            1121 :         if (!strcasecmp(argv[0],"timeout") && argc == 2) {
      49             106 :             server.maxidletime = atoi(argv[1]);
      50              53 :             if (server.maxidletime < 0) {
      51               0 :                 err = "Invalid timeout value"; goto loaderr;
      52                 :             }
      53            1068 :         } else if (!strcasecmp(argv[0],"port") && argc == 2) {
      54             106 :             server.port = atoi(argv[1]);
      55              53 :             if (server.port < 0 || server.port > 65535) {
      56               0 :                 err = "Invalid port"; goto loaderr;
      57                 :             }
      58            1015 :         } else if (!strcasecmp(argv[0],"bind") && argc == 2) {
      59               0 :             server.bindaddr = zstrdup(argv[1]);
      60            1015 :         } else if (!strcasecmp(argv[0],"unixsocket") && argc == 2) {
      61               0 :             server.unixsocket = zstrdup(argv[1]);
      62            1015 :         } else if (!strcasecmp(argv[0],"unixsocketperm") && argc == 2) {
      63               0 :             errno = 0;
      64               0 :             server.unixsocketperm = (mode_t)strtol(argv[1], NULL, 8);
      65               0 :             if (errno || server.unixsocketperm > 0777) {
      66               0 :                 err = "Invalid socket file permissions"; goto loaderr;
      67                 :             }
      68            1015 :         } else if (!strcasecmp(argv[0],"save")) {
      69              53 :             if (argc == 3) {
      70              53 :                 int seconds = atoi(argv[1]);
      71              53 :                 int changes = atoi(argv[2]);
      72              53 :                 if (seconds < 1 || changes < 0) {
      73               0 :                     err = "Invalid save parameters"; goto loaderr;
      74                 :                 }
      75              53 :                 appendServerSaveParams(seconds,changes);
      76               0 :             } else if (argc == 2 && !strcasecmp(argv[1],"")) {
      77               0 :                 resetServerSaveParams();
      78                 :             }
      79             962 :         } else if (!strcasecmp(argv[0],"dir") && argc == 2) {
      80              53 :             if (chdir(argv[1]) == -1) {
      81               0 :                 redisLog(REDIS_WARNING,"Can't chdir to '%s': %s",
      82               0 :                     argv[1], strerror(errno));
      83               0 :                 exit(1);
      84                 :             }
      85             909 :         } else if (!strcasecmp(argv[0],"loglevel") && argc == 2) {
      86              53 :             if (!strcasecmp(argv[1],"debug")) server.verbosity = REDIS_DEBUG;
      87              53 :             else if (!strcasecmp(argv[1],"verbose")) server.verbosity = REDIS_VERBOSE;
      88               0 :             else if (!strcasecmp(argv[1],"notice")) server.verbosity = REDIS_NOTICE;
      89               0 :             else if (!strcasecmp(argv[1],"warning")) server.verbosity = REDIS_WARNING;
      90                 :             else {
      91               0 :                 err = "Invalid log level. Must be one of debug, notice, warning";
      92               0 :                 goto loaderr;
      93                 :             }
      94             856 :         } else if (!strcasecmp(argv[0],"logfile") && argc == 2) {
      95                 :             FILE *logfp;
      96                 : 
      97              53 :             server.logfile = zstrdup(argv[1]);
      98              53 :             if (!strcasecmp(server.logfile,"stdout")) {
      99              53 :                 zfree(server.logfile);
     100              53 :                 server.logfile = NULL;
     101                 :             }
     102              53 :             if (server.logfile) {
     103                 :                 /* Test if we are able to open the file. The server will not
     104                 :                  * be able to abort just for this problem later... */
     105               0 :                 logfp = fopen(server.logfile,"a");
     106               0 :                 if (logfp == NULL) {
     107               0 :                     err = sdscatprintf(sdsempty(),
     108                 :                         "Can't open the log file: %s", strerror(errno));
     109               0 :                     goto loaderr;
     110                 :                 }
     111               0 :                 fclose(logfp);
     112                 :             }
     113             803 :         } else if (!strcasecmp(argv[0],"syslog-enabled") && argc == 2) {
     114               0 :             if ((server.syslog_enabled = yesnotoi(argv[1])) == -1) {
     115               0 :                 err = "argument must be 'yes' or 'no'"; goto loaderr;
     116                 :             }
     117             803 :         } else if (!strcasecmp(argv[0],"syslog-ident") && argc == 2) {
     118               0 :             if (server.syslog_ident) zfree(server.syslog_ident);
     119               0 :             server.syslog_ident = zstrdup(argv[1]);
     120             803 :         } else if (!strcasecmp(argv[0],"syslog-facility") && argc == 2) {
     121                 :             struct {
     122                 :                 const char     *name;
     123                 :                 const int       value;
     124                 :             } validSyslogFacilities[] = {
     125                 :                 {"user",    LOG_USER},
     126                 :                 {"local0",  LOG_LOCAL0},
     127                 :                 {"local1",  LOG_LOCAL1},
     128                 :                 {"local2",  LOG_LOCAL2},
     129                 :                 {"local3",  LOG_LOCAL3},
     130                 :                 {"local4",  LOG_LOCAL4},
     131                 :                 {"local5",  LOG_LOCAL5},
     132                 :                 {"local6",  LOG_LOCAL6},
     133                 :                 {"local7",  LOG_LOCAL7},
     134                 :                 {NULL, 0}
     135               0 :             };
     136                 :             int i;
     137                 : 
     138               0 :             for (i = 0; validSyslogFacilities[i].name; i++) {
     139               0 :                 if (!strcasecmp(validSyslogFacilities[i].name, argv[1])) {
     140               0 :                     server.syslog_facility = validSyslogFacilities[i].value;
     141               0 :                     break;
     142                 :                 }
     143                 :             }
     144                 : 
     145               0 :             if (!validSyslogFacilities[i].name) {
     146               0 :                 err = "Invalid log facility. Must be one of USER or between LOCAL0-LOCAL7";
     147               0 :                 goto loaderr;
     148                 :             }
     149             803 :         } else if (!strcasecmp(argv[0],"databases") && argc == 2) {
     150             106 :             server.dbnum = atoi(argv[1]);
     151              53 :             if (server.dbnum < 1) {
     152               0 :                 err = "Invalid number of databases"; goto loaderr;
     153                 :             }
     154             750 :         } else if (!strcasecmp(argv[0],"include") && argc == 2) {
     155               0 :             loadServerConfig(argv[1],NULL);
     156             750 :         } else if (!strcasecmp(argv[0],"maxclients") && argc == 2) {
     157               0 :             server.maxclients = atoi(argv[1]);
     158             750 :         } else if (!strcasecmp(argv[0],"maxmemory") && argc == 2) {
     159               0 :             server.maxmemory = memtoll(argv[1],NULL);
     160             750 :         } else if (!strcasecmp(argv[0],"maxmemory-policy") && argc == 2) {
     161               0 :             if (!strcasecmp(argv[1],"volatile-lru")) {
     162               0 :                 server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_LRU;
     163               0 :             } else if (!strcasecmp(argv[1],"volatile-random")) {
     164               0 :                 server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_RANDOM;
     165               0 :             } else if (!strcasecmp(argv[1],"volatile-ttl")) {
     166               0 :                 server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_TTL;
     167               0 :             } else if (!strcasecmp(argv[1],"allkeys-lru")) {
     168               0 :                 server.maxmemory_policy = REDIS_MAXMEMORY_ALLKEYS_LRU;
     169               0 :             } else if (!strcasecmp(argv[1],"allkeys-random")) {
     170               0 :                 server.maxmemory_policy = REDIS_MAXMEMORY_ALLKEYS_RANDOM;
     171               0 :             } else if (!strcasecmp(argv[1],"noeviction")) {
     172               0 :                 server.maxmemory_policy = REDIS_MAXMEMORY_NO_EVICTION;
     173                 :             } else {
     174               0 :                 err = "Invalid maxmemory policy";
     175               0 :                 goto loaderr;
     176                 :             }
     177             750 :         } else if (!strcasecmp(argv[0],"maxmemory-samples") && argc == 2) {
     178               0 :             server.maxmemory_samples = atoi(argv[1]);
     179               0 :             if (server.maxmemory_samples <= 0) {
     180               0 :                 err = "maxmemory-samples must be 1 or greater";
     181               0 :                 goto loaderr;
     182                 :             }
     183             750 :         } else if (!strcasecmp(argv[0],"slaveof") && argc == 3) {
     184               0 :             server.masterhost = sdsnew(argv[1]);
     185               0 :             server.masterport = atoi(argv[2]);
     186               0 :             server.repl_state = REDIS_REPL_CONNECT;
     187             750 :         } else if (!strcasecmp(argv[0],"repl-ping-slave-period") && argc == 2) {
     188               0 :             server.repl_ping_slave_period = atoi(argv[1]);
     189               0 :             if (server.repl_ping_slave_period <= 0) {
     190               0 :                 err = "repl-ping-slave-period must be 1 or greater";
     191               0 :                 goto loaderr;
     192                 :             }
     193             750 :         } else if (!strcasecmp(argv[0],"repl-timeout") && argc == 2) {
     194               0 :             server.repl_timeout = atoi(argv[1]);
     195               0 :             if (server.repl_timeout <= 0) {
     196               0 :                 err = "repl-timeout must be 1 or greater";
     197               0 :                 goto loaderr;
     198                 :             }
     199             750 :         } else if (!strcasecmp(argv[0],"masterauth") && argc == 2) {
     200               0 :                 server.masterauth = zstrdup(argv[1]);
     201             750 :         } else if (!strcasecmp(argv[0],"slave-serve-stale-data") && argc == 2) {
     202              53 :             if ((server.repl_serve_stale_data = yesnotoi(argv[1])) == -1) {
     203               0 :                 err = "argument must be 'yes' or 'no'"; goto loaderr;
     204                 :             }
     205             697 :         } else if (!strcasecmp(argv[0],"slave-read-only") && argc == 2) {
     206               0 :             if ((server.repl_slave_ro = yesnotoi(argv[1])) == -1) {
     207               0 :                 err = "argument must be 'yes' or 'no'"; goto loaderr;
     208                 :             }
     209             697 :         } else if (!strcasecmp(argv[0],"rdbcompression") && argc == 2) {
     210              53 :             if ((server.rdb_compression = yesnotoi(argv[1])) == -1) {
     211               0 :                 err = "argument must be 'yes' or 'no'"; goto loaderr;
     212                 :             }
     213             644 :         } else if (!strcasecmp(argv[0],"activerehashing") && argc == 2) {
     214              53 :             if ((server.activerehashing = yesnotoi(argv[1])) == -1) {
     215               0 :                 err = "argument must be 'yes' or 'no'"; goto loaderr;
     216                 :             }
     217             591 :         } else if (!strcasecmp(argv[0],"daemonize") && argc == 2) {
     218              53 :             if ((server.daemonize = yesnotoi(argv[1])) == -1) {
     219               0 :                 err = "argument must be 'yes' or 'no'"; goto loaderr;
     220                 :             }
     221             591 :         } else if (!strcasecmp(argv[0],"appendonly") && argc == 2) {
     222                 :             int yes;
     223                 : 
     224              53 :             if ((yes = yesnotoi(argv[1])) == -1) {
     225               0 :                 err = "argument must be 'yes' or 'no'"; goto loaderr;
     226                 :             }
     227              53 :             server.aof_state = yes ? REDIS_AOF_ON : REDIS_AOF_OFF;
     228             491 :         } else if (!strcasecmp(argv[0],"appendfilename") && argc == 2) {
     229               6 :             zfree(server.aof_filename);
     230               6 :             server.aof_filename = zstrdup(argv[1]);
     231             532 :         } else if (!strcasecmp(argv[0],"no-appendfsync-on-rewrite")
     232              53 :                    && argc == 2) {
     233              53 :             if ((server.aof_no_fsync_on_rewrite= yesnotoi(argv[1])) == -1) {
     234               0 :                 err = "argument must be 'yes' or 'no'"; goto loaderr;
     235                 :             }
     236             426 :         } else if (!strcasecmp(argv[0],"appendfsync") && argc == 2) {
     237              53 :             if (!strcasecmp(argv[1],"no")) {
     238               0 :                 server.aof_fsync = AOF_FSYNC_NO;
     239              53 :             } else if (!strcasecmp(argv[1],"always")) {
     240               0 :                 server.aof_fsync = AOF_FSYNC_ALWAYS;
     241              53 :             } else if (!strcasecmp(argv[1],"everysec")) {
     242              53 :                 server.aof_fsync = AOF_FSYNC_EVERYSEC;
     243                 :             } else {
     244               0 :                 err = "argument must be 'no', 'always' or 'everysec'";
     245               0 :                 goto loaderr;
     246                 :             }
     247             373 :         } else if (!strcasecmp(argv[0],"auto-aof-rewrite-percentage") &&
     248               0 :                    argc == 2)
     249                 :         {
     250               0 :             server.aof_rewrite_perc = atoi(argv[1]);
     251               0 :             if (server.aof_rewrite_perc < 0) {
     252               0 :                 err = "Invalid negative percentage for AOF auto rewrite";
     253               0 :                 goto loaderr;
     254                 :             }
     255             373 :         } else if (!strcasecmp(argv[0],"auto-aof-rewrite-min-size") &&
     256               0 :                    argc == 2)
     257                 :         {
     258               0 :             server.aof_rewrite_min_size = memtoll(argv[1],NULL);
     259             374 :         } else if (!strcasecmp(argv[0],"requirepass") && argc == 2) {
     260               1 :             server.requirepass = zstrdup(argv[1]);
     261             425 :         } else if (!strcasecmp(argv[0],"pidfile") && argc == 2) {
     262              53 :             zfree(server.pidfile);
     263              53 :             server.pidfile = zstrdup(argv[1]);
     264             372 :         } else if (!strcasecmp(argv[0],"dbfilename") && argc == 2) {
     265              53 :             zfree(server.rdb_filename);
     266              53 :             server.rdb_filename = zstrdup(argv[1]);
     267             319 :         } else if (!strcasecmp(argv[0],"hash-max-ziplist-entries") && argc == 2) {
     268              53 :             server.hash_max_ziplist_entries = memtoll(argv[1], NULL);
     269             266 :         } else if (!strcasecmp(argv[0],"hash-max-ziplist-value") && argc == 2) {
     270              53 :             server.hash_max_ziplist_value = memtoll(argv[1], NULL);
     271             213 :         } else if (!strcasecmp(argv[0],"list-max-ziplist-entries") && argc == 2){
     272              53 :             server.list_max_ziplist_entries = memtoll(argv[1], NULL);
     273             160 :         } else if (!strcasecmp(argv[0],"list-max-ziplist-value") && argc == 2) {
     274              53 :             server.list_max_ziplist_value = memtoll(argv[1], NULL);
     275             107 :         } else if (!strcasecmp(argv[0],"set-max-intset-entries") && argc == 2) {
     276              53 :             server.set_max_intset_entries = memtoll(argv[1], NULL);
     277               1 :         } else if (!strcasecmp(argv[0],"zset-max-ziplist-entries") && argc == 2) {
     278               0 :             server.zset_max_ziplist_entries = memtoll(argv[1], NULL);
     279               1 :         } else if (!strcasecmp(argv[0],"zset-max-ziplist-value") && argc == 2) {
     280               0 :             server.zset_max_ziplist_value = memtoll(argv[1], NULL);
     281               1 :         } else if (!strcasecmp(argv[0],"rename-command") && argc == 3) {
     282               0 :             struct redisCommand *cmd = lookupCommand(argv[1]);
     283                 :             int retval;
     284                 : 
     285               0 :             if (!cmd) {
     286               0 :                 err = "No such command in rename-command";
     287               0 :                 goto loaderr;
     288                 :             }
     289                 : 
     290                 :             /* If the target command name is the emtpy string we just
     291                 :              * remove it from the command table. */
     292               0 :             retval = dictDelete(server.commands, argv[1]);
     293               0 :             redisAssert(retval == DICT_OK);
     294                 : 
     295                 :             /* Otherwise we re-add the command under a different name. */
     296               0 :             if (sdslen(argv[2]) != 0) {
     297               0 :                 sds copy = sdsdup(argv[2]);
     298                 : 
     299               0 :                 retval = dictAdd(server.commands, copy, cmd);
     300               0 :                 if (retval != DICT_OK) {
     301               0 :                     sdsfree(copy);
     302               0 :                     err = "Target command name already exists"; goto loaderr;
     303                 :                 }
     304                 :             }
     305               1 :         } else if (!strcasecmp(argv[0],"cluster-enabled") && argc == 2) {
     306               0 :             if ((server.cluster_enabled = yesnotoi(argv[1])) == -1) {
     307               0 :                 err = "argument must be 'yes' or 'no'"; goto loaderr;
     308                 :             }
     309               1 :         } else if (!strcasecmp(argv[0],"cluster-config-file") && argc == 2) {
     310               0 :             zfree(server.cluster.configfile);
     311               0 :             server.cluster.configfile = zstrdup(argv[1]);
     312               1 :         } else if (!strcasecmp(argv[0],"lua-time-limit") && argc == 2) {
     313               0 :             server.lua_time_limit = strtoll(argv[1],NULL,10);
     314               3 :         } else if (!strcasecmp(argv[0],"slowlog-log-slower-than") &&
     315               1 :                    argc == 2)
     316                 :         {
     317               1 :             server.slowlog_log_slower_than = strtoll(argv[1],NULL,10);
     318               0 :         } else if (!strcasecmp(argv[0],"slowlog-max-len") && argc == 2) {
     319               0 :             server.slowlog_max_len = strtoll(argv[1],NULL,10);
     320               0 :         } else if (!strcasecmp(argv[0],"client-output-buffer-limit") &&
     321               0 :                    argc == 5)
     322                 :         {
     323               0 :             int class = getClientLimitClassByName(argv[1]);
     324                 :             unsigned long long hard, soft;
     325                 :             int soft_seconds;
     326                 : 
     327               0 :             if (class == -1) {
     328               0 :                 err = "Unrecognized client limit class";
     329               0 :                 goto loaderr;
     330                 :             }
     331               0 :             hard = memtoll(argv[2],NULL);
     332               0 :             soft = memtoll(argv[3],NULL);
     333               0 :             soft_seconds = atoi(argv[4]);
     334               0 :             if (soft_seconds < 0) {
     335               0 :                 err = "Negative number of seconds in soft limt is invalid";
     336               0 :                 goto loaderr;
     337                 :             }
     338               0 :             server.client_obuf_limits[class].hard_limit_bytes = hard;
     339               0 :             server.client_obuf_limits[class].soft_limit_bytes = soft;
     340               0 :             server.client_obuf_limits[class].soft_limit_seconds = soft_seconds;
     341               0 :         } else if (!strcasecmp(argv[0],"stop-writes-on-bgsave-error") &&
     342               0 :                    argc == 2) {
     343               0 :             if ((server.stop_writes_on_bgsave_err = yesnotoi(argv[1])) == -1) {
     344               0 :                 err = "argument must be 'yes' or 'no'"; goto loaderr;
     345                 :             }
     346                 :         } else {
     347               0 :             err = "Bad directive or wrong number of arguments"; goto loaderr;
     348                 :         }
     349            1121 :         sdsfreesplitres(argv,argc);
     350                 :     }
     351              53 :     sdsfreesplitres(lines,totlines);
     352                 :     return;
     353                 : 
     354                 : loaderr:
     355               0 :     fprintf(stderr, "\n*** FATAL CONFIG FILE ERROR ***\n");
     356               0 :     fprintf(stderr, "Reading the configuration file, at line %d\n", linenum);
     357               0 :     fprintf(stderr, ">>> '%s'\n", lines[i]);
     358               0 :     fprintf(stderr, "%s\n", err);
     359               0 :     exit(1);
     360                 : }
     361                 : 
     362                 : /* Load the server configuration from the specified filename.
     363                 :  * The function appends the additional configuration directives stored
     364                 :  * in the 'options' string to the config file before loading.
     365                 :  *
     366                 :  * Both filename and options can be NULL, in such a case are considered
     367                 :  * emtpy. This way loadServerConfig can be used to just load a file or
     368                 :  * just load a string. */
     369              53 : void loadServerConfig(char *filename, char *options) {
     370              53 :     sds config = sdsempty();
     371                 :     char buf[REDIS_CONFIGLINE_MAX+1];
     372                 : 
     373                 :     /* Load the file content */
     374              53 :     if (filename) {
     375                 :         FILE *fp;
     376                 : 
     377              53 :         if (filename[0] == '-' && filename[1] == '\0') {
     378               0 :             fp = stdin;
     379                 :         } else {
     380              53 :             if ((fp = fopen(filename,"r")) == NULL) {
     381               0 :                 redisLog(REDIS_WARNING,
     382                 :                     "Fatal error, can't open config file '%s'", filename);
     383               0 :                 exit(1);
     384                 :             }
     385                 :         }
     386            1174 :         while(fgets(buf,REDIS_CONFIGLINE_MAX+1,fp) != NULL)
     387            1121 :             config = sdscat(config,buf);
     388              53 :         if (fp != stdin) fclose(fp);
     389                 :     }
     390                 :     /* Append the additional options */
     391              53 :     if (options) {
     392              53 :         config = sdscat(config,"\n");
     393              53 :         config = sdscat(config,options);
     394                 :     }
     395              53 :     loadServerConfigFromString(config);
     396              53 :     sdsfree(config);
     397              53 : }
     398                 : 
     399                 : /*-----------------------------------------------------------------------------
     400                 :  * CONFIG command for remote configuration
     401                 :  *----------------------------------------------------------------------------*/
     402                 : 
     403              43 : void configSetCommand(redisClient *c) {
     404                 :     robj *o;
     405                 :     long long ll;
     406              43 :     redisAssertWithInfo(c,c->argv[2],c->argv[2]->encoding == REDIS_ENCODING_RAW);
     407              43 :     redisAssertWithInfo(c,c->argv[2],c->argv[3]->encoding == REDIS_ENCODING_RAW);
     408              43 :     o = c->argv[3];
     409                 : 
     410              43 :     if (!strcasecmp(c->argv[2]->ptr,"dbfilename")) {
     411               0 :         zfree(server.rdb_filename);
     412               0 :         server.rdb_filename = zstrdup(o->ptr);
     413              43 :     } else if (!strcasecmp(c->argv[2]->ptr,"requirepass")) {
     414               0 :         zfree(server.requirepass);
     415               0 :         server.requirepass = ((char*)o->ptr)[0] ? zstrdup(o->ptr) : NULL;
     416              43 :     } else if (!strcasecmp(c->argv[2]->ptr,"masterauth")) {
     417               0 :         zfree(server.masterauth);
     418               0 :         server.masterauth = zstrdup(o->ptr);
     419              43 :     } else if (!strcasecmp(c->argv[2]->ptr,"maxmemory")) {
     420              26 :         if (getLongLongFromObject(o,&ll) == REDIS_ERR ||
     421              13 :             ll < 0) goto badfmt;
     422              13 :         server.maxmemory = ll;
     423              13 :         if (server.maxmemory) freeMemoryIfNeeded();
     424              30 :     } else if (!strcasecmp(c->argv[2]->ptr,"maxmemory-policy")) {
     425              13 :         if (!strcasecmp(o->ptr,"volatile-lru")) {
     426               3 :             server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_LRU;
     427              10 :         } else if (!strcasecmp(o->ptr,"volatile-random")) {
     428               3 :             server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_RANDOM;
     429               7 :         } else if (!strcasecmp(o->ptr,"volatile-ttl")) {
     430               3 :             server.maxmemory_policy = REDIS_MAXMEMORY_VOLATILE_TTL;
     431               4 :         } else if (!strcasecmp(o->ptr,"allkeys-lru")) {
     432               2 :             server.maxmemory_policy = REDIS_MAXMEMORY_ALLKEYS_LRU;
     433               2 :         } else if (!strcasecmp(o->ptr,"allkeys-random")) {
     434               2 :             server.maxmemory_policy = REDIS_MAXMEMORY_ALLKEYS_RANDOM;
     435               0 :         } else if (!strcasecmp(o->ptr,"noeviction")) {
     436               0 :             server.maxmemory_policy = REDIS_MAXMEMORY_NO_EVICTION;
     437                 :         } else {
     438                 :             goto badfmt;
     439                 :         }
     440              17 :     } else if (!strcasecmp(c->argv[2]->ptr,"maxmemory-samples")) {
     441               0 :         if (getLongLongFromObject(o,&ll) == REDIS_ERR ||
     442               0 :             ll <= 0) goto badfmt;
     443               0 :         server.maxmemory_samples = ll;
     444              17 :     } else if (!strcasecmp(c->argv[2]->ptr,"timeout")) {
     445               0 :         if (getLongLongFromObject(o,&ll) == REDIS_ERR ||
     446               0 :             ll < 0 || ll > LONG_MAX) goto badfmt;
     447               0 :         server.maxidletime = ll;
     448              17 :     } else if (!strcasecmp(c->argv[2]->ptr,"appendfsync")) {
     449               0 :         if (!strcasecmp(o->ptr,"no")) {
     450               0 :             server.aof_fsync = AOF_FSYNC_NO;
     451               0 :         } else if (!strcasecmp(o->ptr,"everysec")) {
     452               0 :             server.aof_fsync = AOF_FSYNC_EVERYSEC;
     453               0 :         } else if (!strcasecmp(o->ptr,"always")) {
     454               0 :             server.aof_fsync = AOF_FSYNC_ALWAYS;
     455                 :         } else {
     456                 :             goto badfmt;
     457                 :         }
     458              17 :     } else if (!strcasecmp(c->argv[2]->ptr,"no-appendfsync-on-rewrite")) {
     459               0 :         int yn = yesnotoi(o->ptr);
     460                 : 
     461               0 :         if (yn == -1) goto badfmt;
     462               0 :         server.aof_no_fsync_on_rewrite = yn;
     463              17 :     } else if (!strcasecmp(c->argv[2]->ptr,"appendonly")) {
     464               2 :         int enable = yesnotoi(o->ptr);
     465                 : 
     466               2 :         if (enable == -1) goto badfmt;
     467               3 :         if (enable == 0 && server.aof_state != REDIS_AOF_OFF) {
     468               1 :             stopAppendOnly();
     469               1 :         } else if (enable && server.aof_state == REDIS_AOF_OFF) {
     470               1 :             if (startAppendOnly() == REDIS_ERR) {
     471               0 :                 addReplyError(c,
     472                 :                     "Unable to turn on AOF. Check server logs.");
     473               0 :                 return;
     474                 :             }
     475                 :         }
     476              15 :     } else if (!strcasecmp(c->argv[2]->ptr,"auto-aof-rewrite-percentage")) {
     477               0 :         if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
     478               0 :         server.aof_rewrite_perc = ll;
     479              15 :     } else if (!strcasecmp(c->argv[2]->ptr,"auto-aof-rewrite-min-size")) {
     480               0 :         if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
     481               0 :         server.aof_rewrite_min_size = ll;
     482              15 :     } else if (!strcasecmp(c->argv[2]->ptr,"save")) {
     483                 :         int vlen, j;
     484               0 :         sds *v = sdssplitlen(o->ptr,sdslen(o->ptr)," ",1,&vlen);
     485                 : 
     486                 :         /* Perform sanity check before setting the new config:
     487                 :          * - Even number of args
     488                 :          * - Seconds >= 1, changes >= 0 */
     489               0 :         if (vlen & 1) {
     490               0 :             sdsfreesplitres(v,vlen);
     491               0 :             goto badfmt;
     492                 :         }
     493               0 :         for (j = 0; j < vlen; j++) {
     494                 :             char *eptr;
     495                 :             long val;
     496                 : 
     497               0 :             val = strtoll(v[j], &eptr, 10);
     498               0 :             if (eptr[0] != '\0' ||
     499               0 :                 ((j & 1) == 0 && val < 1) ||
     500               0 :                 ((j & 1) == 1 && val < 0)) {
     501               0 :                 sdsfreesplitres(v,vlen);
     502               0 :                 goto badfmt;
     503                 :             }
     504                 :         }
     505                 :         /* Finally set the new config */
     506               0 :         resetServerSaveParams();
     507               0 :         for (j = 0; j < vlen; j += 2) {
     508                 :             time_t seconds;
     509                 :             int changes;
     510                 : 
     511               0 :             seconds = strtoll(v[j],NULL,10);
     512               0 :             changes = strtoll(v[j+1],NULL,10);
     513               0 :             appendServerSaveParams(seconds, changes);
     514                 :         }
     515               0 :         sdsfreesplitres(v,vlen);
     516              15 :     } else if (!strcasecmp(c->argv[2]->ptr,"slave-serve-stale-data")) {
     517               0 :         int yn = yesnotoi(o->ptr);
     518                 : 
     519               0 :         if (yn == -1) goto badfmt;
     520               0 :         server.repl_serve_stale_data = yn;
     521              15 :     } else if (!strcasecmp(c->argv[2]->ptr,"slave-read-only")) {
     522               0 :         int yn = yesnotoi(o->ptr);
     523                 : 
     524               0 :         if (yn == -1) goto badfmt;
     525               0 :         server.repl_slave_ro = yn;
     526              15 :     } else if (!strcasecmp(c->argv[2]->ptr,"dir")) {
     527               0 :         if (chdir((char*)o->ptr) == -1) {
     528               0 :             addReplyErrorFormat(c,"Changing directory: %s", strerror(errno));
     529               0 :             return;
     530                 :         }
     531              15 :     } else if (!strcasecmp(c->argv[2]->ptr,"hash-max-ziplist-entries")) {
     532               0 :         if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
     533               0 :         server.hash_max_ziplist_entries = ll;
     534              15 :     } else if (!strcasecmp(c->argv[2]->ptr,"hash-max-ziplist-value")) {
     535               0 :         if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
     536               0 :         server.hash_max_ziplist_value = ll;
     537              15 :     } else if (!strcasecmp(c->argv[2]->ptr,"list-max-ziplist-entries")) {
     538               0 :         if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
     539               0 :         server.list_max_ziplist_entries = ll;
     540              15 :     } else if (!strcasecmp(c->argv[2]->ptr,"list-max-ziplist-value")) {
     541               0 :         if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
     542               0 :         server.list_max_ziplist_value = ll;
     543              15 :     } else if (!strcasecmp(c->argv[2]->ptr,"set-max-intset-entries")) {
     544               0 :         if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
     545               0 :         server.set_max_intset_entries = ll;
     546              15 :     } else if (!strcasecmp(c->argv[2]->ptr,"zset-max-ziplist-entries")) {
     547               4 :         if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
     548               4 :         server.zset_max_ziplist_entries = ll;
     549              11 :     } else if (!strcasecmp(c->argv[2]->ptr,"zset-max-ziplist-value")) {
     550               4 :         if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
     551               4 :         server.zset_max_ziplist_value = ll;
     552               7 :     } else if (!strcasecmp(c->argv[2]->ptr,"lua-time-limit")) {
     553               0 :         if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
     554               0 :         server.lua_time_limit = ll;
     555               7 :     } else if (!strcasecmp(c->argv[2]->ptr,"slowlog-log-slower-than")) {
     556               3 :         if (getLongLongFromObject(o,&ll) == REDIS_ERR) goto badfmt;
     557               3 :         server.slowlog_log_slower_than = ll;
     558               4 :     } else if (!strcasecmp(c->argv[2]->ptr,"slowlog-max-len")) {
     559               1 :         if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
     560               1 :         server.slowlog_max_len = (unsigned)ll;
     561               3 :     } else if (!strcasecmp(c->argv[2]->ptr,"loglevel")) {
     562               0 :         if (!strcasecmp(o->ptr,"warning")) {
     563               0 :             server.verbosity = REDIS_WARNING;
     564               0 :         } else if (!strcasecmp(o->ptr,"notice")) {
     565               0 :             server.verbosity = REDIS_NOTICE;
     566               0 :         } else if (!strcasecmp(o->ptr,"verbose")) {
     567               0 :             server.verbosity = REDIS_VERBOSE;
     568               0 :         } else if (!strcasecmp(o->ptr,"debug")) {
     569               0 :             server.verbosity = REDIS_DEBUG;
     570                 :         } else {
     571                 :             goto badfmt;
     572                 :         }
     573               3 :     } else if (!strcasecmp(c->argv[2]->ptr,"client-output-buffer-limit")) {
     574                 :         int vlen, j;
     575               6 :         sds *v = sdssplitlen(o->ptr,sdslen(o->ptr)," ",1,&vlen);
     576                 : 
     577                 :         /* We need a multiple of 4: <class> <hard> <soft> <soft_seconds> */
     578               3 :         if (vlen % 4) {
     579               0 :             sdsfreesplitres(v,vlen);
     580               0 :             goto badfmt;
     581                 :         }
     582                 : 
     583                 :         /* Sanity check of single arguments, so that we either refuse the
     584                 :          * whole configuration string or accept it all, even if a single
     585                 :          * error in a single client class is present. */
     586              15 :         for (j = 0; j < vlen; j++) {
     587                 :             char *eptr;
     588                 :             long val;
     589                 : 
     590              12 :             if ((j % 4) == 0) {
     591               3 :                 if (getClientLimitClassByName(v[j]) == -1) {
     592               0 :                     sdsfreesplitres(v,vlen);
     593               0 :                     goto badfmt;
     594                 :                 }
     595                 :             } else {
     596               9 :                 val = strtoll(v[j], &eptr, 10);
     597               9 :                 if (eptr[0] != '\0' || val < 0) {
     598               0 :                     sdsfreesplitres(v,vlen);
     599               0 :                     goto badfmt;
     600                 :                 }
     601                 :             }
     602                 :         }
     603                 :         /* Finally set the new config */
     604               6 :         for (j = 0; j < vlen; j += 4) {
     605                 :             int class;
     606                 :             unsigned long long hard, soft;
     607                 :             int soft_seconds;
     608                 : 
     609               3 :             class = getClientLimitClassByName(v[j]);
     610               3 :             hard = strtoll(v[j+1],NULL,10);
     611               3 :             soft = strtoll(v[j+2],NULL,10);
     612               3 :             soft_seconds = strtoll(v[j+3],NULL,10);
     613                 : 
     614               3 :             server.client_obuf_limits[class].hard_limit_bytes = hard;
     615               3 :             server.client_obuf_limits[class].soft_limit_bytes = soft;
     616               3 :             server.client_obuf_limits[class].soft_limit_seconds = soft_seconds;
     617                 :         }
     618               3 :         sdsfreesplitres(v,vlen);
     619               0 :     } else if (!strcasecmp(c->argv[2]->ptr,"stop-writes-on-bgsave-error")) {
     620               0 :         int yn = yesnotoi(o->ptr);
     621                 : 
     622               0 :         if (yn == -1) goto badfmt;
     623               0 :         server.stop_writes_on_bgsave_err = yn;
     624               0 :     } else if (!strcasecmp(c->argv[2]->ptr,"repl-ping-slave-period")) {
     625               0 :         if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll <= 0) goto badfmt;
     626               0 :         server.repl_ping_slave_period = ll;
     627               0 :     } else if (!strcasecmp(c->argv[2]->ptr,"repl-timeout")) {
     628               0 :         if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll <= 0) goto badfmt;
     629               0 :         server.repl_timeout = ll;
     630               0 :     } else if (!strcasecmp(c->argv[2]->ptr,"watchdog-period")) {
     631               0 :         if (getLongLongFromObject(o,&ll) == REDIS_ERR || ll < 0) goto badfmt;
     632               0 :         if (ll)
     633               0 :             enableWatchdog(ll);
     634                 :         else
     635               0 :             disableWatchdog();
     636                 :     } else {
     637               0 :         addReplyErrorFormat(c,"Unsupported CONFIG parameter: %s",
     638               0 :             (char*)c->argv[2]->ptr);
     639               0 :         return;
     640                 :     }
     641              43 :     addReply(c,shared.ok);
     642              43 :     return;
     643                 : 
     644                 : badfmt: /* Bad format errors */
     645               0 :     addReplyErrorFormat(c,"Invalid argument '%s' for CONFIG SET '%s'",
     646                 :             (char*)o->ptr,
     647               0 :             (char*)c->argv[2]->ptr);
     648                 : }
     649                 : 
     650                 : #define config_get_string_field(_name,_var) do { \
     651                 :     if (stringmatch(pattern,_name,0)) { \
     652                 :         addReplyBulkCString(c,_name); \
     653                 :         addReplyBulkCString(c,_var ? _var : ""); \
     654                 :         matches++; \
     655                 :     } \
     656                 : } while(0);
     657                 : 
     658                 : #define config_get_bool_field(_name,_var) do { \
     659                 :     if (stringmatch(pattern,_name,0)) { \
     660                 :         addReplyBulkCString(c,_name); \
     661                 :         addReplyBulkCString(c,_var ? "yes" : "no"); \
     662                 :         matches++; \
     663                 :     } \
     664                 : } while(0);
     665                 : 
     666                 : #define config_get_numerical_field(_name,_var) do { \
     667                 :     if (stringmatch(pattern,_name,0)) { \
     668                 :         ll2string(buf,sizeof(buf),_var); \
     669                 :         addReplyBulkCString(c,_name); \
     670                 :         addReplyBulkCString(c,buf); \
     671                 :         matches++; \
     672                 :     } \
     673                 : } while(0);
     674                 : 
     675               0 : void configGetCommand(redisClient *c) {
     676               0 :     robj *o = c->argv[2];
     677               0 :     void *replylen = addDeferredMultiBulkLength(c);
     678               0 :     char *pattern = o->ptr;
     679                 :     char buf[128];
     680               0 :     int matches = 0;
     681               0 :     redisAssertWithInfo(c,o,o->encoding == REDIS_ENCODING_RAW);
     682                 : 
     683                 :     /* String values */
     684               0 :     config_get_string_field("dbfilename",server.rdb_filename);
     685               0 :     config_get_string_field("requirepass",server.requirepass);
     686               0 :     config_get_string_field("masterauth",server.requirepass);
     687               0 :     config_get_string_field("bind",server.bindaddr);
     688               0 :     config_get_string_field("unixsocket",server.unixsocket);
     689               0 :     config_get_string_field("logfile",server.logfile);
     690               0 :     config_get_string_field("pidfile",server.pidfile);
     691                 : 
     692                 :     /* Numerical values */
     693               0 :     config_get_numerical_field("maxmemory",server.maxmemory);
     694               0 :     config_get_numerical_field("maxmemory-samples",server.maxmemory_samples);
     695               0 :     config_get_numerical_field("timeout",server.maxidletime);
     696               0 :     config_get_numerical_field("auto-aof-rewrite-percentage",
     697                 :             server.aof_rewrite_perc);
     698               0 :     config_get_numerical_field("auto-aof-rewrite-min-size",
     699                 :             server.aof_rewrite_min_size);
     700               0 :     config_get_numerical_field("hash-max-ziplist-entries",
     701                 :             server.hash_max_ziplist_entries);
     702               0 :     config_get_numerical_field("hash-max-ziplist-value",
     703                 :             server.hash_max_ziplist_value);
     704               0 :     config_get_numerical_field("list-max-ziplist-entries",
     705                 :             server.list_max_ziplist_entries);
     706               0 :     config_get_numerical_field("list-max-ziplist-value",
     707                 :             server.list_max_ziplist_value);
     708               0 :     config_get_numerical_field("set-max-intset-entries",
     709                 :             server.set_max_intset_entries);
     710               0 :     config_get_numerical_field("zset-max-ziplist-entries",
     711                 :             server.zset_max_ziplist_entries);
     712               0 :     config_get_numerical_field("zset-max-ziplist-value",
     713                 :             server.zset_max_ziplist_value);
     714               0 :     config_get_numerical_field("lua-time-limit",server.lua_time_limit);
     715               0 :     config_get_numerical_field("slowlog-log-slower-than",
     716                 :             server.slowlog_log_slower_than);
     717               0 :     config_get_numerical_field("slowlog-max-len",
     718                 :             server.slowlog_max_len);
     719               0 :     config_get_numerical_field("port",server.port);
     720               0 :     config_get_numerical_field("databases",server.dbnum);
     721               0 :     config_get_numerical_field("repl-ping-slave-period",server.repl_ping_slave_period);
     722               0 :     config_get_numerical_field("repl-timeout",server.repl_timeout);
     723               0 :     config_get_numerical_field("maxclients",server.maxclients);
     724               0 :     config_get_numerical_field("watchdog-period",server.watchdog_period);
     725                 : 
     726                 :     /* Bool (yes/no) values */
     727               0 :     config_get_bool_field("no-appendfsync-on-rewrite",
     728                 :             server.aof_no_fsync_on_rewrite);
     729               0 :     config_get_bool_field("slave-serve-stale-data",
     730                 :             server.repl_serve_stale_data);
     731               0 :     config_get_bool_field("slave-read-only",
     732                 :             server.repl_slave_ro);
     733               0 :     config_get_bool_field("stop-writes-on-bgsave-error",
     734                 :             server.stop_writes_on_bgsave_err);
     735               0 :     config_get_bool_field("daemonize", server.daemonize);
     736               0 :     config_get_bool_field("rdbcompression", server.rdb_compression);
     737               0 :     config_get_bool_field("activerehashing", server.activerehashing);
     738                 : 
     739                 :     /* Everything we can't handle with macros follows. */
     740                 : 
     741               0 :     if (stringmatch(pattern,"appendonly",0)) {
     742               0 :         addReplyBulkCString(c,"appendonly");
     743               0 :         addReplyBulkCString(c,server.aof_state == REDIS_AOF_OFF ? "no" : "yes");
     744               0 :         matches++;
     745                 :     }
     746               0 :     if (stringmatch(pattern,"dir",0)) {
     747                 :         char buf[1024];
     748                 : 
     749               0 :         if (getcwd(buf,sizeof(buf)) == NULL)
     750               0 :             buf[0] = '\0';
     751                 : 
     752               0 :         addReplyBulkCString(c,"dir");
     753               0 :         addReplyBulkCString(c,buf);
     754               0 :         matches++;
     755                 :     }
     756               0 :     if (stringmatch(pattern,"maxmemory-policy",0)) {
     757                 :         char *s;
     758                 : 
     759               0 :         switch(server.maxmemory_policy) {
     760               0 :         case REDIS_MAXMEMORY_VOLATILE_LRU: s = "volatile-lru"; break;
     761               0 :         case REDIS_MAXMEMORY_VOLATILE_TTL: s = "volatile-ttl"; break;
     762               0 :         case REDIS_MAXMEMORY_VOLATILE_RANDOM: s = "volatile-random"; break;
     763               0 :         case REDIS_MAXMEMORY_ALLKEYS_LRU: s = "allkeys-lru"; break;
     764               0 :         case REDIS_MAXMEMORY_ALLKEYS_RANDOM: s = "allkeys-random"; break;
     765               0 :         case REDIS_MAXMEMORY_NO_EVICTION: s = "noeviction"; break;
     766               0 :         default: s = "unknown"; break; /* too harmless to panic */
     767                 :         }
     768               0 :         addReplyBulkCString(c,"maxmemory-policy");
     769               0 :         addReplyBulkCString(c,s);
     770               0 :         matches++;
     771                 :     }
     772               0 :     if (stringmatch(pattern,"appendfsync",0)) {
     773                 :         char *policy;
     774                 : 
     775               0 :         switch(server.aof_fsync) {
     776               0 :         case AOF_FSYNC_NO: policy = "no"; break;
     777               0 :         case AOF_FSYNC_EVERYSEC: policy = "everysec"; break;
     778               0 :         case AOF_FSYNC_ALWAYS: policy = "always"; break;
     779               0 :         default: policy = "unknown"; break; /* too harmless to panic */
     780                 :         }
     781               0 :         addReplyBulkCString(c,"appendfsync");
     782               0 :         addReplyBulkCString(c,policy);
     783               0 :         matches++;
     784                 :     }
     785               0 :     if (stringmatch(pattern,"save",0)) {
     786               0 :         sds buf = sdsempty();
     787                 :         int j;
     788                 : 
     789               0 :         for (j = 0; j < server.saveparamslen; j++) {
     790               0 :             buf = sdscatprintf(buf,"%ld %d",
     791               0 :                     server.saveparams[j].seconds,
     792               0 :                     server.saveparams[j].changes);
     793               0 :             if (j != server.saveparamslen-1)
     794               0 :                 buf = sdscatlen(buf," ",1);
     795                 :         }
     796               0 :         addReplyBulkCString(c,"save");
     797               0 :         addReplyBulkCString(c,buf);
     798               0 :         sdsfree(buf);
     799               0 :         matches++;
     800                 :     }
     801               0 :     if (stringmatch(pattern,"loglevel",0)) {
     802                 :         char *s;
     803                 : 
     804               0 :         switch(server.verbosity) {
     805               0 :         case REDIS_WARNING: s = "warning"; break;
     806               0 :         case REDIS_VERBOSE: s = "verbose"; break;
     807               0 :         case REDIS_NOTICE: s = "notice"; break;
     808               0 :         case REDIS_DEBUG: s = "debug"; break;
     809               0 :         default: s = "unknown"; break; /* too harmless to panic */
     810                 :         }
     811               0 :         addReplyBulkCString(c,"loglevel");
     812               0 :         addReplyBulkCString(c,s);
     813               0 :         matches++;
     814                 :     }
     815               0 :     if (stringmatch(pattern,"client-output-buffer-limit",0)) {
     816               0 :         sds buf = sdsempty();
     817                 :         int j;
     818                 : 
     819               0 :         for (j = 0; j < REDIS_CLIENT_LIMIT_NUM_CLASSES; j++) {
     820               0 :             buf = sdscatprintf(buf,"%s %llu %llu %ld",
     821                 :                     getClientLimitClassName(j),
     822                 :                     server.client_obuf_limits[j].hard_limit_bytes,
     823                 :                     server.client_obuf_limits[j].soft_limit_bytes,
     824                 :                     (long) server.client_obuf_limits[j].soft_limit_seconds);
     825               0 :             if (j != REDIS_CLIENT_LIMIT_NUM_CLASSES-1)
     826               0 :                 buf = sdscatlen(buf," ",1);
     827                 :         }
     828               0 :         addReplyBulkCString(c,"client-output-buffer-limit");
     829               0 :         addReplyBulkCString(c,buf);
     830               0 :         sdsfree(buf);
     831               0 :         matches++;
     832                 :     }
     833               0 :     if (stringmatch(pattern,"unixsocketperm",0)) {
     834                 :         char buf[32];
     835               0 :         snprintf(buf,sizeof(buf),"%o",server.unixsocketperm);
     836               0 :         addReplyBulkCString(c,"unixsocketperm");
     837               0 :         addReplyBulkCString(c,buf);
     838               0 :         matches++;
     839                 :     }
     840               0 :     if (stringmatch(pattern,"slaveof",0)) {
     841                 :         char buf[256];
     842                 : 
     843               0 :         addReplyBulkCString(c,"slaveof");
     844               0 :         if (server.masterhost)
     845               0 :             snprintf(buf,sizeof(buf),"%s %d",
     846                 :                 server.masterhost, server.masterport);
     847                 :         else
     848               0 :             buf[0] = '\0';
     849               0 :         addReplyBulkCString(c,buf);
     850               0 :         matches++;
     851                 :     }
     852               0 :     setDeferredMultiBulkLength(c,replylen,matches*2);
     853               0 : }
     854                 : 
     855              43 : void configCommand(redisClient *c) {
     856              43 :     if (!strcasecmp(c->argv[1]->ptr,"set")) {
     857              43 :         if (c->argc != 4) goto badarity;
     858              43 :         configSetCommand(c);
     859               0 :     } else if (!strcasecmp(c->argv[1]->ptr,"get")) {
     860               0 :         if (c->argc != 3) goto badarity;
     861               0 :         configGetCommand(c);
     862               0 :     } else if (!strcasecmp(c->argv[1]->ptr,"resetstat")) {
     863               0 :         if (c->argc != 2) goto badarity;
     864               0 :         server.stat_keyspace_hits = 0;
     865               0 :         server.stat_keyspace_misses = 0;
     866               0 :         server.stat_numcommands = 0;
     867               0 :         server.stat_numconnections = 0;
     868               0 :         server.stat_expiredkeys = 0;
     869               0 :         server.stat_rejected_conn = 0;
     870               0 :         server.stat_fork_time = 0;
     871               0 :         server.aof_delayed_fsync = 0;
     872               0 :         resetCommandTableStats();
     873               0 :         addReply(c,shared.ok);
     874                 :     } else {
     875               0 :         addReplyError(c,
     876                 :             "CONFIG subcommand must be one of GET, SET, RESETSTAT");
     877                 :     }
     878                 :     return;
     879                 : 
     880                 : badarity:
     881               0 :     addReplyErrorFormat(c,"Wrong number of arguments for CONFIG %s",
     882               0 :         (char*) c->argv[1]->ptr);
     883                 : }

Generated by: LCOV version 1.7