Bitcoin Core 30.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#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>
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
36
38
39#if HAVE_DECL_FORK
40
51int 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
112static 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();
140 if (const char* exe_name{init.exeName()}) {
141 strUsage += " ";
142 strUsage += exe_name;
143 }
144 strUsage += "\n";
145
146 if (args.GetBoolArg("-version", false)) {
147 strUsage += FormatParagraph(LicenseInfo());
148 } else {
149 strUsage += "\n"
150 "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"
151 "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"
152 "There is an optional wallet component which provides transaction services.\n\n"
153 "It can be used in a headless environment or as part of a server setup.\n"
154 "\n"
155 "Usage: bitcoind [options]\n"
156 "\n";
157 strUsage += args.GetHelpMessage();
158 }
159
160 tfm::format(std::cout, "%s", strUsage);
161 return true;
162 }
163
164 return false;
165}
166
168{
169 bool fRet = false;
170 ArgsManager& args = *Assert(node.args);
171
172#if HAVE_DECL_FORK
173 // Communication with parent after daemonizing. This is used for signalling in the following ways:
174 // - a boolean token is sent when the initialization process (all the Init* functions) have finished to indicate
175 // that the parent process can quit, and whether it was successful/unsuccessful.
176 // - an unexpected shutdown of the child process creates an unexpected end of stream at the parent
177 // end, which is interpreted as failure to start.
178 TokenPipeEnd daemon_ep;
179#endif
180 std::any context{&node};
181 try
182 {
183 // -server defaults to true for bitcoind but not for the GUI so do this here
184 args.SoftSetBoolArg("-server", true);
185 // Set this early so that parameter interactions go to console
188 if (!AppInitBasicSetup(args, node.exit_status)) {
189 // InitError will have been called with detailed error, which ends up on console
190 return false;
191 }
193 // InitError will have been called with detailed error, which ends up on console
194 return false;
195 }
196
197 node.warnings = std::make_unique<node::Warnings>();
198
199 node.kernel = std::make_unique<kernel::Context>();
200 node.ecc_context = std::make_unique<ECC_Context>();
201 if (!AppInitSanityChecks(*node.kernel))
202 {
203 // InitError will have been called with detailed error, which ends up on console
204 return false;
205 }
206
207 if (args.GetBoolArg("-daemon", DEFAULT_DAEMON) || args.GetBoolArg("-daemonwait", DEFAULT_DAEMONWAIT)) {
208#if HAVE_DECL_FORK
209 tfm::format(std::cout, CLIENT_NAME " starting\n");
210
211 // Daemonize
212 switch (fork_daemon(1, 0, daemon_ep)) { // don't chdir (1), do close FDs (0)
213 case 0: // Child: continue.
214 // If -daemonwait is not enabled, immediately send a success token the parent.
215 if (!args.GetBoolArg("-daemonwait", DEFAULT_DAEMONWAIT)) {
216 daemon_ep.TokenWrite(1);
217 daemon_ep.Close();
218 }
219 break;
220 case -1: // Error happened.
221 return InitError(Untranslated(strprintf("fork_daemon() failed: %s", SysErrorString(errno))));
222 default: { // Parent: wait and exit.
223 int token = daemon_ep.TokenRead();
224 if (token) { // Success
225 exit(EXIT_SUCCESS);
226 } else { // fRet = false or token read error (premature exit).
227 tfm::format(std::cerr, "Error during initialization - check debug.log for details\n");
228 exit(EXIT_FAILURE);
229 }
230 }
231 }
232#else
233 return InitError(Untranslated("-daemon is not supported on this operating system"));
234#endif // HAVE_DECL_FORK
235 }
236 // Lock critical directories after daemonization
238 {
239 // If locking a directory failed, exit immediately
240 return false;
241 }
243 }
244 catch (const std::exception& e) {
245 PrintExceptionContinue(&e, "AppInit()");
246 } catch (...) {
247 PrintExceptionContinue(nullptr, "AppInit()");
248 }
249
250#if HAVE_DECL_FORK
251 if (daemon_ep.IsOpen()) {
252 // Signal initialization status to parent, then close pipe.
253 daemon_ep.TokenWrite(fRet);
254 daemon_ep.Close();
255 }
256#endif
257 return fRet;
258}
259
261{
262#ifdef WIN32
263 common::WinCmdLineArgs winArgs;
264 std::tie(argc, argv) = winArgs.get();
265#endif
266
269 std::unique_ptr<interfaces::Init> init = interfaces::MakeNodeInit(node, argc, argv, exit_status);
270 if (!init) {
271 return exit_status;
272 }
273
275
276 // Connect bitcoind signal handlers
277 noui_connect();
278
280
281 // Interpret command line arguments
283 if (!ParseArgs(node, argc, argv)) return EXIT_FAILURE;
284 // Process early info return commands such as -help or -version
286
287 // Start application
288 if (!AppInit(node) || !Assert(node.shutdown_signal)->wait()) {
289 node.exit_status = EXIT_FAILURE;
290 }
293
294 return node.exit_status;
295}
bool HelpRequested(const ArgsManager &args)
Definition: args.cpp:698
bool IsSwitchChar(char c)
Definition: args.h:43
return EXIT_SUCCESS
int exit_status
Definition: bitcoind.cpp:268
noui_connect()
Definition: noui.cpp:60
ArgsManager & args
Definition: bitcoind.cpp:282
static bool ParseArgs(NodeContext &node, int argc, char *argv[])
Definition: bitcoind.cpp:112
SetupEnvironment()
Definition: system.cpp:65
const TranslateFn G_TRANSLATION_FUN
Translate string to current locale using Qt.
Definition: bitcoind.cpp:37
static bool AppInit(NodeContext &node)
Definition: bitcoind.cpp:167
Interrupt(node)
Shutdown(node)
static bool ProcessInitCommands(interfaces::Init &init, ArgsManager &args)
Definition: bitcoind.cpp:135
MAIN_FUNCTION
Definition: bitcoind.cpp:261
#define Assert(val)
Identity function.
Definition: check.h:106
bool ParseParameters(int argc, const char *const argv[], std::string &error)
Definition: args.cpp:179
std::string GetHelpMessage() const
Get the help string.
Definition: args.cpp:623
bool SoftSetBoolArg(const std::string &strArg, bool fValue)
Set a boolean argument if it doesn't already have a value.
Definition: args.cpp:544
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition: args.cpp:513
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:38
void Close()
Explicit close function.
Definition: tokenpipe.cpp:76
int TokenRead()
Read token from endpoint.
Definition: tokenpipe.cpp:56
static std::optional< TokenPipe > Make()
Create a new pipe.
Definition: tokenpipe.cpp:82
Initial interface created when a process is first started, and used to give and get access to other i...
Definition: init.h:31
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:828
bool AppInitBasicSetup(const ArgsManager &args, std::atomic< int > &exit_status)
Initialize bitcoin core: Basic context setup.
Definition: init.cpp:857
bool AppInitParameterInteraction(const ArgsManager &args)
Initialization: parameter interaction.
Definition: init.cpp:894
bool AppInitInterfaces(NodeContext &node)
Initialize node and wallet interface pointers.
Definition: init.cpp:1176
void InitParameterInteraction(ArgsManager &args)
Parameter interaction: change current parameters depending on various rules.
Definition: init.cpp:739
bool AppInitMain(NodeContext &node, interfaces::BlockAndHeaderTipInfo *tip_info)
Bitcoin core main initialization.
Definition: init.cpp:1391
bool AppInitLockDirectories()
Lock bitcoin core critical directories.
Definition: init.cpp:1164
void SetupServerArgs(ArgsManager &argsman, bool can_listen_ipc)
Register all arguments with the ArgsManager.
Definition: init.cpp:453
bool AppInitSanityChecks(const kernel::Context &kernel)
Initialization sanity checks.
Definition: init.cpp:1145
static constexpr bool DEFAULT_DAEMON
Default value for -daemon option.
Definition: init.h:12
static constexpr bool DEFAULT_DAEMONWAIT
Default value for -daemonwait option.
Definition: init.h:14
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: messages.h:20
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 ThreadSetInternalName(const std::string &)
Set the internal (in-memory) name of the current thread only.
Definition: threadnames.cpp:61
NodeContext struct containing references to chain state and connection state.
Definition: context.h:56
std::string SysErrorString(int err)
Return system error string from errno value.
Definition: syserror.cpp:19
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
std::function< std::string(const char *)> TranslateFn
Translate a message to the native language of the user.
Definition: translation.h:16
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition: translation.h:82
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.