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>
26 #include <util/signalinterrupt.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 37 using node::NodeContext;
38 39 const TranslateFn G_TRANSLATION_FUN{nullptr};
40 41 #if HAVE_DECL_FORK
42 43 /** Custom implementation of daemon(). This implements the same order of operations as glibc.
44 * Opens a pipe to the child process to be able to wait for an event to occur.
45 *
46 * @returns 0 if successful, and in child process.
47 * >0 if successful, and in parent process.
48 * -1 in case of error (in parent process).
49 *
50 * In case of success, endpoint will be one end of a pipe from the child to parent process,
51 * which can be used with TokenWrite (in the child) or TokenRead (in the parent).
52 */
53 int 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 114 static 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 137 static bool ProcessInitCommands(interfaces::Init& init, ArgsManager& args)
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 169 static bool AppInit(NodeContext& node)
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
188 InitLogging(args);
189 InitParameterInteraction(args);
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 }
194 if (!AppInitParameterInteraction(args)) {
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
239 if (!AppInitLockDirectories())
240 {
241 // If locking a directory failed, exit immediately
242 return false;
243 }
244 fRet = AppInitInterfaces(node) && AppInitMain(node);
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 262 /// \anchor main
263 MAIN_FUNCTION
264 {
265 NodeContext node;
266 int exit_status;
267 std::unique_ptr<interfaces::Init> init = interfaces::MakeNodeInit(node, argc, argv, exit_status);
268 if (!init) {
269 return exit_status;
270 }
271 272 SetupEnvironment();
273 274 // Connect bitcoind signal handlers
275 noui_connect();
276 277 util::ThreadSetInternalName("init");
278 279 // Interpret command line arguments
280 ArgsManager& args = *Assert(node.args);
281 if (!ParseArgs(node, argc, argv)) return EXIT_FAILURE;
282 // Process early info return commands such as -help or -version
283 if (ProcessInitCommands(*init, args)) return EXIT_SUCCESS;
284 285 // Start application
286 if (!AppInit(node) || !Assert(node.shutdown_signal)->wait()) {
287 node.exit_status = EXIT_FAILURE;
288 }
289 Interrupt(node);
290 Shutdown(node);
291 292 return node.exit_status;
293 }
294