Bitcoin ABC 0.26.3
P2P Digital Currency
Loading...
Searching...
No Matches
bitcoind.cpp
Go to the documentation of this file.
1// Copyright (c) 2009-2010 Satoshi Nakamoto
2// Copyright (c) 2009-2019 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)
7#include <config/bitcoin-config.h>
8#endif
9
10#include <chainparams.h>
11#include <clientversion.h>
12#include <common/args.h>
13#include <common/system.h>
14#include <compat.h>
15#include <config.h>
16#include <httprpc.h>
17#include <init.h>
18#include <interfaces/chain.h>
19#include <node/context.h>
20#include <node/ui_interface.h>
21#include <noui.h>
22#include <shutdown.h>
23#include <util/check.h>
24#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
35
36const std::function<std::string(const char *)> G_TRANSLATION_FUN = nullptr;
37
38#if HAVE_DECL_FORK
39
54 // communication pipe with child process
55 std::optional<TokenPipe> umbilical = TokenPipe::Make();
56 if (!umbilical) {
57 // pipe or pipe2 failed.
58 return -1;
59 }
60
61 int pid = fork();
62 if (pid < 0) {
63 // fork failed.
64 return -1;
65 }
66 if (pid != 0) {
67 // Parent process gets read end, closes write end.
68 endpoint = umbilical->TakeReadEnd();
69 umbilical->TakeWriteEnd().Close();
70
71 int status = endpoint.TokenRead();
72 // Something went wrong while setting up child process.
73 if (status != 0) {
74 endpoint.Close();
75 return -1;
76 }
77
78 return pid;
79 }
80 // Child process gets write end, closes read end.
81 endpoint = umbilical->TakeWriteEnd();
82 umbilical->TakeReadEnd().Close();
83
84#if HAVE_DECL_SETSID
85 if (setsid() < 0) {
86 // setsid failed.
87 exit(1);
88 }
89#endif
90
91 if (!nochdir) {
92 if (chdir("/") != 0) {
93 // chdir failed.
94 exit(1);
95 }
96 }
97 if (!noclose) {
98 // Open /dev/null, and clone it into STDIN, STDOUT and STDERR to detach
99 // from terminal.
100 int fd = open("/dev/null", O_RDWR);
101 if (fd >= 0) {
102 bool err = dup2(fd, STDIN_FILENO) < 0 ||
103 dup2(fd, STDOUT_FILENO) < 0 ||
104 dup2(fd, STDERR_FILENO) < 0;
105 // Don't close if fd<=2 to try to handle the case where the program
106 // was invoked without any file descriptors open.
107 if (fd > 2) {
108 close(fd);
109 }
110 if (err) {
111 // dup2 failed.
112 exit(1);
113 }
114 } else {
115 // open /dev/null failed.
116 exit(1);
117 }
118 }
119 // Success
120 endpoint.TokenWrite(0);
121 return 0;
122}
123
124#endif
125
127//
128// Start
129//
130static bool AppInit(int argc, char *argv[]) {
131 // FIXME: Ideally, we'd like to build the config here, but that's currently
132 // not possible as the whole application has too many global state. However,
133 // this is a first step.
134 auto &config = const_cast<Config &>(GetConfig());
135
136 RPCServer rpcServer;
137
139 std::any context{&node};
140
141 HTTPRPCRequestProcessor httpRPCRequestProcessor(config, rpcServer, context);
142
143 bool fRet = false;
144
146
147 // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's
148 // main()
150 ArgsManager &args = *Assert(node.args);
151 std::string error;
152 if (!args.ParseParameters(argc, argv, error)) {
153 return InitError(Untranslated(
154 strprintf("Error parsing command line arguments: %s\n", error)));
155 }
156
157 // Process help and version before taking care about datadir
158 if (HelpRequested(args) || args.IsArgSet("-version")) {
159 std::string strUsage =
160 PACKAGE_NAME " version " + FormatFullVersion() + "\n";
161
162 if (args.IsArgSet("-version")) {
164 } else {
165 strUsage += "\nUsage: bitcoind [options] "
166 "Start " PACKAGE_NAME "\n";
167 strUsage += "\n" + args.GetHelpMessage();
168 }
169
170 tfm::format(std::cout, "%s", strUsage);
171 return true;
172 }
173
174#if HAVE_DECL_FORK
175 // Communication with parent after daemonizing. This is used for signalling
176 // in the following ways:
177 // - a boolean token is sent when the initialization process (all the Init*
178 // functions) have finished to indicate that the parent process can quit,
179 // and whether it was successful/unsuccessful.
180 // - an unexpected shutdown of the child process creates an unexpected end
181 // of stream at the parent end, which is interpreted as failure to start.
183#endif
184 try {
185 if (!CheckDataDirOption(args)) {
186 return InitError(Untranslated(
187 strprintf("Specified data directory \"%s\" does not exist.\n",
188 args.GetArg("-datadir", ""))));
189 }
190 if (!args.ReadConfigFiles(error, true)) {
191 return InitError(Untranslated(
192 strprintf("Error reading configuration file: %s\n", error)));
193 }
194 // Check for -chain, -testnet or -regtest parameter (Params() calls are
195 // only valid after this clause)
196 try {
198 } catch (const std::exception &e) {
199 return InitError(Untranslated(strprintf("%s\n", e.what())));
200 }
201
202 // Make sure we create the net-specific data directory early on: if it
203 // is new, this has a side effect of also creating
204 // <datadir>/<net>/wallets/.
205 //
206 // TODO: this should be removed once gArgs.GetDataDirNet() no longer
207 // creates the wallets/ subdirectory. See more info at:
208 // https://reviews.bitcoinabc.org/D3312
210
211 // Error out when loose non-argument tokens are encountered on command
212 // line
213 for (int i = 1; i < argc; i++) {
214 if (!IsSwitchChar(argv[i][0])) {
215 return InitError(Untranslated(
216 strprintf("Command line contains unexpected token '%s', "
217 "see bitcoind -h for a list of options.\n",
218 argv[i])));
219 }
220 }
221
222 if (!args.InitSettings(error)) {
224 return false;
225 }
226
227 // -server defaults to true for bitcoind but not for the GUI so do this
228 // here
229 args.SoftSetBoolArg("-server", true);
230 // Set this early so that parameter interactions go to console
231 InitLogging(args);
233 if (!AppInitBasicSetup(args)) {
234 // InitError will have been called with detailed error, which ends
235 // up on console
236 return false;
237 }
238 if (!AppInitParameterInteraction(config, args)) {
239 // InitError will have been called with detailed error, which ends
240 // up on console
241 return false;
242 }
243 if (!AppInitSanityChecks()) {
244 // InitError will have been called with detailed error, which ends
245 // up on console
246 return false;
247 }
248 if (args.GetBoolArg("-daemon", DEFAULT_DAEMON) ||
249 args.GetBoolArg("-daemonwait", DEFAULT_DAEMONWAIT)) {
250#if HAVE_DECL_FORK
251 tfm::format(std::cout, PACKAGE_NAME " starting\n");
252
253 // Daemonize
254 // don't chdir (1), do close FDs (0)
255 switch (fork_daemon(1, 0, daemon_ep)) {
256 case 0:
257 // Child: continue.
258 // If -daemonwait is not enabled, immediately send a success
259 // token the parent.
260 if (!args.GetBoolArg("-daemonwait", DEFAULT_DAEMONWAIT)) {
261 daemon_ep.TokenWrite(1);
262 daemon_ep.Close();
263 }
264 break;
265 case -1:
266 // Error happened.
268 "fork_daemon() failed: %s\n", SysErrorString(errno))));
269 default: {
270 // Parent: wait and exit.
271 int token = daemon_ep.TokenRead();
272 if (token) {
273 // Success
275 } else {
276 // fRet = false or token read error (premature exit).
277 tfm::format(std::cerr, "Error during initialization - "
278 "check debug.log for details\n");
280 }
281 }
282 }
283#else
284 return InitError(Untranslated(
285 "-daemon is not supported on this operating system\n"));
286#endif // HAVE_DECL_FORK
287 }
288
289 // Lock data directory after daemonization
291 // If locking the data directory failed, exit immediately
292 return false;
293 }
295 AppInitMain(config, rpcServer, httpRPCRequestProcessor, node);
296 } catch (const std::exception &e) {
297 PrintExceptionContinue(&e, "AppInit()");
298 } catch (...) {
299 PrintExceptionContinue(nullptr, "AppInit()");
300 }
301
302#if HAVE_DECL_FORK
303 if (daemon_ep.IsOpen()) {
304 // Signal initialization status to parent, then close pipe.
305 daemon_ep.TokenWrite(fRet);
306 daemon_ep.Close();
307 }
308#endif
309 if (fRet) {
311 }
313 Shutdown(node);
314
315 return fRet;
316}
317
318int main(int argc, char *argv[]) {
319#ifdef WIN32
320 common::WinCmdLineArgs winArgs;
321 std::tie(argc, argv) = winArgs.get();
322#endif
324
325 // Connect bitcoind signal handlers
326 noui_connect();
327
329}
bool HelpRequested(const ArgsManager &args)
Definition args.cpp:732
bool CheckDataDirOption(const ArgsManager &args)
Definition args.cpp:784
ArgsManager gArgs
Definition args.cpp:38
bool IsSwitchChar(char c)
Definition args.h:47
int main(void)
Definition bench.c:157
static bool AppInit(int argc, char *argv[])
Definition bitcoind.cpp:130
const std::function< std::string(const char *)> G_TRANSLATION_FUN
Translate string to current locale using Qt.
Definition bitcoind.cpp:36
void SelectParams(const std::string &network)
Sets the params returned by Params() to those for the given BIP70 chain name.
#define Assert(val)
Identity function.
Definition check.h:84
bool InitSettings(std::string &error)
Read and update settings file with saved settings.
Definition args.cpp:385
bool ParseParameters(int argc, const char *const argv[], std::string &error)
Definition args.cpp:201
fs::path GetDataDirNet() const
Get data directory path with appended network identifier.
Definition args.h:215
std::string GetHelpMessage() const
Get the help string.
Definition args.cpp:653
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
Definition args.cpp:381
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition args.cpp:494
bool SoftSetBoolArg(const std::string &strArg, bool fValue)
Set a boolean argument if it doesn't already have a value.
Definition args.cpp:589
bool ReadConfigFiles(std::string &error, bool ignore_invalid_keys=false)
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition args.cpp:556
std::string GetChainName() const
Looks for -regtest, -testnet and returns the appropriate BIP70 chain name.
Definition args.cpp:793
Class for registering and managing all RPC calls.
Definition server.h:40
One end of a token pipe.
Definition tokenpipe.h:14
static std::optional< TokenPipe > Make()
Create a new pipe.
Definition tokenpipe.cpp:75
std::string FormatFullVersion()
std::string LicenseInfo()
Returns licensing information (for -version)
const Config & GetConfig()
Definition config.cpp:40
void PrintExceptionContinue(const std::exception *pex, const char *pszThread)
Definition exception.cpp:38
void Interrupt(NodeContext &node)
Interrupt threads.
Definition init.cpp:201
void InitLogging(const ArgsManager &args)
Initialize global loggers.
Definition init.cpp:1686
bool AppInitLockDataDirectory()
Lock bitcoin data directory.
Definition init.cpp:2087
void SetupServerArgs(NodeContext &node)
Register all arguments with the ArgsManager.
Definition init.cpp:425
void Shutdown(NodeContext &node)
Definition init.cpp:225
bool AppInitMain(Config &config, RPCServer &rpcServer, HTTPRPCRequestProcessor &httpRPCRequestProcessor, NodeContext &node, interfaces::BlockAndHeaderTipInfo *tip_info)
Bitcoin main initialization.
Definition init.cpp:2109
bool AppInitBasicSetup(const ArgsManager &args)
Initialize bitcoin: Basic context setup.
Definition init.cpp:1713
bool AppInitSanityChecks()
Initialization sanity checks: ecc init, sanity checks, dir lock.
Definition init.cpp:2069
bool AppInitInterfaces(NodeContext &node)
Initialize node and wallet interface pointers.
Definition init.cpp:2099
void InitParameterInteraction(ArgsManager &args)
Parameter interaction: change current parameters depending on various rules.
Definition init.cpp:1552
bool AppInitParameterInteraction(Config &config, const ArgsManager &args)
Initialization: parameter interaction.
Definition init.cpp:1760
static constexpr bool DEFAULT_DAEMON
Default value for -daemon option.
Definition init.h:16
static constexpr bool DEFAULT_DAEMONWAIT
Default value for -daemonwait option.
Definition init.h:18
bool error(const char *fmt, const Args &...args)
Definition logging.h:263
Definition init.h:28
void format(std::ostream &out, const char *fmt, const Args &...args)
Format list of arguments to the stream according to given format string.
void ThreadSetInternalName(std::string &&)
Set the internal (in-memory) name of the current thread only.
void noui_connect()
Connect all bitcoind signal handlers.
Definition noui.cpp:59
T GetRand(T nMax=std::numeric_limits< T >::max()) noexcept
Generate a uniform random integer of type T in the range [0..nMax) nMax defaults to std::numeric_limi...
Definition random.h:85
void WaitForShutdown()
Wait for StartShutdown to be called in any thread.
Definition shutdown.cpp:89
NodeContext struct containing references to chain state and connection state.
Definition context.h:43
std::string SysErrorString(int err)
Return system error string from errno value.
Definition syserror.cpp:14
void SetupEnvironment()
Definition system.cpp:70
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition translation.h:36
bool InitError(const bilingual_str &str)
Show error message.
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.