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