LCOV - code coverage report
Current view: top level - src - bitcoind.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 0 127 0.0 %
Date: 2026-06-25 07:23:51 Functions: 0 4 0.0 %

          Line data    Source code
       1             : // Copyright (c) 2009-2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2021 The Bitcoin Core developers
       3             : // Copyright (c) 2014-2025 The Dash Core developers
       4             : // Distributed under the MIT software license, see the accompanying
       5             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       6             : 
       7             : #if defined(HAVE_CONFIG_H)
       8             : #include <config/bitcoin-config.h>
       9             : #endif
      10             : 
      11             : #include <chainparams.h>
      12             : #include <clientversion.h>
      13             : #include <common/url.h>
      14             : #include <compat/compat.h>
      15             : #include <init.h>
      16             : #include <interfaces/chain.h>
      17             : #include <interfaces/init.h>
      18             : #include <node/context.h>
      19             : #include <node/interface_ui.h>
      20             : #include <noui.h>
      21             : #include <shutdown.h>
      22             : #include <util/check.h>
      23             : #include <util/syserror.h>
      24             : #include <util/system.h>
      25             : #include <util/strencodings.h>
      26             : #include <util/threadnames.h>
      27             : #include <util/tokenpipe.h>
      28             : #include <util/translation.h>
      29             : #include <stacktraces.h>
      30             : 
      31             : #include <cstdio>
      32             : #include <functional>
      33             : 
      34             : using node::NodeContext;
      35             : 
      36           0 : const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
      37             : UrlDecodeFn* const URL_DECODE = urlDecode;
      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           0 :         return -1; // pipe or pipe2 failed.
      57             :     }
      58             : 
      59           0 :     int pid = fork();
      60           0 :     if (pid < 0) {
      61           0 :         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           0 :             return -1;
      72             :         }
      73             : 
      74           0 :         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           0 :     }
      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           0 :         } else {
     103           0 :             exit(1); // open /dev/null failed.
     104             :         }
     105           0 :     }
     106           0 :     endpoint.TokenWrite(0); // Success
     107           0 :     return 0;
     108           0 : }
     109             : 
     110             : #endif
     111             : 
     112           0 : static bool AppInit(NodeContext& node, int argc, char* argv[])
     113             : {
     114           0 :     bool fRet = false;
     115             : 
     116           0 :     util::ThreadSetInternalName("init");
     117             : 
     118             :     // If Qt is used, parameters/dash.conf are parsed in qt/bitcoin.cpp's main()
     119           0 :     ArgsManager& args = *Assert(node.args);
     120           0 :     SetupServerArgs(args);
     121           0 :     std::string error;
     122           0 :     if (!args.ParseParameters(argc, argv, error)) {
     123           0 :         return InitError(Untranslated(strprintf("Error parsing command line arguments: %s\n", error)));
     124             :     }
     125             : 
     126           0 :     if (args.IsArgSet("-printcrashinfo")) {
     127           0 :         std::cout << GetCrashInfoStrFromSerializedStr(args.GetArg("-printcrashinfo", "")) << std::endl;
     128           0 :         return true;
     129             :     }
     130             : 
     131             :     // Process help and version before taking care about datadir
     132           0 :     if (HelpRequested(args) || args.IsArgSet("-version")) {
     133           0 :         std::string strUsage = PACKAGE_NAME " version " + FormatFullVersion() + "\n";
     134             : 
     135           0 :         if (args.IsArgSet("-version")) {
     136           0 :             strUsage += FormatParagraph(LicenseInfo());
     137           0 :         } else {
     138           0 :             strUsage += "\nUsage:  dashd [options]                     Start " PACKAGE_NAME "\n"
     139             :                 "\n";
     140           0 :             strUsage += args.GetHelpMessage();
     141             :         }
     142             : 
     143           0 :         tfm::format(std::cout, "%s", strUsage);
     144           0 :         return true;
     145           0 :     }
     146             : 
     147           0 :     CoreContext context{node};
     148             : #if HAVE_DECL_FORK
     149             :     // Communication with parent after daemonizing. This is used for signalling in the following ways:
     150             :     // - a boolean token is sent when the initialization process (all the Init* functions) have finished to indicate
     151             :     // that the parent process can quit, and whether it was successful/unsuccessful.
     152             :     // - an unexpected shutdown of the child process creates an unexpected end of stream at the parent
     153             :     // end, which is interpreted as failure to start.
     154           0 :     TokenPipeEnd daemon_ep;
     155             : #endif
     156             :     try
     157             :     {
     158           0 :         if (!CheckDataDirOption()) {
     159           0 :             return InitError(Untranslated(strprintf("Specified data directory \"%s\" does not exist.\n", args.GetArg("-datadir", ""))));
     160             :         }
     161           0 :         if (!args.ReadConfigFiles(error, true)) {
     162           0 :             return InitError(Untranslated(strprintf("Error reading configuration file: %s\n", error)));
     163             :         }
     164             :         // Check for chain settings (Params() calls are only valid after this clause)
     165             :         try {
     166           0 :             SelectParams(args.GetChainName());
     167           0 :         } catch (const std::exception& e) {
     168           0 :             return InitError(Untranslated(strprintf("%s\n", e.what())));
     169           0 :         }
     170             : 
     171             :         // Error out when loose non-argument tokens are encountered on command line
     172           0 :         for (int i = 1; i < argc; i++) {
     173           0 :             if (!IsSwitchChar(argv[i][0])) {
     174           0 :                 return InitError(Untranslated(strprintf("Command line contains unexpected token '%s', see dashd -h for a list of options.\n", argv[i])));
     175             :             }
     176           0 :         }
     177             : 
     178           0 :         if (!gArgs.InitSettings(error)) {
     179           0 :             InitError(Untranslated(error));
     180           0 :             return false;
     181             :         }
     182             : 
     183             :         // -server defaults to true for dashd 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)) {
     189             :             // InitError will have been called with detailed error, which ends up on console
     190           0 :             return false;
     191             :         }
     192           0 :         if (!AppInitParameterInteraction(args)) {
     193             :             // InitError will have been called with detailed error, which ends up on console
     194           0 :             return false;
     195             :         }
     196           0 :         if (!AppInitSanityChecks())
     197             :         {
     198             :             // InitError will have been called with detailed error, which ends up on console
     199           0 :             return false;
     200             :         }
     201           0 :         if (args.GetBoolArg("-daemon", DEFAULT_DAEMON) || args.GetBoolArg("-daemonwait", DEFAULT_DAEMONWAIT)) {
     202             : #if HAVE_DECL_FORK
     203           0 :             tfm::format(std::cout, PACKAGE_NAME " starting\n");
     204             : 
     205             :             // Daemonize
     206           0 :             switch (fork_daemon(1, 0, daemon_ep)) { // don't chdir (1), do close FDs (0)
     207             :             case 0: // Child: continue.
     208             :                 // If -daemonwait is not enabled, immediately send a success token the parent.
     209           0 :                 if (!args.GetBoolArg("-daemonwait", DEFAULT_DAEMONWAIT)) {
     210           0 :                     daemon_ep.TokenWrite(1);
     211           0 :                     daemon_ep.Close();
     212           0 :                 }
     213           0 :                 break;
     214             :             case -1: // Error happened.
     215           0 :                 return InitError(Untranslated(strprintf("fork_daemon() failed: %s\n", SysErrorString(errno))));
     216             :             default: { // Parent: wait and exit.
     217           0 :                 int token = daemon_ep.TokenRead();
     218           0 :                 if (token) { // Success
     219           0 :                     exit(EXIT_SUCCESS);
     220             :                 } else { // fRet = false or token read error (premature exit).
     221           0 :                     tfm::format(std::cerr, "Error during initialization - check debug.log for details\n");
     222           0 :                     exit(EXIT_FAILURE);
     223             :                 }
     224             :             }
     225             :             }
     226             : #else
     227             :             return InitError(Untranslated("-daemon is not supported on this operating system\n"));
     228             : #endif // HAVE_DECL_FORK
     229           0 :         }
     230             :         // Lock data directory after daemonization
     231           0 :         if (!AppInitLockDataDirectory())
     232             :         {
     233             :             // If locking the data directory failed, exit immediately
     234           0 :             return false;
     235             :         }
     236           0 :         fRet = AppInitInterfaces(node) && AppInitMain(node);
     237           0 :     } catch (...) {
     238           0 :         PrintExceptionContinue(std::current_exception(), "AppInit()");
     239           0 :     }
     240             : 
     241             : #if HAVE_DECL_FORK
     242           0 :     if (daemon_ep.IsOpen()) {
     243             :         // Signal initialization status to parent, then close pipe.
     244           0 :         daemon_ep.TokenWrite(fRet);
     245           0 :         daemon_ep.Close();
     246           0 :     }
     247             : #endif
     248           0 :     if (fRet) {
     249           0 :         WaitForShutdown();
     250           0 :     }
     251           0 :     Interrupt(node);
     252           0 :     Shutdown(node);
     253             : 
     254           0 :     return fRet;
     255           0 : }
     256             : 
     257           0 : MAIN_FUNCTION
     258             : {
     259           0 :     RegisterPrettyTerminateHander();
     260           0 :     RegisterPrettySignalHandlers();
     261             : 
     262             : #ifdef WIN32
     263             :     util::WinCmdLineArgs winArgs;
     264             :     std::tie(argc, argv) = winArgs.get();
     265             : #endif
     266             : 
     267           0 :     NodeContext node;
     268             :     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 dashd signal handlers
     277           0 :     noui_connect();
     278             : 
     279           0 :     return (AppInit(node, argc, argv) ? EXIT_SUCCESS : EXIT_FAILURE);
     280           0 : }

Generated by: LCOV version 1.16