// TODO: get rid of this lock using thread-local storage
extern Mutex _dout_lock;
-/* True if we should output high-priority messages to stderr */
-static bool use_stderr = true;
-
//////////////////////// Helper functions //////////////////////////
+// Try a 0-byte write to a file descriptor to see if it open.
+static bool fd_is_open(int fd)
+{
+ char buf;
+ ssize_t res = TEMP_FAILURE_RETRY(write(fd, &buf, 0));
+ return (res == 0);
+}
+
static bool empty(const char *str)
{
if (!str)
}
template <typename charT, typename traits>
-void DoutStreambuf<charT, traits>::set_use_stderr(bool val)
+void DoutStreambuf<charT, traits>::handle_stderr_closed()
{
- _dout_lock.Lock();
- use_stderr = val;
- if (val)
- flags |= DOUTSB_FLAG_STDERR;
- else
- flags &= ~DOUTSB_FLAG_STDERR;
- _dout_lock.Unlock();
+ assert(_dout_lock.is_locked());
+ flags &= ~DOUTSB_FLAG_STDERR;
+}
+
+template <typename charT, typename traits>
+void DoutStreambuf<charT, traits>::handle_stdout_closed()
+{
+ assert(_dout_lock.is_locked());
+ flags &= ~DOUTSB_FLAG_STDOUT;
}
template <typename charT, typename traits>
flags |= DOUTSB_FLAG_SYSLOG;
}
if (g_conf.log_to_stdout) {
- flags |= DOUTSB_FLAG_STDOUT;
+ if (fd_is_open(STDOUT_FILENO)) {
+ flags |= DOUTSB_FLAG_STDOUT;
+ }
}
- if (use_stderr) {
+ if (fd_is_open(STDERR_FILENO)) {
flags |= DOUTSB_FLAG_STDERR;
}
if (g_conf.log_to_file) {
template <typename charT, typename traits>
int DoutStreambuf<charT, traits>::handle_pid_change()
{
- Mutex::Locker l(_dout_lock);
+ assert(_dout_lock.is_locked());
if (!(flags & DOUTSB_FLAG_OFILE))
return 0;
ostringstream oss;
oss << "g_conf.log_to_syslog = " << g_conf.log_to_syslog << "\n";
oss << "g_conf.log_to_stdout = " << g_conf.log_to_stdout << "\n";
- oss << "use_stderr = " << use_stderr << "\n";
oss << "g_conf.log_to_file = " << g_conf.log_to_file << "\n";
oss << "g_conf.log_file = '" << cpp_str(g_conf.log_file) << "'\n";
oss << "g_conf.log_dir = '" << cpp_str(g_conf.log_dir) << "'\n";
assert(ofd == -1);
ofd = open(opath.c_str(),
- O_CREAT | O_WRONLY | O_CLOEXEC | O_APPEND, S_IWUSR | S_IRUSR);
+ O_CREAT | O_WRONLY | O_APPEND, S_IWUSR | S_IRUSR);
if (ofd < 0) {
int err = errno;
ostringstream oss;
DoutStreambuf();
- // Set or clear the use_stderr bit
- // If this bit is cleared, we don't bother outputting high priority messages
- // on stderr any more. We should clear the bit after daemonizing, since
- // stderr -> /dev/null at that point.
- void set_use_stderr(bool val);
+ // Call when you close stderr. Not strictly necessary, since we would get an
+ // error the next time we tried to write to stdedrr. But nicer than waiting
+ // for the error to happen.
+ void handle_stderr_closed();
+
+ // Call when you close stdout.
+ void handle_stdout_closed();
// Set the flags based on the global configuration
void read_global_config();
_dout_need_open = false;
}
-int dout_handle_pid_change() // after calling daemon()
+int dout_handle_daemonize()
{
Mutex::Locker l(_dout_lock);
+ _doss->handle_stdout_closed();
+ _doss->handle_stderr_closed();
return _doss->handle_pid_change();
}
return _doss->create_rank_symlink(n);
}
-void dout_disable_stderr()
-{
- _doss->set_use_stderr(false);
-}
-
void hex2str(const char *s, int len, char *buf, int dest_len)
{
int pos = 0;