Bitcoin Core  27.99.0
P2P Digital Currency
bitcoind.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2022 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #if defined(HAVE_CONFIG_H)
8 #endif
9 
10 #include <chainparams.h>
11 #include <clientversion.h>
12 #include <common/args.h>
13 #include <common/init.h>
14 #include <common/system.h>
15 #include <compat/compat.h>
16 #include <init.h>
17 #include <interfaces/chain.h>
18 #include <interfaces/init.h>
19 #include <node/context.h>
20 #include <node/interface_ui.h>
21 #include <noui.h>
22 #include <util/check.h>
23 #include <util/exception.h>
24 #include <util/strencodings.h>
25 #include <util/syserror.h>
26 #include <util/threadnames.h>
27 #include <util/tokenpipe.h>
28 #include <util/translation.h>
29 
30 #include <any>
31 #include <functional>
32 #include <optional>
33 
34 using node::NodeContext;
35 
36 const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
37 
38 #if HAVE_DECL_FORK
39 
50 int fork_daemon(bool nochdir, bool noclose, TokenPipeEnd& endpoint)
51 {
52  // communication pipe with child process
53  std::optional<TokenPipe> umbilical = TokenPipe::Make();
54  if (!umbilical) {
55  return -1; // pipe or pipe2 failed.
56  }
57 
58  int pid = fork();
59  if (pid < 0) {
60  return -1; // fork failed.
61  }
62  if (pid != 0) {
63  // Parent process gets read end, closes write end.
64  endpoint = umbilical->TakeReadEnd();
65  umbilical->TakeWriteEnd().Close();
66 
67  int status = endpoint.TokenRead();
68  if (status != 0) { // Something went wrong while setting up child process.
69  endpoint.Close();
70  return -1;
71  }
72 
73  return pid;
74  }
75  // Child process gets write end, closes read end.
76  endpoint = umbilical->TakeWriteEnd();
77  umbilical->TakeReadEnd().Close();
78 
79 #if HAVE_DECL_SETSID
80  if (setsid() < 0) {
81  exit(1); // setsid failed.
82  }
83 #endif
84 
85  if (!nochdir) {
86  if (chdir("/") != 0) {
87  exit(1); // chdir failed.
88  }
89  }
90  if (!noclose) {
91  // Open /dev/null, and clone it into STDIN, STDOUT and STDERR to detach
92  // from terminal.
93  int fd = open("/dev/null", O_RDWR);
94  if (fd >= 0) {
95  bool err = dup2(fd, STDIN_FILENO) < 0 || dup2(fd, STDOUT_FILENO) < 0 || dup2(fd, STDERR_FILENO) < 0;
96  // Don't close if fd<=2 to try to handle the case where the program was invoked without any file descriptors open.
97  if (fd > 2) close(fd);
98  if (err) {
99  exit(1); // dup2 failed.
100  }
101  } else {
102  exit(1); // open /dev/null failed.
103  }
104  }
105  endpoint.TokenWrite(0); // Success
106  return 0;
107 }
108 
109 #endif
110 
111 static bool ParseArgs(ArgsManager& args, int argc, char* argv[])
112 {
113  // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
115  std::string error;
116  if (!args.ParseParameters(argc, argv, error)) {
117  return InitError(Untranslated(strprintf("Error parsing command line arguments: %s", error)));
118  }
119 
120  if (auto error = common::InitConfig(args)) {
121  return InitError(error->message, error->details);
122  }
123 
124  // Error out when loose non-argument tokens are encountered on command line
125  for (int i = 1; i < argc; i++) {
126  if (!IsSwitchChar(argv[i][0])) {
127  return InitError(Untranslated(strprintf("Command line contains unexpected token '%s', see bitcoind -h for a list of options.", argv[i])));
128  }
129  }
130  return true;
131 }
132 
134 {
135  // Process help and version before taking care about datadir
136  if (HelpRequested(args) || args.IsArgSet("-version")) {
137  std::string strUsage = PACKAGE_NAME " version " + FormatFullVersion() + "\n";
138 
139  if (args.IsArgSet("-version")) {
140  strUsage += FormatParagraph(LicenseInfo());
141  } else {
142  strUsage += "\nUsage: bitcoind [options] Start " PACKAGE_NAME "\n"
143  "\n";
144  strUsage += args.GetHelpMessage();
145  }
146 
147  tfm::format(std::cout, "%s", strUsage);
148  return true;
149  }
150 
151  return false;
152 }
153 
154 static bool AppInit(NodeContext& node)
155 {
156  bool fRet = false;
157  ArgsManager& args = *Assert(node.args);
158 
159 #if HAVE_DECL_FORK
160  // Communication with parent after daemonizing. This is used for signalling in the following ways:
161  // - a boolean token is sent when the initialization process (all the Init* functions) have finished to indicate
162  // that the parent process can quit, and whether it was successful/unsuccessful.
163  // - an unexpected shutdown of the child process creates an unexpected end of stream at the parent
164  // end, which is interpreted as failure to start.
165  TokenPipeEnd daemon_ep;
166 #endif
167  std::any context{&node};
168  try
169  {
170  // -server defaults to true for bitcoind but not for the GUI so do this here
171  args.SoftSetBoolArg("-server", true);
172  // Set this early so that parameter interactions go to console
173  InitLogging(args);
175  if (!AppInitBasicSetup(args, node.exit_status)) {
176  // InitError will have been called with detailed error, which ends up on console
177  return false;
178  }
180  // InitError will have been called with detailed error, which ends up on console
181  return false;
182  }
183 
184  node.kernel = std::make_unique<kernel::Context>();
185  if (!AppInitSanityChecks(*node.kernel))
186  {
187  // InitError will have been called with detailed error, which ends up on console
188  return false;
189  }
190 
191  if (args.GetBoolArg("-daemon", DEFAULT_DAEMON) || args.GetBoolArg("-daemonwait", DEFAULT_DAEMONWAIT)) {
192 #if HAVE_DECL_FORK
193  tfm::format(std::cout, PACKAGE_NAME " starting\n");
194 
195  // Daemonize
196  switch (fork_daemon(1, 0, daemon_ep)) { // don't chdir (1), do close FDs (0)
197  case 0: // Child: continue.
198  // If -daemonwait is not enabled, immediately send a success token the parent.
199  if (!args.GetBoolArg("-daemonwait", DEFAULT_DAEMONWAIT)) {
200  daemon_ep.TokenWrite(1);
201  daemon_ep.Close();
202  }
203  break;
204  case -1: // Error happened.
205  return InitError(Untranslated(strprintf("fork_daemon() failed: %s", SysErrorString(errno))));
206  default: { // Parent: wait and exit.
207  int token = daemon_ep.TokenRead();
208  if (token) { // Success
209  exit(EXIT_SUCCESS);
210  } else { // fRet = false or token read error (premature exit).
211  tfm::format(std::cerr, "Error during initialization - check debug.log for details\n");
212  exit(EXIT_FAILURE);
213  }
214  }
215  }
216 #else
217  return InitError(Untranslated("-daemon is not supported on this operating system"));
218 #endif // HAVE_DECL_FORK
219  }
220  // Lock data directory after daemonization
222  {
223  // If locking the data directory failed, exit immediately
224  return false;
225  }
227  }
228  catch (const std::exception& e) {
229  PrintExceptionContinue(&e, "AppInit()");
230  } catch (...) {
231  PrintExceptionContinue(nullptr, "AppInit()");
232  }
233 
234 #if HAVE_DECL_FORK
235  if (daemon_ep.IsOpen()) {
236  // Signal initialization status to parent, then close pipe.
237  daemon_ep.TokenWrite(fRet);
238  daemon_ep.Close();
239  }
240 #endif
241  return fRet;
242 }
243 
245 {
246 #ifdef WIN32
247  common::WinCmdLineArgs winArgs;
248  std::tie(argc, argv) = winArgs.get();
249 #endif
250 
253  std::unique_ptr<interfaces::Init> init = interfaces::MakeNodeInit(node, argc, argv, exit_status);
254  if (!init) {
255  return exit_status;
256  }
257 
259 
260  // Connect bitcoind signal handlers
261  noui_connect();
262 
264 
265  // Interpret command line arguments
267  if (!ParseArgs(args, argc, argv)) return EXIT_FAILURE;
268  // Process early info return commands such as -help or -version
270 
271  // Start application
272  if (!AppInit(node) || !Assert(node.shutdown)->wait()) {
273  node.exit_status = EXIT_FAILURE;
274  }
277 
278  return node.exit_status;
279 }
bool HelpRequested(const ArgsManager &args)
Definition: args.cpp:659
bool IsSwitchChar(char c)
Definition: args.h:43
#define PACKAGE_NAME
return EXIT_SUCCESS
int exit_status
Definition: bitcoind.cpp:252
static bool ParseArgs(ArgsManager &args, int argc, char *argv[])
Definition: bitcoind.cpp:111
noui_connect()
Definition: noui.cpp:60
ArgsManager & args
Definition: bitcoind.cpp:266
const std::function< std::string(const char *)> G_TRANSLATION_FUN
Translate string to current locale using Qt.
Definition: bitcoind.cpp:36
SetupEnvironment()
Definition: system.cpp:59
static bool AppInit(NodeContext &node)
Definition: bitcoind.cpp:154
Interrupt(node)
Shutdown(node)
static bool ProcessInitCommands(ArgsManager &args)
Definition: bitcoind.cpp:133
MAIN_FUNCTION
Definition: bitcoind.cpp:245
#define Assert(val)
Identity function.
Definition: check.h:77
bool ParseParameters(int argc, const char *const argv[], std::string &error)
Definition: args.cpp:177
std::string GetHelpMessage() const
Get the help string.
Definition: args.cpp:590
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
Definition: args.cpp:369
bool SoftSetBoolArg(const std::string &strArg, bool fValue)
Set a boolean argument if it doesn't already have a value.
Definition: args.cpp:536
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition: args.cpp:505
One end of a token pipe.
Definition: tokenpipe.h:15
bool IsOpen()
Return whether endpoint is open.
Definition: tokenpipe.h:53
int TokenWrite(uint8_t token)
Write token to endpoint.
Definition: tokenpipe.cpp:40
void Close()
Explicit close function.
Definition: tokenpipe.cpp:78
int TokenRead()
Read token from endpoint.
Definition: tokenpipe.cpp:58
static std::optional< TokenPipe > Make()
Create a new pipe.
Definition: tokenpipe.cpp:84
std::string FormatFullVersion()
std::string LicenseInfo()
Returns licensing information (for -version)
void PrintExceptionContinue(const std::exception *pex, std::string_view thread_name)
Definition: exception.cpp:36
void InitLogging(const ArgsManager &args)
Initialize global loggers.
Definition: init.cpp:815
bool AppInitLockDataDirectory()
Lock bitcoin core data directory.
Definition: init.cpp:1099
void SetupServerArgs(ArgsManager &argsman)
Register all arguments with the ArgsManager.
Definition: init.cpp:438
bool AppInitBasicSetup(const ArgsManager &args, std::atomic< int > &exit_status)
Initialize bitcoin core: Basic context setup.
Definition: init.cpp:845
bool AppInitParameterInteraction(const ArgsManager &args)
Initialization: parameter interaction.
Definition: init.cpp:882
bool AppInitInterfaces(NodeContext &node)
Initialize node and wallet interface pointers.
Definition: init.cpp:1111
void InitParameterInteraction(ArgsManager &args)
Parameter interaction: change current parameters depending on various rules.
Definition: init.cpp:723
bool AppInitMain(NodeContext &node, interfaces::BlockAndHeaderTipInfo *tip_info)
Bitcoin core main initialization.
Definition: init.cpp:1117
bool AppInitSanityChecks(const kernel::Context &kernel)
Initialization sanity checks.
Definition: init.cpp:1084
static constexpr bool DEFAULT_DAEMON
Default value for -daemon option.
Definition: init.h:14
static constexpr bool DEFAULT_DAEMONWAIT
Default value for -daemonwait option.
Definition: init.h:16
bool InitError(const bilingual_str &str)
Show error message.
std::optional< ConfigError > InitConfig(ArgsManager &args, SettingsAbortFn settings_abort_fn)
Definition: init.cpp:18
std::unique_ptr< Init > MakeNodeInit(node::NodeContext &node, int argc, char *argv[], int &exit_status)
Return implementation of Init interface for the node process.
Definition: init.h:25
void format(std::ostream &out, const char *fmt, const Args &... args)
Format list of arguments to the stream according to given format string.
Definition: tinyformat.h:1060
void ThreadSetInternalName(std::string &&)
Set the internal (in-memory) name of the current thread only.
Definition: threadnames.cpp:65
NodeContext struct containing references to chain state and connection state.
Definition: context.h:49
std::string SysErrorString(int err)
Return system error string from errno value.
Definition: syserror.cpp:21
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1162
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition: translation.h:48
std::string FormatParagraph(std::string_view in, size_t width, size_t indent)
Format a paragraph of text to a fixed width, adding spaces for indentation to any added line.