From 8b64e7b4e1a748026de4737578c6909f7ba19f20 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 9 Oct 2016 19:14:49 +0900 Subject: [PATCH] src: Add XSI-compliant version strerror_r --- src/CMakeLists.txt | 1 + src/Makefile.am | 3 +- src/shrpx.cc | 112 ++++++++++++++++++++++++------------ src/shrpx_config.cc | 35 +++++++---- src/shrpx_worker_process.cc | 18 ++++-- src/xsi_strerror.c | 50 ++++++++++++++++ src/xsi_strerror.h | 53 +++++++++++++++++ 7 files changed, 217 insertions(+), 55 deletions(-) create mode 100644 src/xsi_strerror.c create mode 100644 src/xsi_strerror.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2a1836af..92b2ab40 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -112,6 +112,7 @@ if(ENABLE_APP) shrpx_api_downstream_connection.cc shrpx_health_monitor_downstream_connection.cc shrpx_exec.cc + xsi_strerror.c ) if(HAVE_SPDYLAY) list(APPEND NGHTTPX_SRCS diff --git a/src/Makefile.am b/src/Makefile.am index 23594e71..ceaa04a8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -139,7 +139,8 @@ NGHTTPX_SRCS = \ shrpx_health_monitor_downstream_connection.cc \ shrpx_health_monitor_downstream_connection.h \ shrpx_exec.cc shrpx_exec.h \ - buffer.h memchunk.h template.h allocator.h + buffer.h memchunk.h template.h allocator.h \ + xsi_strerror.c xsi_strerror.h if HAVE_SPDYLAY NGHTTPX_SRCS += shrpx_spdy_upstream.cc shrpx_spdy_upstream.h diff --git a/src/shrpx.cc b/src/shrpx.cc index fdbac302..f2219ba9 100644 --- a/src/shrpx.cc +++ b/src/shrpx.cc @@ -88,6 +88,7 @@ #include "template.h" #include "allocator.h" #include "ssl_compat.h" +#include "xsi_strerror.h" extern char **environ; @@ -298,6 +299,7 @@ int chown_to_running_user(const char *path) { namespace { int save_pid() { + std::array errbuf; auto config = get_config(); constexpr auto SUFFIX = StringRef::from_lit(".XXXXXX"); @@ -317,7 +319,7 @@ int save_pid() { if (fd == -1) { auto error = errno; LOG(ERROR) << "Could not save PID to file " << pid_file << ": " - << strerror(error); + << xsi_strerror(error, errbuf.data(), errbuf.size()); return -1; } @@ -326,14 +328,14 @@ int save_pid() { if (write(fd, content.c_str(), content.size()) == -1) { auto error = errno; LOG(ERROR) << "Could not save PID to file " << pid_file << ": " - << strerror(error); + << xsi_strerror(error, errbuf.data(), errbuf.size()); return -1; } if (fsync(fd) == -1) { auto error = errno; LOG(ERROR) << "Could not save PID to file " << pid_file << ": " - << strerror(error); + << xsi_strerror(error, errbuf.data(), errbuf.size()); return -1; } @@ -342,7 +344,7 @@ int save_pid() { if (rename(temp_path, pid_file.c_str()) == -1) { auto error = errno; LOG(ERROR) << "Could not save PID to file " << pid_file << ": " - << strerror(error); + << xsi_strerror(error, errbuf.data(), errbuf.size()); unlink(temp_path); @@ -352,8 +354,8 @@ int save_pid() { if (config->uid != 0) { if (chown_to_running_user(pid_file.c_str()) == -1) { auto error = errno; - LOG(WARN) << "Changing owner of pid file " << pid_file - << " failed: " << strerror(error); + LOG(WARN) << "Changing owner of pid file " << pid_file << " failed: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); } } @@ -365,13 +367,15 @@ namespace { void exec_binary() { int rv; sigset_t oldset; + std::array errbuf; LOG(NOTICE) << "Executing new binary"; rv = shrpx_signal_block_all(&oldset); if (rv != 0) { auto error = errno; - LOG(ERROR) << "Blocking all signals failed: " << strerror(error); + LOG(ERROR) << "Blocking all signals failed: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); return; } @@ -388,7 +392,8 @@ void exec_binary() { if (rv != 0) { auto error = errno; - LOG(FATAL) << "Restoring signal mask failed: " << strerror(error); + LOG(FATAL) << "Restoring signal mask failed: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); exit(EXIT_FAILURE); } @@ -403,7 +408,8 @@ void exec_binary() { rv = shrpx_signal_unblock_all(); if (rv != 0) { auto error = errno; - LOG(ERROR) << "Unblocking all signals failed: " << strerror(error); + LOG(ERROR) << "Unblocking all signals failed: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); _Exit(EXIT_FAILURE); } @@ -493,6 +499,7 @@ void exec_binary() { namespace { void ipc_send(WorkerProcess *wp, uint8_t ipc_event) { + std::array errbuf; ssize_t nwrite; while ((nwrite = write(wp->ipc_fd, &ipc_event, 1)) == -1 && errno == EINTR) ; @@ -500,7 +507,7 @@ void ipc_send(WorkerProcess *wp, uint8_t ipc_event) { if (nwrite < 0) { auto error = errno; LOG(ERROR) << "Could not send IPC event to worker process: " - << strerror(error); + << xsi_strerror(error, errbuf.data(), errbuf.size()); return; } @@ -569,6 +576,7 @@ void worker_process_child_cb(struct ev_loop *loop, ev_child *w, int revents) { namespace { int create_unix_domain_server_socket(UpstreamAddr &faddr, std::vector &iaddrs) { + std::array errbuf; auto found = std::find_if( std::begin(iaddrs), std::end(iaddrs), [&faddr](const InheritedAddr &ia) { return !ia.used && ia.host_unix && ia.host == faddr.host; @@ -588,14 +596,16 @@ int create_unix_domain_server_socket(UpstreamAddr &faddr, auto fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0); if (fd == -1) { auto error = errno; - LOG(WARN) << "socket() syscall failed: " << strerror(error); + LOG(WARN) << "socket() syscall failed: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); return -1; } #else // !SOCK_NONBLOCK auto fd = socket(AF_UNIX, SOCK_STREAM, 0); if (fd == -1) { auto error = errno; - LOG(WARN) << "socket() syscall failed: " << strerror(error); + LOG(WARN) << "socket() syscall failed: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); return -1; } util::make_socket_nonblocking(fd); @@ -605,7 +615,7 @@ int create_unix_domain_server_socket(UpstreamAddr &faddr, static_cast(sizeof(val))) == -1) { auto error = errno; LOG(WARN) << "Failed to set SO_REUSEADDR option to listener socket: " - << strerror(error); + << xsi_strerror(error, errbuf.data(), errbuf.size()); close(fd); return -1; } @@ -626,7 +636,8 @@ int create_unix_domain_server_socket(UpstreamAddr &faddr, if (bind(fd, &addr.sa, sizeof(addr.un)) != 0) { auto error = errno; - LOG(FATAL) << "Failed to bind UNIX domain socket: " << strerror(error); + LOG(FATAL) << "Failed to bind UNIX domain socket: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); close(fd); return -1; } @@ -635,7 +646,8 @@ int create_unix_domain_server_socket(UpstreamAddr &faddr, if (listen(fd, listenerconf.backlog) != 0) { auto error = errno; - LOG(FATAL) << "Failed to listen to UNIX domain socket: " << strerror(error); + LOG(FATAL) << "Failed to listen to UNIX domain socket: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); close(fd); return -1; } @@ -653,6 +665,7 @@ int create_unix_domain_server_socket(UpstreamAddr &faddr, namespace { int create_tcp_server_socket(UpstreamAddr &faddr, std::vector &iaddrs) { + std::array errbuf; int fd = -1; int rv; @@ -713,14 +726,16 @@ int create_tcp_server_socket(UpstreamAddr &faddr, socket(rp->ai_family, rp->ai_socktype | SOCK_NONBLOCK, rp->ai_protocol); if (fd == -1) { auto error = errno; - LOG(WARN) << "socket() syscall failed: " << strerror(error); + LOG(WARN) << "socket() syscall failed: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); continue; } #else // !SOCK_NONBLOCK fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); if (fd == -1) { auto error = errno; - LOG(WARN) << "socket() syscall failed: " << strerror(error); + LOG(WARN) << "socket() syscall failed: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); continue; } util::make_socket_nonblocking(fd); @@ -730,7 +745,7 @@ int create_tcp_server_socket(UpstreamAddr &faddr, static_cast(sizeof(val))) == -1) { auto error = errno; LOG(WARN) << "Failed to set SO_REUSEADDR option to listener socket: " - << strerror(error); + << xsi_strerror(error, errbuf.data(), errbuf.size()); close(fd); continue; } @@ -741,7 +756,7 @@ int create_tcp_server_socket(UpstreamAddr &faddr, static_cast(sizeof(val))) == -1) { auto error = errno; LOG(WARN) << "Failed to set IPV6_V6ONLY option to listener socket: " - << strerror(error); + << xsi_strerror(error, errbuf.data(), errbuf.size()); close(fd); continue; } @@ -754,7 +769,7 @@ int create_tcp_server_socket(UpstreamAddr &faddr, static_cast(sizeof(val))) == -1) { auto error = errno; LOG(WARN) << "Failed to set TCP_DEFER_ACCEPT option to listener socket: " - << strerror(error); + << xsi_strerror(error, errbuf.data(), errbuf.size()); } #endif // TCP_DEFER_ACCEPT @@ -763,7 +778,8 @@ int create_tcp_server_socket(UpstreamAddr &faddr, // ports will fail with permission denied error. if (bind(fd, rp->ai_addr, rp->ai_addrlen) == -1) { auto error = errno; - LOG(WARN) << "bind() syscall failed: " << strerror(error); + LOG(WARN) << "bind() syscall failed: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); close(fd); continue; } @@ -774,13 +790,14 @@ int create_tcp_server_socket(UpstreamAddr &faddr, static_cast(sizeof(val))) == -1) { auto error = errno; LOG(WARN) << "Failed to set TCP_FASTOPEN option to listener socket: " - << strerror(error); + << xsi_strerror(error, errbuf.data(), errbuf.size()); } } if (listen(fd, listenerconf.backlog) == -1) { auto error = errno; - LOG(WARN) << "listen() syscall failed: " << strerror(error); + LOG(WARN) << "listen() syscall failed: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); close(fd); continue; } @@ -812,6 +829,7 @@ namespace { // |config| is usually a current configuration. std::vector get_inherited_addr_from_config(BlockAllocator &balloc, Config *config) { + std::array errbuf; int rv; auto &listenerconf = config->conn.listener; @@ -848,7 +866,7 @@ get_inherited_addr_from_config(BlockAllocator &balloc, Config *config) { if (getsockname(addr.fd, &su.sa, &salen) != 0) { auto error = errno; LOG(WARN) << "getsockname() syscall failed (fd=" << addr.fd - << "): " << strerror(error); + << "): " << xsi_strerror(error, errbuf.data(), errbuf.size()); continue; } @@ -873,6 +891,7 @@ namespace { // variables. This function handles the old environment variable // names used in 1.7.0 or earlier. std::vector get_inherited_addr_from_env(Config *config) { + std::array errbuf; int rv; std::vector iaddrs; @@ -971,7 +990,7 @@ std::vector get_inherited_addr_from_env(Config *config) { if (getsockname(fd, &su.sa, &salen) != 0) { auto error = errno; LOG(WARN) << "getsockname() syscall failed (fd=" << fd - << "): " << strerror(error); + << "): " << xsi_strerror(error, errbuf.data(), errbuf.size()); close(fd); continue; } @@ -1033,6 +1052,7 @@ void close_unused_inherited_addr(const std::vector &iaddrs) { namespace { int create_acceptor_socket(Config *config, std::vector &iaddrs) { + std::array errbuf; auto &listenerconf = config->conn.listener; for (auto &addr : listenerconf.addrs) { @@ -1047,7 +1067,8 @@ int create_acceptor_socket(Config *config, std::vector &iaddrs) { if (chown_to_running_user(addr.host.c_str()) == -1) { auto error = errno; LOG(WARN) << "Changing owner of UNIX domain socket " << addr.host - << " failed: " << strerror(error); + << " failed: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); } } continue; @@ -1078,13 +1099,14 @@ namespace { // messages to the worker process. On success, ipc_fd[0] is for // reading, and ipc_fd[1] for writing, just like pipe(2). int create_ipc_socket(std::array &ipc_fd) { + std::array errbuf; int rv; rv = pipe(ipc_fd.data()); if (rv == -1) { auto error = errno; LOG(WARN) << "Failed to create pipe to communicate worker process: " - << strerror(error); + << xsi_strerror(error, errbuf.data(), errbuf.size()); return -1; } @@ -1106,6 +1128,7 @@ namespace { // used in the current configuration. pid_t fork_worker_process(int &main_ipc_fd, const std::vector &iaddrs) { + std::array errbuf; int rv; sigset_t oldset; @@ -1119,7 +1142,8 @@ pid_t fork_worker_process(int &main_ipc_fd, rv = shrpx_signal_block_all(&oldset); if (rv != 0) { auto error = errno; - LOG(ERROR) << "Blocking all signals failed: " << strerror(error); + LOG(ERROR) << "Blocking all signals failed: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); close(ipc_fd[0]); close(ipc_fd[1]); @@ -1143,7 +1167,8 @@ pid_t fork_worker_process(int &main_ipc_fd, rv = shrpx_signal_unblock_all(); if (rv != 0) { auto error = errno; - LOG(FATAL) << "Unblocking all signals failed: " << strerror(error); + LOG(FATAL) << "Unblocking all signals failed: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); _Exit(EXIT_FAILURE); } @@ -1166,13 +1191,15 @@ pid_t fork_worker_process(int &main_ipc_fd, // parent process if (pid == -1) { auto error = errno; - LOG(ERROR) << "Could not spawn worker process: " << strerror(error); + LOG(ERROR) << "Could not spawn worker process: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); } rv = shrpx_signal_set(&oldset); if (rv != 0) { auto error = errno; - LOG(FATAL) << "Restoring signal mask failed: " << strerror(error); + LOG(FATAL) << "Restoring signal mask failed: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); exit(EXIT_FAILURE); } @@ -1196,6 +1223,8 @@ pid_t fork_worker_process(int &main_ipc_fd, namespace { int event_loop() { + std::array errbuf; + shrpx_signal_set_master_proc_ign_handler(); auto config = mod_config(); @@ -1203,7 +1232,8 @@ int event_loop() { if (config->daemon) { if (call_daemon() == -1) { auto error = errno; - LOG(FATAL) << "Failed to daemonize: " << strerror(error); + LOG(FATAL) << "Failed to daemonize: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); return -1; } @@ -2398,6 +2428,7 @@ Misc: namespace { int process_options(Config *config, std::vector> &cmdcfgs) { + std::array errbuf; if (conf_exists(config->conf_path.c_str())) { std::set include_set; if (load_config(config, config->conf_path.c_str(), include_set) == -1) { @@ -2442,13 +2473,13 @@ int process_options(Config *config, fchown(log_config()->accesslog_fd, config->uid, config->gid) == -1) { auto error = errno; LOG(WARN) << "Changing owner of access log file failed: " - << strerror(error); + << xsi_strerror(error, errbuf.data(), errbuf.size()); } if (log_config()->errorlog_fd != -1 && fchown(log_config()->errorlog_fd, config->uid, config->gid) == -1) { auto error = errno; LOG(WARN) << "Changing owner of error log file failed: " - << strerror(error); + << xsi_strerror(error, errbuf.data(), errbuf.size()); } } @@ -2472,7 +2503,8 @@ int process_options(Config *config, if (chown_to_running_user(path) == -1) { auto error = errno; LOG(WARN) << "Changing owner of http2 upstream request header file " - << path << " failed: " << strerror(error); + << path << " failed: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); } } } @@ -2493,7 +2525,8 @@ int process_options(Config *config, if (chown_to_running_user(path) == -1) { auto error = errno; LOG(WARN) << "Changing owner of http2 upstream response header file" - << " " << path << " failed: " << strerror(error); + << " " << path << " failed: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); } } } @@ -2614,7 +2647,8 @@ int process_options(Config *config, static_cast(config->rlimit_nofile)}; if (setrlimit(RLIMIT_NOFILE, &lim) != 0) { auto error = errno; - LOG(WARN) << "Setting rlimit-nofile failed: " << strerror(error); + LOG(WARN) << "Setting rlimit-nofile failed: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); } } @@ -2740,6 +2774,7 @@ void reload_config(WorkerProcess *wp) { int main(int argc, char **argv) { int rv; + std::array errbuf; nghttp2::ssl::libssl_init(); @@ -2768,7 +2803,8 @@ int main(int argc, char **argv) { suconfig.argv[i] = strdup(argv[i]); if (suconfig.argv[i] == nullptr) { auto error = errno; - LOG(FATAL) << "failed to copy argv: " << strerror(error); + LOG(FATAL) << "failed to copy argv: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); exit(EXIT_FAILURE); } } diff --git a/src/shrpx_config.cc b/src/shrpx_config.cc index 5527ad4e..a1a20b70 100644 --- a/src/shrpx_config.cc +++ b/src/shrpx_config.cc @@ -58,6 +58,7 @@ #include "util.h" #include "base64.h" #include "ssl_compat.h" +#include "xsi_strerror.h" namespace shrpx { @@ -225,6 +226,8 @@ read_tls_ticket_key_file(const std::vector &files, } FILE *open_file_for_write(const char *filename) { + std::array errbuf; + #if defined O_CLOEXEC auto fd = open(filename, O_WRONLY | O_CLOEXEC | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); @@ -237,14 +240,16 @@ FILE *open_file_for_write(const char *filename) { } #endif if (fd == -1) { - LOG(ERROR) << "Failed to open " << filename - << " for writing. Cause: " << strerror(errno); + auto error = errno; + LOG(ERROR) << "Failed to open " << filename << " for writing. Cause: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); return nullptr; } auto f = fdopen(fd, "wb"); if (f == nullptr) { - LOG(ERROR) << "Failed to open " << filename - << " for writing. Cause: " << strerror(errno); + auto error = errno; + LOG(ERROR) << "Failed to open " << filename << " for writing. Cause: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); return nullptr; } @@ -963,6 +968,8 @@ int parse_forwarded_node_type(const StringRef &optarg) { namespace { int parse_error_page(std::vector &error_pages, const StringRef &opt, const StringRef &optarg) { + std::array errbuf; + auto eq = std::find(std::begin(optarg), std::end(optarg), '='); if (eq == std::end(optarg) || eq + 1 == std::end(optarg)) { LOG(ERROR) << opt << ": bad value: '" << optarg << "'"; @@ -991,7 +998,8 @@ int parse_error_page(std::vector &error_pages, const StringRef &opt, auto fd = open(path.c_str(), O_RDONLY); if (fd == -1) { auto error = errno; - LOG(ERROR) << opt << ": " << optarg << ": " << strerror(error); + LOG(ERROR) << opt << ": " << optarg << ": " + << xsi_strerror(error, errbuf.data(), errbuf.size()); return -1; } @@ -1002,7 +1010,8 @@ int parse_error_page(std::vector &error_pages, const StringRef &opt, auto n = read(fd, buf.data(), buf.size()); if (n == -1) { auto error = errno; - LOG(ERROR) << opt << ": " << optarg << ": " << strerror(error); + LOG(ERROR) << opt << ": " << optarg << ": " + << xsi_strerror(error, errbuf.data(), errbuf.size()); return -1; } if (n == 0) { @@ -1068,10 +1077,13 @@ namespace { // must be NULL-terminated string. int read_tls_sct_from_dir(std::vector &dst, const StringRef &opt, const StringRef &dir_path) { + std::array errbuf; + auto dir = opendir(dir_path.c_str()); if (dir == nullptr) { auto error = errno; - LOG(ERROR) << opt << ": " << dir_path << ": " << strerror(error); + LOG(ERROR) << opt << ": " << dir_path << ": " + << xsi_strerror(error, errbuf.data(), errbuf.size()); return -1; } @@ -1088,7 +1100,7 @@ int read_tls_sct_from_dir(std::vector &dst, const StringRef &opt, if (errno != 0) { auto error = errno; LOG(ERROR) << opt << ": failed to read directory " << dir_path << ": " - << strerror(error); + << xsi_strerror(error, errbuf.data(), errbuf.size()); return -1; } break; @@ -1113,7 +1125,7 @@ int read_tls_sct_from_dir(std::vector &dst, const StringRef &opt, if (fd == -1) { auto error = errno; LOG(ERROR) << opt << ": failed to read SCT from " << path << ": " - << strerror(error); + << xsi_strerror(error, errbuf.data(), errbuf.size()); return -1; } @@ -1131,7 +1143,7 @@ int read_tls_sct_from_dir(std::vector &dst, const StringRef &opt, if (nread == -1) { auto error = errno; LOG(ERROR) << opt << ": failed to read SCT data from " << path << ": " - << strerror(error); + << xsi_strerror(error, errbuf.data(), errbuf.size()); return -1; } @@ -2000,6 +2012,7 @@ int parse_config(Config *config, const StringRef &opt, const StringRef &optarg, int parse_config(Config *config, int optid, const StringRef &opt, const StringRef &optarg, std::set &included_set) { + std::array errbuf; char host[NI_MAXHOST]; uint16_t port; @@ -2304,7 +2317,7 @@ int parse_config(Config *config, int optid, const StringRef &opt, auto pwd = getpwnam(optarg.c_str()); if (!pwd) { LOG(ERROR) << opt << ": failed to get uid from " << optarg << ": " - << strerror(errno); + << xsi_strerror(errno, errbuf.data(), errbuf.size()); return -1; } config->user = make_string_ref(config->balloc, StringRef{pwd->pw_name}); diff --git a/src/shrpx_worker_process.cc b/src/shrpx_worker_process.cc index 3ed67a36..76770d10 100644 --- a/src/shrpx_worker_process.cc +++ b/src/shrpx_worker_process.cc @@ -52,6 +52,7 @@ #include "util.h" #include "app_helper.h" #include "template.h" +#include "xsi_strerror.h" using namespace nghttp2; @@ -63,23 +64,26 @@ void drop_privileges( neverbleed_t *nb #endif // HAVE_NEVERBLEED ) { + std::array errbuf; auto config = get_config(); if (getuid() == 0 && config->uid != 0) { if (initgroups(config->user.c_str(), config->gid) != 0) { auto error = errno; LOG(FATAL) << "Could not change supplementary groups: " - << strerror(error); + << xsi_strerror(error, errbuf.data(), errbuf.size()); exit(EXIT_FAILURE); } if (setgid(config->gid) != 0) { auto error = errno; - LOG(FATAL) << "Could not change gid: " << strerror(error); + LOG(FATAL) << "Could not change gid: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); exit(EXIT_FAILURE); } if (setuid(config->uid) != 0) { auto error = errno; - LOG(FATAL) << "Could not change uid: " << strerror(error); + LOG(FATAL) << "Could not change uid: " + << xsi_strerror(error, errbuf.data(), errbuf.size()); exit(EXIT_FAILURE); } if (setuid(0) != -1) { @@ -387,6 +391,8 @@ std::random_device rd; } // namespace int worker_process_event_loop(WorkerProcessConfig *wpconf) { + std::array errbuf; + if (reopen_log_files() != 0) { LOG(FATAL) << "Failed to open log file"; return -1; @@ -501,7 +507,8 @@ int worker_process_event_loop(WorkerProcessConfig *wpconf) { rv = pthread_sigmask(SIG_BLOCK, &set, nullptr); if (rv != 0) { - LOG(ERROR) << "Blocking SIGCHLD failed: " << strerror(rv); + LOG(ERROR) << "Blocking SIGCHLD failed: " + << xsi_strerror(rv, errbuf.data(), errbuf.size()); return -1; } #endif // !NOTHREADS @@ -514,7 +521,8 @@ int worker_process_event_loop(WorkerProcessConfig *wpconf) { #ifndef NOTHREADS rv = pthread_sigmask(SIG_UNBLOCK, &set, nullptr); if (rv != 0) { - LOG(ERROR) << "Unblocking SIGCHLD failed: " << strerror(rv); + LOG(ERROR) << "Unblocking SIGCHLD failed: " + << xsi_strerror(rv, errbuf.data(), errbuf.size()); return -1; } #endif // !NOTHREADS diff --git a/src/xsi_strerror.c b/src/xsi_strerror.c new file mode 100644 index 00000000..1796b7dc --- /dev/null +++ b/src/xsi_strerror.c @@ -0,0 +1,50 @@ +/* + * nghttp2 - HTTP/2 C Library + * + * Copyright (c) 2016 Tatsuhiro Tsujikawa + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#include "xsi_strerror.h" + +/* Make sure that we get XSI-compliant version of strerror_r */ +#ifdef _POSIX_C_SOURCE +#undef _POSIX_C_SOURCE +#endif /* _POSIX_C_SOURCE */ + +#ifdef _GNU_SOURCE +#undef _GNU_SOURCE +#endif /* _GNU_SOURCE */ + +#include + +char *xsi_strerror(int errnum, char *buf, size_t buflen) { + int rv; + + rv = strerror_r(errnum, buf, buflen); + + if (rv != 0) { + if (buflen > 0) { + buf[0] = '\0'; + } + } + + return buf; +} diff --git a/src/xsi_strerror.h b/src/xsi_strerror.h new file mode 100644 index 00000000..2476f343 --- /dev/null +++ b/src/xsi_strerror.h @@ -0,0 +1,53 @@ +/* + * nghttp2 - HTTP/2 C Library + * + * Copyright (c) 2016 Tatsuhiro Tsujikawa + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +#ifndef XSI_STRERROR_H +#define XSI_STRERROR_H + +#ifdef HAVE_CONFIG_H +#include +#endif /* HAVE_CONFIG_H */ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* Looks like error message is quite small, but we really don't know + how much longer they become. */ +#define STRERROR_BUFSIZE 256 + +/* + * Returns description of error denoted by |errnum|. The description + * is written in |buf| of length |buflen| including terminal NULL. If + * there is an error, including the case that buffer space is not + * sufficient to include error message, and |buflen| > 0, empty string + * is written to |buf|. This function returns |buf|. + */ +char *xsi_strerror(int errnum, char *buf, unsigned long buflen); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* XSI_STRERROR_H */