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