Allow daemon to fork on posix systems

This commit is contained in:
Zachary Michaels 2014-06-18 14:05:28 -04:00
parent 31394c78d0
commit ce38a70023
4 changed files with 123 additions and 8 deletions

View File

@ -4,7 +4,10 @@ file(GLOB_RECURSE COMMON common/*)
file(GLOB_RECURSE CRYPTO crypto/*)
file(GLOB_RECURSE CRYPTONOTE_CORE cryptonote_core/*)
file(GLOB_RECURSE CRYPTONOTE_PROTOCOL cryptonote_protocol/*)
file(GLOB_RECURSE DAEMON daemon/*)
file(GLOB_RECURSE DAEMON daemon/*.cpp)
if(WIN32)
list(REMOVE_ITEM DAEMON "daemon/posix_fork.cpp")
endif()
file(GLOB_RECURSE P2P p2p/*)
file(GLOB_RECURSE RPC rpc/*)
file(GLOB_RECURSE SIMPLEWALLET simplewallet/*)

View File

@ -23,9 +23,9 @@ using namespace epee;
#include "rpc/core_rpc_server.h"
#include "cryptonote_protocol/cryptonote_protocol_handler.h"
//#ifndef WIN32
//#include "posix_daemonize.h"
//#endif
#ifndef WIN32
#include "posix_fork.h"
#endif
#ifdef WIN32
#include <crtdbg.h>
@ -166,8 +166,8 @@ int main(int argc, char* argv[])
#ifndef WIN32
if (command_line::arg_present(vm, arg_detach)) {
std::cout << "start daemon" << std::endl;
return 0;
std::cout << "forking to background..." << std::endl;
posix_fork();
}
#endif
@ -225,9 +225,10 @@ int main(int argc, char* argv[])
CHECK_AND_ASSERT_MES(res, 1, "Failed to initialize core");
LOG_PRINT_L0("Core initialized OK");
// start components
if(!command_line::has_arg(vm, arg_console))
// Start handling console input if requested and not detached
if(!command_line::arg_present(vm, arg_console) && !command_line::arg_present(vm, arg_detach))
{
LOG_PRINT_L0("Begin handling console input");
console_command_thread.start();
}

104
src/daemon/posix_fork.cpp Normal file
View File

@ -0,0 +1,104 @@
#include "daemon/posix_fork.h"
#include <cstdlib>
#include <syslog.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
namespace daemonize {
void posix_fork()
{
// Fork the process and have the parent exit. If the process was started
// from a shell, this returns control to the user. Forking a new process is
// also a prerequisite for the subsequent call to setsid().
if (pid_t pid = fork())
{
if (pid > 0)
{
// We're in the parent process and need to exit.
//
// When the exit() function is used, the program terminates without
// invoking local variables' destructors. Only global variables are
// destroyed. As the io_service object is a local variable, this means
// we do not have to call:
//
// io_service.notify_fork(boost::asio::io_service::fork_parent);
//
// However, this line should be added before each call to exit() if
// using a global io_service object. An additional call:
//
// io_service.notify_fork(boost::asio::io_service::fork_prepare);
//
// should also precede the second fork().
exit(0);
}
else
{
syslog(LOG_ERR | LOG_USER, "First fork failed: %m");
exit(1);
}
}
// Make the process a new session leader. This detaches it from the
// terminal.
setsid();
// A process inherits its working directory from its parent. This could be
// on a mounted filesystem, which means that the running daemon would
// prevent this filesystem from being unmounted. Changing to the root
// directory avoids this problem.
chdir("/");
// The file mode creation mask is also inherited from the parent process.
// We don't want to restrict the permissions on files created by the
// daemon, so the mask is cleared.
umask(0);
// A second fork ensures the process cannot acquire a controlling terminal.
if (pid_t pid = fork())
{
if (pid > 0)
{
exit(0);
}
else
{
syslog(LOG_ERR | LOG_USER, "Second fork failed: %m");
exit(1);
}
}
// Close the standard streams. This decouples the daemon from the terminal
// that started it.
close(0);
close(1);
close(2);
// We don't want the daemon to have any standard input.
if (open("/dev/null", O_RDONLY) < 0)
{
syslog(LOG_ERR | LOG_USER, "Unable to open /dev/null: %m");
exit(1);
}
// Send standard output to a log file.
const char* output = "/tmp/bitmonero.daemon.out";
const int flags = O_WRONLY | O_CREAT | O_APPEND;
const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
if (open(output, flags, mode) < 0)
{
syslog(LOG_ERR | LOG_USER, "Unable to open output file %s: %m", output);
exit(1);
}
// Also send standard error to the same log file.
if (dup(1) < 0)
{
syslog(LOG_ERR | LOG_USER, "Unable to dup output descriptor: %m");
exit(1);
}
}
}

7
src/daemon/posix_fork.h Normal file
View File

@ -0,0 +1,7 @@
#pragma once
namespace daemonize {
void posix_fork();
} // namespace daemonize