diff --git a/src/Makefile b/src/Makefile index 3f982cc8eb9..efc63b28ef9 100644 --- a/src/Makefile +++ b/src/Makefile @@ -206,11 +206,13 @@ endif REDIS_SERVER_NAME=redis-server REDIS_SENTINEL_NAME=redis-sentinel -REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o lolwut.o lolwut5.o lolwut6.o acl.o gopher.o tracking.o connection.o tls.o sha256.o timeout.o + +REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o redis_err.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o t_stream.o listpack.o localtime.o lolwut.o lolwut5.o lolwut6.o acl.o gopher.o tracking.o connection.o tls.o sha256.o timeout.o REDIS_CLI_NAME=redis-cli -REDIS_CLI_OBJ=anet.o adlist.o dict.o redis-cli.o zmalloc.o release.o ae.o crc64.o siphash.o crc16.o +REDIS_CLI_OBJ=anet.o adlist.o dict.o redis-cli.o zmalloc.o redis_err.o release.o ae.o crc64.o siphash.o crc16.o REDIS_BENCHMARK_NAME=redis-benchmark -REDIS_BENCHMARK_OBJ=ae.o anet.o redis-benchmark.o adlist.o dict.o zmalloc.o siphash.o +REDIS_BENCHMARK_OBJ=ae.o anet.o redis-benchmark.o adlist.o dict.o zmalloc.o redis_err.o siphash.o + REDIS_CHECK_RDB_NAME=redis-check-rdb REDIS_CHECK_AOF_NAME=redis-check-aof diff --git a/src/config.c b/src/config.c index 7c87ebe6e27..56a04e677d9 100644 --- a/src/config.c +++ b/src/config.c @@ -30,6 +30,7 @@ #include "server.h" #include "cluster.h" +#include "redis_err.h" #include #include @@ -550,7 +551,7 @@ void loadServerConfig(char *filename, char *options) { } else { if ((fp = fopen(filename,"r")) == NULL) { serverLog(LL_WARNING, - "Fatal error, can't open config file '%s'", filename); + "Fatal error, can't open config file '%s', %s", filename, redisError(errno)); exit(1); } } diff --git a/src/redis_err.c b/src/redis_err.c new file mode 100644 index 00000000000..b1070a4d47e --- /dev/null +++ b/src/redis_err.c @@ -0,0 +1,67 @@ +/* + * strerror is not thread safe + * why oh why should I complain + * when strerror_r & _l behave differently + * Across the Unix domain + * + * after distinguishing between the two + * And allocating error strings all over + * You have ugly Marcos + * (and are still not async signal safe) + * + * Allocate a static array containing all possible error strings + */ + +#include +#include +#include + +#include "redis_err.h" +#include "zmalloc.h" + +const char **ERROR_ARRAY; +/* sys_nerr is considered internal impl. detail, and isn't available on all OSes */ +const unsigned int MAX_ERR = 256; +const char *UNKNOWN_STRING = "Unknown error"; + +/* + * Initialize the error array + */ +int initErrorStrings(){ + ERROR_ARRAY = zmalloc(sizeof(char*)*(MAX_ERR)); + + unsigned int n = 0; + char *err; + + for (; n < MAX_ERR; n++) { + err = strerror(n); + if (err == NULL + || strncasecmp(err, UNKNOWN_STRING, 13) == 0) + { + ERROR_ARRAY[n] = UNKNOWN_STRING; + continue; + } + ERROR_ARRAY[n] = zstrdup(err); + } + return 0; +} + + +const char *redisError(unsigned int err) { + if (err > MAX_ERR) { + perror("Requested out of bounds error string"); + return UNKNOWN_STRING; + } + return ERROR_ARRAY[err]; +} + + +void freeErrorStrings() { + unsigned int n = 0; + for (;n < MAX_ERR; n++) { + if (ERROR_ARRAY[n] != UNKNOWN_STRING) { + zfree((void *)ERROR_ARRAY[n]); + } + } + +} \ No newline at end of file diff --git a/src/redis_err.h b/src/redis_err.h new file mode 100644 index 00000000000..63c14489cdd --- /dev/null +++ b/src/redis_err.h @@ -0,0 +1,13 @@ +// +// Created by uri on 6/7/19. +// + +#ifndef REDIS_REDIS_ERR_H +#define REDIS_REDIS_ERR_H + + +int initErrorStrings (); +const char *redisError(unsigned int err); +void freeErrorStrings(); + +#endif //REDIS_REDIS_ERR_H diff --git a/src/server.c b/src/server.c index 4fdbf30ec0c..127372c2a4d 100644 --- a/src/server.c +++ b/src/server.c @@ -33,6 +33,7 @@ #include "bio.h" #include "latency.h" #include "atomicvar.h" +#include "redis_err.h" #include #include @@ -1767,7 +1768,7 @@ void checkChildrenDone(void) { if (pid == -1) { serverLog(LL_WARNING,"wait3() returned an error: %s. " "rdb_child_pid = %d, aof_child_pid = %d, module_child_pid = %d", - strerror(errno), + redisError(errno), (int) server.rdb_child_pid, (int) server.aof_child_pid, (int) server.module_child_pid); @@ -2843,7 +2844,7 @@ void initServer(void) { O_WRONLY|O_APPEND|O_CREAT,0644); if (server.aof_fd == -1) { serverLog(LL_WARNING, "Can't open the append-only file: %s", - strerror(errno)); + redisError(errno)); exit(1); } } @@ -4773,7 +4774,7 @@ void loadDataFromDisk(void) { selectDb(server.cached_master,rsi.repl_stream_db); } } else if (errno != ENOENT) { - serverLog(LL_WARNING,"Fatal error loading the DB: %s. Exiting.",strerror(errno)); + serverLog(LL_WARNING,"Fatal error loading the DB: %s. Exiting.",redisError(errno)); exit(1); } } @@ -4902,6 +4903,7 @@ int main(int argc, char **argv) { setlocale(LC_COLLATE,""); tzset(); /* Populates 'timezone' global. */ zmalloc_set_oom_handler(redisOutOfMemoryHandler); + initErrorStrings(); srand(time(NULL)^getpid()); gettimeofday(&tv,NULL); @@ -5073,6 +5075,7 @@ int main(int argc, char **argv) { aeSetAfterSleepProc(server.el,afterSleep); aeMain(server.el); aeDeleteEventLoop(server.el); + freeErrorStrings(); return 0; }