LCOV - code coverage report
Current view: top level - src - bitcoind.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 77 163 47.2 %
Date: 2021-06-29 14:35:33 Functions: 2 3 66.7 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 37 84 44.0 %

           Branch data     Line data    Source code
#       1                 :            : // Copyright (c) 2009-2010 Satoshi Nakamoto
#       2                 :            : // Copyright (c) 2009-2020 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 <compat.h>
#      13                 :            : #include <init.h>
#      14                 :            : #include <interfaces/chain.h>
#      15                 :            : #include <interfaces/init.h>
#      16                 :            : #include <node/context.h>
#      17                 :            : #include <node/ui_interface.h>
#      18                 :            : #include <noui.h>
#      19                 :            : #include <shutdown.h>
#      20                 :            : #include <util/check.h>
#      21                 :            : #include <util/strencodings.h>
#      22                 :            : #include <util/system.h>
#      23                 :            : #include <util/threadnames.h>
#      24                 :            : #include <util/tokenpipe.h>
#      25                 :            : #include <util/translation.h>
#      26                 :            : #include <util/url.h>
#      27                 :            : 
#      28                 :            : #include <any>
#      29                 :            : #include <functional>
#      30                 :            : #include <optional>
#      31                 :            : 
#      32                 :            : const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr;
#      33                 :            : UrlDecodeFn* const URL_DECODE = urlDecode;
#      34                 :            : 
#      35                 :            : #if HAVE_DECL_FORK
#      36                 :            : 
#      37                 :            : /** Custom implementation of daemon(). This implements the same order of operations as glibc.
#      38                 :            :  * Opens a pipe to the child process to be able to wait for an event to occur.
#      39                 :            :  *
#      40                 :            :  * @returns 0 if successful, and in child process.
#      41                 :            :  *          >0 if successful, and in parent process.
#      42                 :            :  *          -1 in case of error (in parent process).
#      43                 :            :  *
#      44                 :            :  *          In case of success, endpoint will be one end of a pipe from the child to parent process,
#      45                 :            :  *          which can be used with TokenWrite (in the child) or TokenRead (in the parent).
#      46                 :            :  */
#      47                 :            : int fork_daemon(bool nochdir, bool noclose, TokenPipeEnd& endpoint)
#      48                 :          0 : {
#      49                 :            :     // communication pipe with child process
#      50                 :          0 :     std::optional<TokenPipe> umbilical = TokenPipe::Make();
#      51         [ #  # ]:          0 :     if (!umbilical) {
#      52                 :          0 :         return -1; // pipe or pipe2 failed.
#      53                 :          0 :     }
#      54                 :            : 
#      55                 :          0 :     int pid = fork();
#      56         [ #  # ]:          0 :     if (pid < 0) {
#      57                 :          0 :         return -1; // fork failed.
#      58                 :          0 :     }
#      59         [ #  # ]:          0 :     if (pid != 0) {
#      60                 :            :         // Parent process gets read end, closes write end.
#      61                 :          0 :         endpoint = umbilical->TakeReadEnd();
#      62                 :          0 :         umbilical->TakeWriteEnd().Close();
#      63                 :            : 
#      64                 :          0 :         int status = endpoint.TokenRead();
#      65         [ #  # ]:          0 :         if (status != 0) { // Something went wrong while setting up child process.
#      66                 :          0 :             endpoint.Close();
#      67                 :          0 :             return -1;
#      68                 :          0 :         }
#      69                 :            : 
#      70                 :          0 :         return pid;
#      71                 :          0 :     }
#      72                 :            :     // Child process gets write end, closes read end.
#      73                 :          0 :     endpoint = umbilical->TakeWriteEnd();
#      74                 :          0 :     umbilical->TakeReadEnd().Close();
#      75                 :            : 
#      76                 :          0 : #if HAVE_DECL_SETSID
#      77         [ #  # ]:          0 :     if (setsid() < 0) {
#      78                 :          0 :         exit(1); // setsid failed.
#      79                 :          0 :     }
#      80                 :          0 : #endif
#      81                 :            : 
#      82         [ #  # ]:          0 :     if (!nochdir) {
#      83         [ #  # ]:          0 :         if (chdir("/") != 0) {
#      84                 :          0 :             exit(1); // chdir failed.
#      85                 :          0 :         }
#      86                 :          0 :     }
#      87         [ #  # ]:          0 :     if (!noclose) {
#      88                 :            :         // Open /dev/null, and clone it into STDIN, STDOUT and STDERR to detach
#      89                 :            :         // from terminal.
#      90                 :          0 :         int fd = open("/dev/null", O_RDWR);
#      91         [ #  # ]:          0 :         if (fd >= 0) {
#      92 [ #  # ][ #  # ]:          0 :             bool err = dup2(fd, STDIN_FILENO) < 0 || dup2(fd, STDOUT_FILENO) < 0 || dup2(fd, STDERR_FILENO) < 0;
#                 [ #  # ]
#      93                 :            :             // Don't close if fd<=2 to try to handle the case where the program was invoked without any file descriptors open.
#      94         [ #  # ]:          0 :             if (fd > 2) close(fd);
#      95         [ #  # ]:          0 :             if (err) {
#      96                 :          0 :                 exit(1); // dup2 failed.
#      97                 :          0 :             }
#      98                 :          0 :         } else {
#      99                 :          0 :             exit(1); // open /dev/null failed.
#     100                 :          0 :         }
#     101                 :          0 :     }
#     102                 :          0 :     endpoint.TokenWrite(0); // Success
#     103                 :          0 :     return 0;
#     104                 :          0 : }
#     105                 :            : 
#     106                 :            : #endif
#     107                 :            : 
#     108                 :            : static bool AppInit(NodeContext& node, int argc, char* argv[])
#     109                 :        688 : {
#     110                 :        688 :     bool fRet = false;
#     111                 :            : 
#     112                 :        688 :     util::ThreadSetInternalName("init");
#     113                 :            : 
#     114                 :            :     // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
#     115                 :        688 :     SetupServerArgs(node);
#     116                 :        688 :     ArgsManager& args = *Assert(node.args);
#     117                 :        688 :     std::string error;
#     118         [ +  + ]:        688 :     if (!args.ParseParameters(argc, argv, error)) {
#     119                 :          7 :         return InitError(Untranslated(strprintf("Error parsing command line arguments: %s\n", error)));
#     120                 :          7 :     }
#     121                 :            : 
#     122                 :            :     // Process help and version before taking care about datadir
#     123 [ +  + ][ +  + ]:        681 :     if (HelpRequested(args) || args.IsArgSet("-version")) {
#                 [ +  + ]
#     124                 :          2 :         std::string strUsage = PACKAGE_NAME " version " + FormatFullVersion() + "\n";
#     125                 :            : 
#     126         [ +  + ]:          2 :         if (!args.IsArgSet("-version")) {
#     127                 :          1 :             strUsage += FormatParagraph(LicenseInfo()) + "\n"
#     128                 :          1 :                 "\nUsage:  bitcoind [options]                     Start " PACKAGE_NAME "\n"
#     129                 :          1 :                 "\n";
#     130                 :          1 :             strUsage += args.GetHelpMessage();
#     131                 :          1 :         }
#     132                 :            : 
#     133                 :          2 :         tfm::format(std::cout, "%s", strUsage);
#     134                 :          2 :         return true;
#     135                 :          2 :     }
#     136                 :            : 
#     137                 :        679 : #if HAVE_DECL_FORK
#     138                 :            :     // Communication with parent after daemonizing. This is used for signalling in the following ways:
#     139                 :            :     // - a boolean token is sent when the initialization process (all the Init* functions) have finished to indicate
#     140                 :            :     // that the parent process can quit, and whether it was successful/unsuccessful.
#     141                 :            :     // - an unexpected shutdown of the child process creates an unexpected end of stream at the parent
#     142                 :            :     // end, which is interpreted as failure to start.
#     143                 :        679 :     TokenPipeEnd daemon_ep;
#     144                 :        679 : #endif
#     145                 :        679 :     std::any context{&node};
#     146                 :        679 :     try
#     147                 :        679 :     {
#     148         [ +  + ]:        679 :         if (!CheckDataDirOption()) {
#     149                 :          1 :             return InitError(Untranslated(strprintf("Specified data directory \"%s\" does not exist.\n", args.GetArg("-datadir", ""))));
#     150                 :          1 :         }
#     151         [ +  + ]:        678 :         if (!args.ReadConfigFiles(error, true)) {
#     152                 :          7 :             return InitError(Untranslated(strprintf("Error reading configuration file: %s\n", error)));
#     153                 :          7 :         }
#     154                 :            :         // Check for chain settings (Params() calls are only valid after this clause)
#     155                 :        671 :         try {
#     156                 :        671 :             SelectParams(args.GetChainName());
#     157                 :        671 :         } catch (const std::exception& e) {
#     158                 :          0 :             return InitError(Untranslated(strprintf("%s\n", e.what())));
#     159                 :          0 :         }
#     160                 :            : 
#     161                 :            :         // Error out when loose non-argument tokens are encountered on command line
#     162         [ +  + ]:       6668 :         for (int i = 1; i < argc; i++) {
#     163         [ -  + ]:       5997 :             if (!IsSwitchChar(argv[i][0])) {
#     164                 :          0 :                 return InitError(Untranslated(strprintf("Command line contains unexpected token '%s', see bitcoind -h for a list of options.\n", argv[i])));
#     165                 :          0 :             }
#     166                 :       5997 :         }
#     167                 :            : 
#     168         [ +  + ]:        671 :         if (!args.InitSettings(error)) {
#     169                 :          3 :             InitError(Untranslated(error));
#     170                 :          3 :             return false;
#     171                 :          3 :         }
#     172                 :            : 
#     173                 :            :         // -server defaults to true for bitcoind but not for the GUI so do this here
#     174                 :        668 :         args.SoftSetBoolArg("-server", true);
#     175                 :            :         // Set this early so that parameter interactions go to console
#     176                 :        668 :         InitLogging(args);
#     177                 :        668 :         InitParameterInteraction(args);
#     178         [ -  + ]:        668 :         if (!AppInitBasicSetup(args)) {
#     179                 :            :             // InitError will have been called with detailed error, which ends up on console
#     180                 :          0 :             return false;
#     181                 :          0 :         }
#     182         [ +  + ]:        668 :         if (!AppInitParameterInteraction(args)) {
#     183                 :            :             // InitError will have been called with detailed error, which ends up on console
#     184                 :          4 :             return false;
#     185                 :          4 :         }
#     186         [ +  + ]:        664 :         if (!AppInitSanityChecks())
#     187                 :          1 :         {
#     188                 :            :             // InitError will have been called with detailed error, which ends up on console
#     189                 :          1 :             return false;
#     190                 :          1 :         }
#     191 [ -  + ][ -  + ]:        663 :         if (args.GetBoolArg("-daemon", DEFAULT_DAEMON) || args.GetBoolArg("-daemonwait", DEFAULT_DAEMONWAIT)) {
#                 [ -  + ]
#     192                 :          0 : #if HAVE_DECL_FORK
#     193                 :          0 :             tfm::format(std::cout, PACKAGE_NAME " starting\n");
#     194                 :            : 
#     195                 :            :             // Daemonize
#     196                 :          0 :             switch (fork_daemon(1, 0, daemon_ep)) { // don't chdir (1), do close FDs (0)
#     197         [ #  # ]:          0 :             case 0: // Child: continue.
#     198                 :            :                 // If -daemonwait is not enabled, immediately send a success token the parent.
#     199         [ #  # ]:          0 :                 if (!args.GetBoolArg("-daemonwait", DEFAULT_DAEMONWAIT)) {
#     200                 :          0 :                     daemon_ep.TokenWrite(1);
#     201                 :          0 :                     daemon_ep.Close();
#     202                 :          0 :                 }
#     203                 :          0 :                 break;
#     204         [ #  # ]:          0 :             case -1: // Error happened.
#     205                 :          0 :                 return InitError(Untranslated(strprintf("fork_daemon() failed: %s\n", strerror(errno))));
#     206         [ #  # ]:          0 :             default: { // Parent: wait and exit.
#     207                 :          0 :                 int token = daemon_ep.TokenRead();
#     208         [ #  # ]:          0 :                 if (token) { // Success
#     209                 :          0 :                     exit(EXIT_SUCCESS);
#     210                 :          0 :                 } else { // fRet = false or token read error (premature exit).
#     211                 :          0 :                     tfm::format(std::cerr, "Error during initializaton - check debug.log for details\n");
#     212                 :          0 :                     exit(EXIT_FAILURE);
#     213                 :          0 :                 }
#     214                 :          0 :             }
#     215                 :          0 :             }
#     216                 :            : #else
#     217                 :            :             return InitError(Untranslated("-daemon is not supported on this operating system\n"));
#     218                 :            : #endif // HAVE_DECL_FORK
#     219                 :          0 :         }
#     220                 :            :         // Lock data directory after daemonization
#     221         [ -  + ]:        663 :         if (!AppInitLockDataDirectory())
#     222                 :          0 :         {
#     223                 :            :             // If locking the data directory failed, exit immediately
#     224                 :          0 :             return false;
#     225                 :          0 :         }
#     226 [ +  - ][ +  + ]:        663 :         fRet = AppInitInterfaces(node) && AppInitMain(node);
#     227                 :        663 :     }
#     228                 :        679 :     catch (const std::exception& e) {
#     229                 :          0 :         PrintExceptionContinue(&e, "AppInit()");
#     230                 :          0 :     } catch (...) {
#     231                 :          0 :         PrintExceptionContinue(nullptr, "AppInit()");
#     232                 :          0 :     }
#     233                 :            : 
#     234                 :        679 : #if HAVE_DECL_FORK
#     235         [ -  + ]:        679 :     if (daemon_ep.IsOpen()) {
#     236                 :            :         // Signal initialization status to parent, then close pipe.
#     237                 :          0 :         daemon_ep.TokenWrite(fRet);
#     238                 :          0 :         daemon_ep.Close();
#     239                 :          0 :     }
#     240                 :        663 : #endif
#     241         [ +  + ]:        663 :     if (fRet) {
#     242                 :        618 :         WaitForShutdown();
#     243                 :        618 :     }
#     244                 :        663 :     Interrupt(node);
#     245                 :        663 :     Shutdown(node);
#     246                 :            : 
#     247                 :        663 :     return fRet;
#     248                 :        679 : }
#     249                 :            : 
#     250                 :            : int main(int argc, char* argv[])
#     251                 :        688 : {
#     252                 :            : #ifdef WIN32
#     253                 :            :     util::WinCmdLineArgs winArgs;
#     254                 :            :     std::tie(argc, argv) = winArgs.get();
#     255                 :            : #endif
#     256                 :            : 
#     257                 :        688 :     NodeContext node;
#     258                 :        688 :     int exit_status;
#     259                 :        688 :     std::unique_ptr<interfaces::Init> init = interfaces::MakeNodeInit(node, argc, argv, exit_status);
#     260         [ -  + ]:        688 :     if (!init) {
#     261                 :          0 :         return exit_status;
#     262                 :          0 :     }
#     263                 :            : 
#     264                 :        688 :     SetupEnvironment();
#     265                 :            : 
#     266                 :            :     // Connect bitcoind signal handlers
#     267                 :        688 :     noui_connect();
#     268                 :            : 
#     269         [ +  + ]:        688 :     return (AppInit(node, argc, argv) ? EXIT_SUCCESS : EXIT_FAILURE);
#     270                 :        688 : }

Generated by: LCOV version 1.14