src: Add XSI-compliant version strerror_r

This commit is contained in:
Tatsuhiro Tsujikawa 2016-10-09 19:14:49 +09:00
parent a5d66e71d0
commit 8b64e7b4e1
7 changed files with 217 additions and 55 deletions

View File

@ -112,6 +112,7 @@ if(ENABLE_APP)
shrpx_api_downstream_connection.cc shrpx_api_downstream_connection.cc
shrpx_health_monitor_downstream_connection.cc shrpx_health_monitor_downstream_connection.cc
shrpx_exec.cc shrpx_exec.cc
xsi_strerror.c
) )
if(HAVE_SPDYLAY) if(HAVE_SPDYLAY)
list(APPEND NGHTTPX_SRCS list(APPEND NGHTTPX_SRCS

View File

@ -139,7 +139,8 @@ NGHTTPX_SRCS = \
shrpx_health_monitor_downstream_connection.cc \ shrpx_health_monitor_downstream_connection.cc \
shrpx_health_monitor_downstream_connection.h \ shrpx_health_monitor_downstream_connection.h \
shrpx_exec.cc shrpx_exec.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 if HAVE_SPDYLAY
NGHTTPX_SRCS += shrpx_spdy_upstream.cc shrpx_spdy_upstream.h NGHTTPX_SRCS += shrpx_spdy_upstream.cc shrpx_spdy_upstream.h

View File

@ -88,6 +88,7 @@
#include "template.h" #include "template.h"
#include "allocator.h" #include "allocator.h"
#include "ssl_compat.h" #include "ssl_compat.h"
#include "xsi_strerror.h"
extern char **environ; extern char **environ;
@ -298,6 +299,7 @@ int chown_to_running_user(const char *path) {
namespace { namespace {
int save_pid() { int save_pid() {
std::array<char, STRERROR_BUFSIZE> errbuf;
auto config = get_config(); auto config = get_config();
constexpr auto SUFFIX = StringRef::from_lit(".XXXXXX"); constexpr auto SUFFIX = StringRef::from_lit(".XXXXXX");
@ -317,7 +319,7 @@ int save_pid() {
if (fd == -1) { if (fd == -1) {
auto error = errno; auto error = errno;
LOG(ERROR) << "Could not save PID to file " << pid_file << ": " LOG(ERROR) << "Could not save PID to file " << pid_file << ": "
<< strerror(error); << xsi_strerror(error, errbuf.data(), errbuf.size());
return -1; return -1;
} }
@ -326,14 +328,14 @@ int save_pid() {
if (write(fd, content.c_str(), content.size()) == -1) { if (write(fd, content.c_str(), content.size()) == -1) {
auto error = errno; auto error = errno;
LOG(ERROR) << "Could not save PID to file " << pid_file << ": " LOG(ERROR) << "Could not save PID to file " << pid_file << ": "
<< strerror(error); << xsi_strerror(error, errbuf.data(), errbuf.size());
return -1; return -1;
} }
if (fsync(fd) == -1) { if (fsync(fd) == -1) {
auto error = errno; auto error = errno;
LOG(ERROR) << "Could not save PID to file " << pid_file << ": " LOG(ERROR) << "Could not save PID to file " << pid_file << ": "
<< strerror(error); << xsi_strerror(error, errbuf.data(), errbuf.size());
return -1; return -1;
} }
@ -342,7 +344,7 @@ int save_pid() {
if (rename(temp_path, pid_file.c_str()) == -1) { if (rename(temp_path, pid_file.c_str()) == -1) {
auto error = errno; auto error = errno;
LOG(ERROR) << "Could not save PID to file " << pid_file << ": " LOG(ERROR) << "Could not save PID to file " << pid_file << ": "
<< strerror(error); << xsi_strerror(error, errbuf.data(), errbuf.size());
unlink(temp_path); unlink(temp_path);
@ -352,8 +354,8 @@ int save_pid() {
if (config->uid != 0) { if (config->uid != 0) {
if (chown_to_running_user(pid_file.c_str()) == -1) { if (chown_to_running_user(pid_file.c_str()) == -1) {
auto error = errno; auto error = errno;
LOG(WARN) << "Changing owner of pid file " << pid_file LOG(WARN) << "Changing owner of pid file " << pid_file << " failed: "
<< " failed: " << strerror(error); << xsi_strerror(error, errbuf.data(), errbuf.size());
} }
} }
@ -365,13 +367,15 @@ namespace {
void exec_binary() { void exec_binary() {
int rv; int rv;
sigset_t oldset; sigset_t oldset;
std::array<char, STRERROR_BUFSIZE> errbuf;
LOG(NOTICE) << "Executing new binary"; LOG(NOTICE) << "Executing new binary";
rv = shrpx_signal_block_all(&oldset); rv = shrpx_signal_block_all(&oldset);
if (rv != 0) { if (rv != 0) {
auto error = errno; 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; return;
} }
@ -388,7 +392,8 @@ void exec_binary() {
if (rv != 0) { if (rv != 0) {
auto error = errno; 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); exit(EXIT_FAILURE);
} }
@ -403,7 +408,8 @@ void exec_binary() {
rv = shrpx_signal_unblock_all(); rv = shrpx_signal_unblock_all();
if (rv != 0) { if (rv != 0) {
auto error = errno; 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); _Exit(EXIT_FAILURE);
} }
@ -493,6 +499,7 @@ void exec_binary() {
namespace { namespace {
void ipc_send(WorkerProcess *wp, uint8_t ipc_event) { void ipc_send(WorkerProcess *wp, uint8_t ipc_event) {
std::array<char, STRERROR_BUFSIZE> errbuf;
ssize_t nwrite; ssize_t nwrite;
while ((nwrite = write(wp->ipc_fd, &ipc_event, 1)) == -1 && errno == EINTR) 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) { if (nwrite < 0) {
auto error = errno; auto error = errno;
LOG(ERROR) << "Could not send IPC event to worker process: " LOG(ERROR) << "Could not send IPC event to worker process: "
<< strerror(error); << xsi_strerror(error, errbuf.data(), errbuf.size());
return; return;
} }
@ -569,6 +576,7 @@ void worker_process_child_cb(struct ev_loop *loop, ev_child *w, int revents) {
namespace { namespace {
int create_unix_domain_server_socket(UpstreamAddr &faddr, int create_unix_domain_server_socket(UpstreamAddr &faddr,
std::vector<InheritedAddr> &iaddrs) { std::vector<InheritedAddr> &iaddrs) {
std::array<char, STRERROR_BUFSIZE> errbuf;
auto found = std::find_if( auto found = std::find_if(
std::begin(iaddrs), std::end(iaddrs), [&faddr](const InheritedAddr &ia) { std::begin(iaddrs), std::end(iaddrs), [&faddr](const InheritedAddr &ia) {
return !ia.used && ia.host_unix && ia.host == faddr.host; 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); auto fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0);
if (fd == -1) { if (fd == -1) {
auto error = errno; auto error = errno;
LOG(WARN) << "socket() syscall failed: " << strerror(error); LOG(WARN) << "socket() syscall failed: "
<< xsi_strerror(error, errbuf.data(), errbuf.size());
return -1; return -1;
} }
#else // !SOCK_NONBLOCK #else // !SOCK_NONBLOCK
auto fd = socket(AF_UNIX, SOCK_STREAM, 0); auto fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd == -1) { if (fd == -1) {
auto error = errno; auto error = errno;
LOG(WARN) << "socket() syscall failed: " << strerror(error); LOG(WARN) << "socket() syscall failed: "
<< xsi_strerror(error, errbuf.data(), errbuf.size());
return -1; return -1;
} }
util::make_socket_nonblocking(fd); util::make_socket_nonblocking(fd);
@ -605,7 +615,7 @@ int create_unix_domain_server_socket(UpstreamAddr &faddr,
static_cast<socklen_t>(sizeof(val))) == -1) { static_cast<socklen_t>(sizeof(val))) == -1) {
auto error = errno; auto error = errno;
LOG(WARN) << "Failed to set SO_REUSEADDR option to listener socket: " LOG(WARN) << "Failed to set SO_REUSEADDR option to listener socket: "
<< strerror(error); << xsi_strerror(error, errbuf.data(), errbuf.size());
close(fd); close(fd);
return -1; return -1;
} }
@ -626,7 +636,8 @@ int create_unix_domain_server_socket(UpstreamAddr &faddr,
if (bind(fd, &addr.sa, sizeof(addr.un)) != 0) { if (bind(fd, &addr.sa, sizeof(addr.un)) != 0) {
auto error = errno; 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); close(fd);
return -1; return -1;
} }
@ -635,7 +646,8 @@ int create_unix_domain_server_socket(UpstreamAddr &faddr,
if (listen(fd, listenerconf.backlog) != 0) { if (listen(fd, listenerconf.backlog) != 0) {
auto error = errno; 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); close(fd);
return -1; return -1;
} }
@ -653,6 +665,7 @@ int create_unix_domain_server_socket(UpstreamAddr &faddr,
namespace { namespace {
int create_tcp_server_socket(UpstreamAddr &faddr, int create_tcp_server_socket(UpstreamAddr &faddr,
std::vector<InheritedAddr> &iaddrs) { std::vector<InheritedAddr> &iaddrs) {
std::array<char, STRERROR_BUFSIZE> errbuf;
int fd = -1; int fd = -1;
int rv; 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); socket(rp->ai_family, rp->ai_socktype | SOCK_NONBLOCK, rp->ai_protocol);
if (fd == -1) { if (fd == -1) {
auto error = errno; auto error = errno;
LOG(WARN) << "socket() syscall failed: " << strerror(error); LOG(WARN) << "socket() syscall failed: "
<< xsi_strerror(error, errbuf.data(), errbuf.size());
continue; continue;
} }
#else // !SOCK_NONBLOCK #else // !SOCK_NONBLOCK
fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
if (fd == -1) { if (fd == -1) {
auto error = errno; auto error = errno;
LOG(WARN) << "socket() syscall failed: " << strerror(error); LOG(WARN) << "socket() syscall failed: "
<< xsi_strerror(error, errbuf.data(), errbuf.size());
continue; continue;
} }
util::make_socket_nonblocking(fd); util::make_socket_nonblocking(fd);
@ -730,7 +745,7 @@ int create_tcp_server_socket(UpstreamAddr &faddr,
static_cast<socklen_t>(sizeof(val))) == -1) { static_cast<socklen_t>(sizeof(val))) == -1) {
auto error = errno; auto error = errno;
LOG(WARN) << "Failed to set SO_REUSEADDR option to listener socket: " LOG(WARN) << "Failed to set SO_REUSEADDR option to listener socket: "
<< strerror(error); << xsi_strerror(error, errbuf.data(), errbuf.size());
close(fd); close(fd);
continue; continue;
} }
@ -741,7 +756,7 @@ int create_tcp_server_socket(UpstreamAddr &faddr,
static_cast<socklen_t>(sizeof(val))) == -1) { static_cast<socklen_t>(sizeof(val))) == -1) {
auto error = errno; auto error = errno;
LOG(WARN) << "Failed to set IPV6_V6ONLY option to listener socket: " LOG(WARN) << "Failed to set IPV6_V6ONLY option to listener socket: "
<< strerror(error); << xsi_strerror(error, errbuf.data(), errbuf.size());
close(fd); close(fd);
continue; continue;
} }
@ -754,7 +769,7 @@ int create_tcp_server_socket(UpstreamAddr &faddr,
static_cast<socklen_t>(sizeof(val))) == -1) { static_cast<socklen_t>(sizeof(val))) == -1) {
auto error = errno; auto error = errno;
LOG(WARN) << "Failed to set TCP_DEFER_ACCEPT option to listener socket: " 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 #endif // TCP_DEFER_ACCEPT
@ -763,7 +778,8 @@ int create_tcp_server_socket(UpstreamAddr &faddr,
// ports will fail with permission denied error. // ports will fail with permission denied error.
if (bind(fd, rp->ai_addr, rp->ai_addrlen) == -1) { if (bind(fd, rp->ai_addr, rp->ai_addrlen) == -1) {
auto error = errno; auto error = errno;
LOG(WARN) << "bind() syscall failed: " << strerror(error); LOG(WARN) << "bind() syscall failed: "
<< xsi_strerror(error, errbuf.data(), errbuf.size());
close(fd); close(fd);
continue; continue;
} }
@ -774,13 +790,14 @@ int create_tcp_server_socket(UpstreamAddr &faddr,
static_cast<socklen_t>(sizeof(val))) == -1) { static_cast<socklen_t>(sizeof(val))) == -1) {
auto error = errno; auto error = errno;
LOG(WARN) << "Failed to set TCP_FASTOPEN option to listener socket: " 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) { if (listen(fd, listenerconf.backlog) == -1) {
auto error = errno; auto error = errno;
LOG(WARN) << "listen() syscall failed: " << strerror(error); LOG(WARN) << "listen() syscall failed: "
<< xsi_strerror(error, errbuf.data(), errbuf.size());
close(fd); close(fd);
continue; continue;
} }
@ -812,6 +829,7 @@ namespace {
// |config| is usually a current configuration. // |config| is usually a current configuration.
std::vector<InheritedAddr> std::vector<InheritedAddr>
get_inherited_addr_from_config(BlockAllocator &balloc, Config *config) { get_inherited_addr_from_config(BlockAllocator &balloc, Config *config) {
std::array<char, STRERROR_BUFSIZE> errbuf;
int rv; int rv;
auto &listenerconf = config->conn.listener; 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) { if (getsockname(addr.fd, &su.sa, &salen) != 0) {
auto error = errno; auto error = errno;
LOG(WARN) << "getsockname() syscall failed (fd=" << addr.fd LOG(WARN) << "getsockname() syscall failed (fd=" << addr.fd
<< "): " << strerror(error); << "): " << xsi_strerror(error, errbuf.data(), errbuf.size());
continue; continue;
} }
@ -873,6 +891,7 @@ namespace {
// variables. This function handles the old environment variable // variables. This function handles the old environment variable
// names used in 1.7.0 or earlier. // names used in 1.7.0 or earlier.
std::vector<InheritedAddr> get_inherited_addr_from_env(Config *config) { std::vector<InheritedAddr> get_inherited_addr_from_env(Config *config) {
std::array<char, STRERROR_BUFSIZE> errbuf;
int rv; int rv;
std::vector<InheritedAddr> iaddrs; std::vector<InheritedAddr> iaddrs;
@ -971,7 +990,7 @@ std::vector<InheritedAddr> get_inherited_addr_from_env(Config *config) {
if (getsockname(fd, &su.sa, &salen) != 0) { if (getsockname(fd, &su.sa, &salen) != 0) {
auto error = errno; auto error = errno;
LOG(WARN) << "getsockname() syscall failed (fd=" << fd LOG(WARN) << "getsockname() syscall failed (fd=" << fd
<< "): " << strerror(error); << "): " << xsi_strerror(error, errbuf.data(), errbuf.size());
close(fd); close(fd);
continue; continue;
} }
@ -1033,6 +1052,7 @@ void close_unused_inherited_addr(const std::vector<InheritedAddr> &iaddrs) {
namespace { namespace {
int create_acceptor_socket(Config *config, std::vector<InheritedAddr> &iaddrs) { int create_acceptor_socket(Config *config, std::vector<InheritedAddr> &iaddrs) {
std::array<char, STRERROR_BUFSIZE> errbuf;
auto &listenerconf = config->conn.listener; auto &listenerconf = config->conn.listener;
for (auto &addr : listenerconf.addrs) { for (auto &addr : listenerconf.addrs) {
@ -1047,7 +1067,8 @@ int create_acceptor_socket(Config *config, std::vector<InheritedAddr> &iaddrs) {
if (chown_to_running_user(addr.host.c_str()) == -1) { if (chown_to_running_user(addr.host.c_str()) == -1) {
auto error = errno; auto error = errno;
LOG(WARN) << "Changing owner of UNIX domain socket " << addr.host LOG(WARN) << "Changing owner of UNIX domain socket " << addr.host
<< " failed: " << strerror(error); << " failed: "
<< xsi_strerror(error, errbuf.data(), errbuf.size());
} }
} }
continue; continue;
@ -1078,13 +1099,14 @@ namespace {
// messages to the worker process. On success, ipc_fd[0] is for // messages to the worker process. On success, ipc_fd[0] is for
// reading, and ipc_fd[1] for writing, just like pipe(2). // reading, and ipc_fd[1] for writing, just like pipe(2).
int create_ipc_socket(std::array<int, 2> &ipc_fd) { int create_ipc_socket(std::array<int, 2> &ipc_fd) {
std::array<char, STRERROR_BUFSIZE> errbuf;
int rv; int rv;
rv = pipe(ipc_fd.data()); rv = pipe(ipc_fd.data());
if (rv == -1) { if (rv == -1) {
auto error = errno; auto error = errno;
LOG(WARN) << "Failed to create pipe to communicate worker process: " LOG(WARN) << "Failed to create pipe to communicate worker process: "
<< strerror(error); << xsi_strerror(error, errbuf.data(), errbuf.size());
return -1; return -1;
} }
@ -1106,6 +1128,7 @@ namespace {
// used in the current configuration. // used in the current configuration.
pid_t fork_worker_process(int &main_ipc_fd, pid_t fork_worker_process(int &main_ipc_fd,
const std::vector<InheritedAddr> &iaddrs) { const std::vector<InheritedAddr> &iaddrs) {
std::array<char, STRERROR_BUFSIZE> errbuf;
int rv; int rv;
sigset_t oldset; sigset_t oldset;
@ -1119,7 +1142,8 @@ pid_t fork_worker_process(int &main_ipc_fd,
rv = shrpx_signal_block_all(&oldset); rv = shrpx_signal_block_all(&oldset);
if (rv != 0) { if (rv != 0) {
auto error = errno; 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[0]);
close(ipc_fd[1]); close(ipc_fd[1]);
@ -1143,7 +1167,8 @@ pid_t fork_worker_process(int &main_ipc_fd,
rv = shrpx_signal_unblock_all(); rv = shrpx_signal_unblock_all();
if (rv != 0) { if (rv != 0) {
auto error = errno; 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); _Exit(EXIT_FAILURE);
} }
@ -1166,13 +1191,15 @@ pid_t fork_worker_process(int &main_ipc_fd,
// parent process // parent process
if (pid == -1) { if (pid == -1) {
auto error = errno; 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); rv = shrpx_signal_set(&oldset);
if (rv != 0) { if (rv != 0) {
auto error = errno; 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); exit(EXIT_FAILURE);
} }
@ -1196,6 +1223,8 @@ pid_t fork_worker_process(int &main_ipc_fd,
namespace { namespace {
int event_loop() { int event_loop() {
std::array<char, STRERROR_BUFSIZE> errbuf;
shrpx_signal_set_master_proc_ign_handler(); shrpx_signal_set_master_proc_ign_handler();
auto config = mod_config(); auto config = mod_config();
@ -1203,7 +1232,8 @@ int event_loop() {
if (config->daemon) { if (config->daemon) {
if (call_daemon() == -1) { if (call_daemon() == -1) {
auto error = errno; auto error = errno;
LOG(FATAL) << "Failed to daemonize: " << strerror(error); LOG(FATAL) << "Failed to daemonize: "
<< xsi_strerror(error, errbuf.data(), errbuf.size());
return -1; return -1;
} }
@ -2398,6 +2428,7 @@ Misc:
namespace { namespace {
int process_options(Config *config, int process_options(Config *config,
std::vector<std::pair<StringRef, StringRef>> &cmdcfgs) { std::vector<std::pair<StringRef, StringRef>> &cmdcfgs) {
std::array<char, STRERROR_BUFSIZE> errbuf;
if (conf_exists(config->conf_path.c_str())) { if (conf_exists(config->conf_path.c_str())) {
std::set<StringRef> include_set; std::set<StringRef> include_set;
if (load_config(config, config->conf_path.c_str(), include_set) == -1) { 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) { fchown(log_config()->accesslog_fd, config->uid, config->gid) == -1) {
auto error = errno; auto error = errno;
LOG(WARN) << "Changing owner of access log file failed: " LOG(WARN) << "Changing owner of access log file failed: "
<< strerror(error); << xsi_strerror(error, errbuf.data(), errbuf.size());
} }
if (log_config()->errorlog_fd != -1 && if (log_config()->errorlog_fd != -1 &&
fchown(log_config()->errorlog_fd, config->uid, config->gid) == -1) { fchown(log_config()->errorlog_fd, config->uid, config->gid) == -1) {
auto error = errno; auto error = errno;
LOG(WARN) << "Changing owner of error log file failed: " 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) { if (chown_to_running_user(path) == -1) {
auto error = errno; auto error = errno;
LOG(WARN) << "Changing owner of http2 upstream request header file " 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) { if (chown_to_running_user(path) == -1) {
auto error = errno; auto error = errno;
LOG(WARN) << "Changing owner of http2 upstream response header file" 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<rlim_t>(config->rlimit_nofile)}; static_cast<rlim_t>(config->rlimit_nofile)};
if (setrlimit(RLIMIT_NOFILE, &lim) != 0) { if (setrlimit(RLIMIT_NOFILE, &lim) != 0) {
auto error = errno; 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 main(int argc, char **argv) {
int rv; int rv;
std::array<char, STRERROR_BUFSIZE> errbuf;
nghttp2::ssl::libssl_init(); nghttp2::ssl::libssl_init();
@ -2768,7 +2803,8 @@ int main(int argc, char **argv) {
suconfig.argv[i] = strdup(argv[i]); suconfig.argv[i] = strdup(argv[i]);
if (suconfig.argv[i] == nullptr) { if (suconfig.argv[i] == nullptr) {
auto error = errno; 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); exit(EXIT_FAILURE);
} }
} }

View File

@ -58,6 +58,7 @@
#include "util.h" #include "util.h"
#include "base64.h" #include "base64.h"
#include "ssl_compat.h" #include "ssl_compat.h"
#include "xsi_strerror.h"
namespace shrpx { namespace shrpx {
@ -225,6 +226,8 @@ read_tls_ticket_key_file(const std::vector<StringRef> &files,
} }
FILE *open_file_for_write(const char *filename) { FILE *open_file_for_write(const char *filename) {
std::array<char, STRERROR_BUFSIZE> errbuf;
#if defined O_CLOEXEC #if defined O_CLOEXEC
auto fd = open(filename, O_WRONLY | O_CLOEXEC | O_CREAT | O_TRUNC, auto fd = open(filename, O_WRONLY | O_CLOEXEC | O_CREAT | O_TRUNC,
S_IRUSR | S_IWUSR); S_IRUSR | S_IWUSR);
@ -237,14 +240,16 @@ FILE *open_file_for_write(const char *filename) {
} }
#endif #endif
if (fd == -1) { if (fd == -1) {
LOG(ERROR) << "Failed to open " << filename auto error = errno;
<< " for writing. Cause: " << strerror(errno); LOG(ERROR) << "Failed to open " << filename << " for writing. Cause: "
<< xsi_strerror(error, errbuf.data(), errbuf.size());
return nullptr; return nullptr;
} }
auto f = fdopen(fd, "wb"); auto f = fdopen(fd, "wb");
if (f == nullptr) { if (f == nullptr) {
LOG(ERROR) << "Failed to open " << filename auto error = errno;
<< " for writing. Cause: " << strerror(errno); LOG(ERROR) << "Failed to open " << filename << " for writing. Cause: "
<< xsi_strerror(error, errbuf.data(), errbuf.size());
return nullptr; return nullptr;
} }
@ -963,6 +968,8 @@ int parse_forwarded_node_type(const StringRef &optarg) {
namespace { namespace {
int parse_error_page(std::vector<ErrorPage> &error_pages, const StringRef &opt, int parse_error_page(std::vector<ErrorPage> &error_pages, const StringRef &opt,
const StringRef &optarg) { const StringRef &optarg) {
std::array<char, STRERROR_BUFSIZE> errbuf;
auto eq = std::find(std::begin(optarg), std::end(optarg), '='); auto eq = std::find(std::begin(optarg), std::end(optarg), '=');
if (eq == std::end(optarg) || eq + 1 == std::end(optarg)) { if (eq == std::end(optarg) || eq + 1 == std::end(optarg)) {
LOG(ERROR) << opt << ": bad value: '" << optarg << "'"; LOG(ERROR) << opt << ": bad value: '" << optarg << "'";
@ -991,7 +998,8 @@ int parse_error_page(std::vector<ErrorPage> &error_pages, const StringRef &opt,
auto fd = open(path.c_str(), O_RDONLY); auto fd = open(path.c_str(), O_RDONLY);
if (fd == -1) { if (fd == -1) {
auto error = errno; auto error = errno;
LOG(ERROR) << opt << ": " << optarg << ": " << strerror(error); LOG(ERROR) << opt << ": " << optarg << ": "
<< xsi_strerror(error, errbuf.data(), errbuf.size());
return -1; return -1;
} }
@ -1002,7 +1010,8 @@ int parse_error_page(std::vector<ErrorPage> &error_pages, const StringRef &opt,
auto n = read(fd, buf.data(), buf.size()); auto n = read(fd, buf.data(), buf.size());
if (n == -1) { if (n == -1) {
auto error = errno; auto error = errno;
LOG(ERROR) << opt << ": " << optarg << ": " << strerror(error); LOG(ERROR) << opt << ": " << optarg << ": "
<< xsi_strerror(error, errbuf.data(), errbuf.size());
return -1; return -1;
} }
if (n == 0) { if (n == 0) {
@ -1068,10 +1077,13 @@ namespace {
// must be NULL-terminated string. // must be NULL-terminated string.
int read_tls_sct_from_dir(std::vector<uint8_t> &dst, const StringRef &opt, int read_tls_sct_from_dir(std::vector<uint8_t> &dst, const StringRef &opt,
const StringRef &dir_path) { const StringRef &dir_path) {
std::array<char, STRERROR_BUFSIZE> errbuf;
auto dir = opendir(dir_path.c_str()); auto dir = opendir(dir_path.c_str());
if (dir == nullptr) { if (dir == nullptr) {
auto error = errno; auto error = errno;
LOG(ERROR) << opt << ": " << dir_path << ": " << strerror(error); LOG(ERROR) << opt << ": " << dir_path << ": "
<< xsi_strerror(error, errbuf.data(), errbuf.size());
return -1; return -1;
} }
@ -1088,7 +1100,7 @@ int read_tls_sct_from_dir(std::vector<uint8_t> &dst, const StringRef &opt,
if (errno != 0) { if (errno != 0) {
auto error = errno; auto error = errno;
LOG(ERROR) << opt << ": failed to read directory " << dir_path << ": " LOG(ERROR) << opt << ": failed to read directory " << dir_path << ": "
<< strerror(error); << xsi_strerror(error, errbuf.data(), errbuf.size());
return -1; return -1;
} }
break; break;
@ -1113,7 +1125,7 @@ int read_tls_sct_from_dir(std::vector<uint8_t> &dst, const StringRef &opt,
if (fd == -1) { if (fd == -1) {
auto error = errno; auto error = errno;
LOG(ERROR) << opt << ": failed to read SCT from " << path << ": " LOG(ERROR) << opt << ": failed to read SCT from " << path << ": "
<< strerror(error); << xsi_strerror(error, errbuf.data(), errbuf.size());
return -1; return -1;
} }
@ -1131,7 +1143,7 @@ int read_tls_sct_from_dir(std::vector<uint8_t> &dst, const StringRef &opt,
if (nread == -1) { if (nread == -1) {
auto error = errno; auto error = errno;
LOG(ERROR) << opt << ": failed to read SCT data from " << path << ": " LOG(ERROR) << opt << ": failed to read SCT data from " << path << ": "
<< strerror(error); << xsi_strerror(error, errbuf.data(), errbuf.size());
return -1; 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, int parse_config(Config *config, int optid, const StringRef &opt,
const StringRef &optarg, std::set<StringRef> &included_set) { const StringRef &optarg, std::set<StringRef> &included_set) {
std::array<char, STRERROR_BUFSIZE> errbuf;
char host[NI_MAXHOST]; char host[NI_MAXHOST];
uint16_t port; uint16_t port;
@ -2304,7 +2317,7 @@ int parse_config(Config *config, int optid, const StringRef &opt,
auto pwd = getpwnam(optarg.c_str()); auto pwd = getpwnam(optarg.c_str());
if (!pwd) { if (!pwd) {
LOG(ERROR) << opt << ": failed to get uid from " << optarg << ": " LOG(ERROR) << opt << ": failed to get uid from " << optarg << ": "
<< strerror(errno); << xsi_strerror(errno, errbuf.data(), errbuf.size());
return -1; return -1;
} }
config->user = make_string_ref(config->balloc, StringRef{pwd->pw_name}); config->user = make_string_ref(config->balloc, StringRef{pwd->pw_name});

View File

@ -52,6 +52,7 @@
#include "util.h" #include "util.h"
#include "app_helper.h" #include "app_helper.h"
#include "template.h" #include "template.h"
#include "xsi_strerror.h"
using namespace nghttp2; using namespace nghttp2;
@ -63,23 +64,26 @@ void drop_privileges(
neverbleed_t *nb neverbleed_t *nb
#endif // HAVE_NEVERBLEED #endif // HAVE_NEVERBLEED
) { ) {
std::array<char, STRERROR_BUFSIZE> errbuf;
auto config = get_config(); auto config = get_config();
if (getuid() == 0 && config->uid != 0) { if (getuid() == 0 && config->uid != 0) {
if (initgroups(config->user.c_str(), config->gid) != 0) { if (initgroups(config->user.c_str(), config->gid) != 0) {
auto error = errno; auto error = errno;
LOG(FATAL) << "Could not change supplementary groups: " LOG(FATAL) << "Could not change supplementary groups: "
<< strerror(error); << xsi_strerror(error, errbuf.data(), errbuf.size());
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
if (setgid(config->gid) != 0) { if (setgid(config->gid) != 0) {
auto error = errno; 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); exit(EXIT_FAILURE);
} }
if (setuid(config->uid) != 0) { if (setuid(config->uid) != 0) {
auto error = errno; 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); exit(EXIT_FAILURE);
} }
if (setuid(0) != -1) { if (setuid(0) != -1) {
@ -387,6 +391,8 @@ std::random_device rd;
} // namespace } // namespace
int worker_process_event_loop(WorkerProcessConfig *wpconf) { int worker_process_event_loop(WorkerProcessConfig *wpconf) {
std::array<char, STRERROR_BUFSIZE> errbuf;
if (reopen_log_files() != 0) { if (reopen_log_files() != 0) {
LOG(FATAL) << "Failed to open log file"; LOG(FATAL) << "Failed to open log file";
return -1; return -1;
@ -501,7 +507,8 @@ int worker_process_event_loop(WorkerProcessConfig *wpconf) {
rv = pthread_sigmask(SIG_BLOCK, &set, nullptr); rv = pthread_sigmask(SIG_BLOCK, &set, nullptr);
if (rv != 0) { if (rv != 0) {
LOG(ERROR) << "Blocking SIGCHLD failed: " << strerror(rv); LOG(ERROR) << "Blocking SIGCHLD failed: "
<< xsi_strerror(rv, errbuf.data(), errbuf.size());
return -1; return -1;
} }
#endif // !NOTHREADS #endif // !NOTHREADS
@ -514,7 +521,8 @@ int worker_process_event_loop(WorkerProcessConfig *wpconf) {
#ifndef NOTHREADS #ifndef NOTHREADS
rv = pthread_sigmask(SIG_UNBLOCK, &set, nullptr); rv = pthread_sigmask(SIG_UNBLOCK, &set, nullptr);
if (rv != 0) { if (rv != 0) {
LOG(ERROR) << "Unblocking SIGCHLD failed: " << strerror(rv); LOG(ERROR) << "Unblocking SIGCHLD failed: "
<< xsi_strerror(rv, errbuf.data(), errbuf.size());
return -1; return -1;
} }
#endif // !NOTHREADS #endif // !NOTHREADS

50
src/xsi_strerror.c Normal file
View File

@ -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 <string.h>
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;
}

53
src/xsi_strerror.h Normal file
View File

@ -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 <config.h>
#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 */