diff --git a/src/redis.c b/src/redis.c index f7b04f08f05cbe54add0f931de5da212e751c0e4..75617d6ae1cdb9c9427c86e6294550417bbbc8c8 100644 --- a/src/redis.c +++ b/src/redis.c @@ -1163,6 +1163,7 @@ void createSharedObjects(void) { void initServerConfig() { getRandomHexChars(server.runid,REDIS_RUN_ID_SIZE); + server.configfile = NULL; server.hz = REDIS_DEFAULT_HZ; server.runid[REDIS_RUN_ID_SIZE] = '\0'; server.arch_bits = (sizeof(long) == 8) ? 64 : 32; @@ -2006,7 +2007,8 @@ sds genRedisInfoString(char *section) { "uptime_in_seconds:%ld\r\n" "uptime_in_days:%ld\r\n" "hz:%d\r\n" - "lru_clock:%ld\r\n", + "lru_clock:%ld\r\n" + "config_file:%s\r\n", REDIS_VERSION, redisGitSHA1(), strtol(redisGitDirty(),NULL,10) > 0, @@ -2026,7 +2028,8 @@ sds genRedisInfoString(char *section) { uptime, uptime/(3600*24), server.hz, - (unsigned long) server.lruclock); + (unsigned long) server.lruclock, + server.configfile ? server.configfile : ""); } /* Clients */ @@ -2689,6 +2692,58 @@ void redisSetProcTitle(char *title) { #endif } +/* Given the filename, return the absolute path as an SDS string, or NULL + * if it fails for some reason. Note that "filename" may be an absolute path + * already, this will be detected and handled correctly. + * + * The function does not try to normalize everything, but only the obvious + * case of one or more "../" appearning at the start of "filename" + * relative path. */ +sds getAbsolutePath(char *filename) { + char cwd[1024]; + sds abspath; + sds relpath = sdsnew(filename); + + relpath = sdstrim(relpath," \r\n\t"); + if (relpath[0] == '/') return relpath; /* Path is already absolute. */ + + /* If path is relative, join cwd and relative path. */ + if (getcwd(cwd,sizeof(cwd)) == NULL) { + sdsfree(relpath); + return NULL; + } + abspath = sdsnew(cwd); + if (sdslen(abspath) && abspath[sdslen(abspath)-1] != '/') + abspath = sdscat(abspath,"/"); + + /* At this point we have the current path always ending with "/", and + * the trimmed relative path. Try to normalize the obvious case of + * trailing ../ elements at the start of the path. + * + * For every "../" we find in the filename, we remove it and also remove + * the last element of the cwd, unless the current cwd is "/". */ + while (sdslen(relpath) >= 3 && + relpath[0] == '.' && relpath[1] == '.' && relpath[2] == '/') + { + relpath = sdsrange(relpath,3,-1); + if (sdslen(abspath) > 1) { + char *p = abspath + sdslen(abspath)-2; + int trimlen = 1; + + while(*p != '/') { + p--; + trimlen++; + } + abspath = sdsrange(abspath,0,-(trimlen+1)); + } + } + + /* Finally glue the two parts together. */ + abspath = sdscatsds(abspath,relpath); + sdsfree(relpath); + return abspath; +} + int main(int argc, char **argv) { struct timeval tv; @@ -2756,6 +2811,7 @@ int main(int argc, char **argv) { resetServerSaveParams(); loadServerConfig(configfile,options); sdsfree(options); + if (configfile) server.configfile = getAbsolutePath(configfile); } else { redisLog(REDIS_WARNING, "Warning: no config file specified, using the default config. In order to specify a config file use %s /path/to/%s.conf", argv[0], server.sentinel_mode ? "sentinel" : "redis"); } diff --git a/src/redis.h b/src/redis.h index a05a3ad36471b234bcf435a0f3c8e0907105bcb9..23773ca493b1a07a7a3ff8b0511f6f07502309af 100644 --- a/src/redis.h +++ b/src/redis.h @@ -519,6 +519,7 @@ typedef struct redisOpArray { struct redisServer { /* General */ + char *configfile; /* Absolute config file path, or NULL */ int hz; /* serverCron() calls frequency in hertz */ redisDb *db; dict *commands; /* Command table */