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