Branch data Line data Source code
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>
24 : : #include <util/signalinterrupt.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 : :
35 : : using node::NodeContext;
36 : :
37 : : const TranslateFn G_TRANSLATION_FUN{nullptr};
38 : :
39 : : #if HAVE_DECL_FORK
40 : :
41 : : /** Custom implementation of daemon(). This implements the same order of operations as glibc.
42 : : * Opens a pipe to the child process to be able to wait for an event to occur.
43 : : *
44 : : * @returns 0 if successful, and in child process.
45 : : * >0 if successful, and in parent process.
46 : : * -1 in case of error (in parent process).
47 : : *
48 : : * In case of success, endpoint will be one end of a pipe from the child to parent process,
49 : : * which can be used with TokenWrite (in the child) or TokenRead (in the parent).
50 : : */
51 : 0 : int fork_daemon(bool nochdir, bool noclose, TokenPipeEnd& endpoint)
52 : : {
53 : : // communication pipe with child process
54 : 0 : std::optional<TokenPipe> umbilical = TokenPipe::Make();
55 [ # # ]: 0 : if (!umbilical) {
56 : : return -1; // pipe or pipe2 failed.
57 : : }
58 : :
59 : 0 : int pid = fork();
60 [ # # ]: 0 : if (pid < 0) {
61 : : return -1; // fork failed.
62 : : }
63 [ # # ]: 0 : if (pid != 0) {
64 : : // Parent process gets read end, closes write end.
65 [ # # ]: 0 : endpoint = umbilical->TakeReadEnd();
66 [ # # # # ]: 0 : umbilical->TakeWriteEnd().Close();
67 : :
68 [ # # ]: 0 : int status = endpoint.TokenRead();
69 [ # # ]: 0 : if (status != 0) { // Something went wrong while setting up child process.
70 [ # # ]: 0 : endpoint.Close();
71 : : return -1;
72 : : }
73 : :
74 : : return pid;
75 : : }
76 : : // Child process gets write end, closes read end.
77 [ # # ]: 0 : endpoint = umbilical->TakeWriteEnd();
78 [ # # # # ]: 0 : umbilical->TakeReadEnd().Close();
79 : :
80 : : #if HAVE_DECL_SETSID
81 [ # # ]: 0 : if (setsid() < 0) {
82 : 0 : exit(1); // setsid failed.
83 : : }
84 : : #endif
85 : :
86 [ # # ]: 0 : if (!nochdir) {
87 [ # # ]: 0 : if (chdir("/") != 0) {
88 : 0 : exit(1); // chdir failed.
89 : : }
90 : : }
91 [ # # ]: 0 : if (!noclose) {
92 : : // Open /dev/null, and clone it into STDIN, STDOUT and STDERR to detach
93 : : // from terminal.
94 [ # # ]: 0 : int fd = open("/dev/null", O_RDWR);
95 [ # # ]: 0 : if (fd >= 0) {
96 [ # # # # : 0 : 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 [ # # # # ]: 0 : if (fd > 2) close(fd);
99 [ # # ]: 0 : if (err) {
100 : 0 : exit(1); // dup2 failed.
101 : : }
102 : : } else {
103 : 0 : exit(1); // open /dev/null failed.
104 : : }
105 : : }
106 [ # # ]: 0 : endpoint.TokenWrite(0); // Success
107 : : return 0;
108 : 0 : }
109 : :
110 : : #endif
111 : :
112 : 0 : static bool ParseArgs(NodeContext& node, int argc, char* argv[])
113 : : {
114 : 0 : ArgsManager& args{*Assert(node.args)};
115 : : // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
116 : 0 : SetupServerArgs(args, node.init->canListenIpc());
117 [ # # ]: 0 : std::string error;
118 [ # # # # ]: 0 : if (!args.ParseParameters(argc, argv, error)) {
119 [ # # # # : 0 : return InitError(Untranslated(strprintf("Error parsing command line arguments: %s", error)));
# # ]
120 : : }
121 : :
122 [ # # # # ]: 0 : if (auto error = common::InitConfig(args)) {
123 [ # # ]: 0 : return InitError(error->message, error->details);
124 : 0 : }
125 : :
126 : : // Error out when loose non-argument tokens are encountered on command line
127 [ # # ]: 0 : for (int i = 1; i < argc; i++) {
128 [ # # ]: 0 : if (!IsSwitchChar(argv[i][0])) {
129 [ # # # # : 0 : 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 : 0 : }
134 : :
135 : 0 : static bool ProcessInitCommands(interfaces::Init& init, ArgsManager& args)
136 : : {
137 : : // Process help and version before taking care about datadir
138 [ # # # # : 0 : if (HelpRequested(args) || args.GetBoolArg("-version", false)) {
# # # # ]
139 [ # # ]: 0 : std::string strUsage = CLIENT_NAME " daemon version " + FormatFullVersion();
140 [ # # # # ]: 0 : if (const char* exe_name{init.exeName()}) {
141 [ # # ]: 0 : strUsage += " ";
142 [ # # ]: 0 : strUsage += exe_name;
143 : : }
144 [ # # ]: 0 : strUsage += "\n";
145 : :
146 [ # # # # : 0 : if (args.GetBoolArg("-version", false)) {
# # ]
147 [ # # # # ]: 0 : strUsage += FormatParagraph(LicenseInfo());
148 : : } else {
149 [ # # ]: 0 : 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 : 0 : "\n";
157 [ # # ]: 0 : strUsage += args.GetHelpMessage();
158 : : }
159 : :
160 [ # # ]: 0 : tfm::format(std::cout, "%s", strUsage);
161 : 0 : return true;
162 : 0 : }
163 : :
164 : : return false;
165 : : }
166 : :
167 : 0 : static bool AppInit(NodeContext& node)
168 : : {
169 : 0 : bool fRet = false;
170 : 0 : 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 : 0 : TokenPipeEnd daemon_ep;
179 : : #endif
180 [ # # ]: 0 : std::any context{&node};
181 : 0 : try
182 : : {
183 : : // -server defaults to true for bitcoind but not for the GUI so do this here
184 [ # # # # ]: 0 : args.SoftSetBoolArg("-server", true);
185 : : // Set this early so that parameter interactions go to console
186 [ # # ]: 0 : InitLogging(args);
187 [ # # ]: 0 : InitParameterInteraction(args);
188 [ # # # # ]: 0 : if (!AppInitBasicSetup(args, node.exit_status)) {
189 : : // InitError will have been called with detailed error, which ends up on console
190 : : return false;
191 : : }
192 [ # # # # ]: 0 : if (!AppInitParameterInteraction(args)) {
193 : : // InitError will have been called with detailed error, which ends up on console
194 : : return false;
195 : : }
196 : :
197 [ # # ]: 0 : node.warnings = std::make_unique<node::Warnings>();
198 : :
199 [ # # ]: 0 : node.kernel = std::make_unique<kernel::Context>();
200 [ # # ]: 0 : node.ecc_context = std::make_unique<ECC_Context>();
201 [ # # # # ]: 0 : 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 [ # # # # : 0 : if (args.GetBoolArg("-daemon", DEFAULT_DAEMON) || args.GetBoolArg("-daemonwait", DEFAULT_DAEMONWAIT)) {
# # # # #
# # # # #
# # ]
208 : : #if HAVE_DECL_FORK
209 [ # # ]: 0 : tfm::format(std::cout, CLIENT_NAME " starting\n");
210 : :
211 : : // Daemonize
212 [ # # # # : 0 : switch (fork_daemon(1, 0, daemon_ep)) { // don't chdir (1), do close FDs (0)
# ]
213 : 0 : case 0: // Child: continue.
214 : : // If -daemonwait is not enabled, immediately send a success token the parent.
215 [ # # # # : 0 : if (!args.GetBoolArg("-daemonwait", DEFAULT_DAEMONWAIT)) {
# # ]
216 [ # # ]: 0 : daemon_ep.TokenWrite(1);
217 [ # # ]: 0 : daemon_ep.Close();
218 : : }
219 : : break;
220 : 0 : case -1: // Error happened.
221 [ # # # # : 0 : return InitError(Untranslated(strprintf("fork_daemon() failed: %s", SysErrorString(errno))));
# # # # ]
222 : 0 : default: { // Parent: wait and exit.
223 [ # # ]: 0 : int token = daemon_ep.TokenRead();
224 [ # # ]: 0 : if (token) { // Success
225 : 0 : exit(EXIT_SUCCESS);
226 : : } else { // fRet = false or token read error (premature exit).
227 [ # # ]: 0 : tfm::format(std::cerr, "Error during initialization - check debug.log for details\n");
228 : 0 : 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
237 [ # # # # ]: 0 : if (!AppInitLockDirectories())
238 : : {
239 : : // If locking a directory failed, exit immediately
240 : : return false;
241 : : }
242 [ # # # # : 0 : fRet = AppInitInterfaces(node) && AppInitMain(node);
# # # # ]
243 : : }
244 [ - - ]: 0 : catch (const std::exception& e) {
245 [ - - ]: 0 : PrintExceptionContinue(&e, "AppInit()");
246 : 0 : } catch (...) {
247 [ - - ]: 0 : PrintExceptionContinue(nullptr, "AppInit()");
248 [ - - ]: 0 : }
249 : :
250 : : #if HAVE_DECL_FORK
251 [ # # ]: 0 : if (daemon_ep.IsOpen()) {
252 : : // Signal initialization status to parent, then close pipe.
253 [ # # ]: 0 : daemon_ep.TokenWrite(fRet);
254 [ # # ]: 0 : daemon_ep.Close();
255 : : }
256 : : #endif
257 : : return fRet;
258 : 0 : }
259 : :
260 : 0 : MAIN_FUNCTION
261 : : {
262 : : #ifdef WIN32
263 : : common::WinCmdLineArgs winArgs;
264 : : std::tie(argc, argv) = winArgs.get();
265 : : #endif
266 : :
267 : 0 : NodeContext node;
268 : 0 : int exit_status;
269 [ # # ]: 0 : std::unique_ptr<interfaces::Init> init = interfaces::MakeNodeInit(node, argc, argv, exit_status);
270 [ # # ]: 0 : if (!init) {
271 : 0 : return exit_status;
272 : : }
273 : :
274 [ # # ]: 0 : SetupEnvironment();
275 : :
276 : : // Connect bitcoind signal handlers
277 [ # # ]: 0 : noui_connect();
278 : :
279 [ # # # # ]: 0 : util::ThreadSetInternalName("init");
280 : :
281 : : // Interpret command line arguments
282 [ # # ]: 0 : ArgsManager& args = *Assert(node.args);
283 [ # # # # ]: 0 : if (!ParseArgs(node, argc, argv)) return EXIT_FAILURE;
284 : : // Process early info return commands such as -help or -version
285 [ # # # # ]: 0 : if (ProcessInitCommands(*init, args)) return EXIT_SUCCESS;
286 : :
287 : : // Start application
288 [ # # # # : 0 : if (!AppInit(node) || !Assert(node.shutdown_signal)->wait()) {
# # # # #
# ]
289 : 0 : node.exit_status = EXIT_FAILURE;
290 : : }
291 [ # # ]: 0 : Interrupt(node);
292 [ # # ]: 0 : Shutdown(node);
293 : :
294 : 0 : return node.exit_status;
295 : 0 : }
|