LCOV - code coverage report
Current view: top level - src - bitcoin.cpp (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 0.0 % 102 0
Test Date: 2025-11-13 04:35:55 Functions: 0.0 % 5 0
Branches: 0.0 % 304 0

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2025 The Bitcoin Core developers
       2                 :             : // Distributed under the MIT software license, see the accompanying
       3                 :             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4                 :             : 
       5                 :             : #include <bitcoin-build-config.h> // IWYU pragma: keep
       6                 :             : 
       7                 :             : #include <clientversion.h>
       8                 :             : #include <common/args.h>
       9                 :             : #include <common/system.h>
      10                 :             : #include <util/fs.h>
      11                 :             : #include <util/exec.h>
      12                 :             : #include <util/strencodings.h>
      13                 :             : #include <util/translation.h>
      14                 :             : 
      15                 :             : #include <iostream>
      16                 :             : #include <string>
      17                 :             : #include <tinyformat.h>
      18                 :             : #include <vector>
      19                 :             : 
      20                 :             : const TranslateFn G_TRANSLATION_FUN{nullptr};
      21                 :             : 
      22                 :             : static constexpr auto HELP_USAGE = R"(Usage: %s [OPTIONS] COMMAND...
      23                 :             : 
      24                 :             : Options:
      25                 :             :   -m, --multiprocess     Run multiprocess binaries bitcoin-node, bitcoin-gui.
      26                 :             :   -M, --monolithic       Run monolithic binaries bitcoind, bitcoin-qt. (Default behavior)
      27                 :             :   -v, --version          Show version information
      28                 :             :   -h, --help             Show full help message
      29                 :             : 
      30                 :             : Commands:
      31                 :             :   gui [ARGS]     Start GUI, equivalent to running 'bitcoin-qt [ARGS]' or 'bitcoin-gui [ARGS]'.
      32                 :             :   node [ARGS]    Start node, equivalent to running 'bitcoind [ARGS]' or 'bitcoin-node [ARGS]'.
      33                 :             :   rpc [ARGS]     Call RPC method, equivalent to running 'bitcoin-cli -named [ARGS]'.
      34                 :             :   wallet [ARGS]  Call wallet command, equivalent to running 'bitcoin-wallet [ARGS]'.
      35                 :             :   tx [ARGS]      Manipulate hex-encoded transactions, equivalent to running 'bitcoin-tx [ARGS]'.
      36                 :             :   help           Show full help message.
      37                 :             : )";
      38                 :             : 
      39                 :             : static constexpr auto HELP_FULL = R"(
      40                 :             : Additional less commonly used commands:
      41                 :             :   bench [ARGS]      Run bench command, equivalent to running 'bench_bitcoin [ARGS]'.
      42                 :             :   chainstate [ARGS] Run bitcoin kernel chainstate util, equivalent to running 'bitcoin-chainstate [ARGS]'.
      43                 :             :   test [ARGS]       Run unit tests, equivalent to running 'test_bitcoin [ARGS]'.
      44                 :             :   test-gui [ARGS]   Run GUI unit tests, equivalent to running 'test_bitcoin-qt [ARGS]'.
      45                 :             : )";
      46                 :             : 
      47                 :             : static constexpr auto HELP_SHORT = R"(
      48                 :             : Run '%s help' to see additional commands (e.g. for testing and debugging).
      49                 :             : )";
      50                 :             : 
      51                 :           0 : struct CommandLine {
      52                 :             :     std::optional<bool> use_multiprocess;
      53                 :             :     bool show_version{false};
      54                 :             :     bool show_help{false};
      55                 :             :     std::string_view command;
      56                 :             :     std::vector<const char*> args;
      57                 :             : };
      58                 :             : 
      59                 :             : CommandLine ParseCommandLine(int argc, char* argv[]);
      60                 :             : bool UseMultiprocess(const CommandLine& cmd);
      61                 :             : static void ExecCommand(const std::vector<const char*>& args, std::string_view argv0);
      62                 :             : 
      63                 :           0 : int main(int argc, char* argv[])
      64                 :             : {
      65                 :           0 :     SetupEnvironment();
      66                 :             : 
      67                 :           0 :     try {
      68         [ #  # ]:           0 :         CommandLine cmd{ParseCommandLine(argc, argv)};
      69         [ #  # ]:           0 :         if (cmd.show_version) {
      70   [ #  #  #  #  :           0 :             tfm::format(std::cout, "%s version %s\n%s", CLIENT_NAME, FormatFullVersion(), FormatParagraph(LicenseInfo()));
             #  #  #  # ]
      71                 :           0 :             return EXIT_SUCCESS;
      72                 :             :         }
      73                 :             : 
      74   [ #  #  #  #  :           0 :         std::string exe_name{fs::PathToString(fs::PathFromString(argv[0]).filename())};
             #  #  #  # ]
      75                 :           0 :         std::vector<const char*> args;
      76   [ #  #  #  # ]:           0 :         if (cmd.show_help || cmd.command.empty()) {
      77         [ #  # ]:           0 :             tfm::format(std::cout, HELP_USAGE, exe_name);
      78         [ #  # ]:           0 :             if (cmd.show_help) {
      79         [ #  # ]:           0 :                 tfm::format(std::cout, HELP_FULL);
      80                 :             :                 return EXIT_SUCCESS;
      81                 :             :             } else {
      82         [ #  # ]:           0 :                 tfm::format(std::cout, HELP_SHORT, exe_name);
      83                 :             :                 return EXIT_FAILURE;
      84                 :             :             }
      85         [ #  # ]:           0 :         } else if (cmd.command == "gui") {
      86   [ #  #  #  #  :           0 :             args.emplace_back(UseMultiprocess(cmd) ? "bitcoin-gui" : "bitcoin-qt");
                   #  # ]
      87         [ #  # ]:           0 :         } else if (cmd.command == "node") {
      88   [ #  #  #  #  :           0 :             args.emplace_back(UseMultiprocess(cmd) ? "bitcoin-node" : "bitcoind");
                   #  # ]
      89         [ #  # ]:           0 :         } else if (cmd.command == "rpc") {
      90         [ #  # ]:           0 :             args.emplace_back("bitcoin-cli");
      91                 :             :             // Since "bitcoin rpc" is a new interface that doesn't need to be
      92                 :             :             // backward compatible, enable -named by default so it is convenient
      93                 :             :             // for callers to use a mix of named and unnamed parameters. Callers
      94                 :             :             // can override this by specifying -nonamed, but should not need to
      95                 :             :             // unless they are passing string values containing '=' characters
      96                 :             :             // as unnamed parameters.
      97         [ #  # ]:           0 :             args.emplace_back("-named");
      98         [ #  # ]:           0 :         } else if (cmd.command == "wallet") {
      99         [ #  # ]:           0 :             args.emplace_back("bitcoin-wallet");
     100         [ #  # ]:           0 :         } else if (cmd.command == "tx") {
     101         [ #  # ]:           0 :             args.emplace_back("bitcoin-tx");
     102         [ #  # ]:           0 :         } else if (cmd.command == "bench") {
     103         [ #  # ]:           0 :             args.emplace_back("bench_bitcoin");
     104         [ #  # ]:           0 :         } else if (cmd.command == "chainstate") {
     105         [ #  # ]:           0 :             args.emplace_back("bitcoin-chainstate");
     106         [ #  # ]:           0 :         } else if (cmd.command == "test") {
     107         [ #  # ]:           0 :             args.emplace_back("test_bitcoin");
     108         [ #  # ]:           0 :         } else if (cmd.command == "test-gui") {
     109         [ #  # ]:           0 :             args.emplace_back("test_bitcoin-qt");
     110         [ #  # ]:           0 :         } else if (cmd.command == "util") {
     111         [ #  # ]:           0 :             args.emplace_back("bitcoin-util");
     112                 :             :         } else {
     113   [ #  #  #  # ]:           0 :             throw std::runtime_error(strprintf("Unrecognized command: '%s'", cmd.command));
     114                 :             :         }
     115         [ #  # ]:           0 :         if (!args.empty()) {
     116         [ #  # ]:           0 :             args.insert(args.end(), cmd.args.begin(), cmd.args.end());
     117         [ #  # ]:           0 :             ExecCommand(args, argv[0]);
     118                 :             :         }
     119         [ #  # ]:           0 :     } catch (const std::exception& e) {
     120         [ -  - ]:           0 :         tfm::format(std::cerr, "Error: %s\nTry '%s --help' for more information.\n", e.what(), argv[0]);
     121                 :           0 :         return EXIT_FAILURE;
     122                 :           0 :     }
     123                 :           0 :     return EXIT_SUCCESS;
     124                 :             : }
     125                 :             : 
     126                 :           0 : CommandLine ParseCommandLine(int argc, char* argv[])
     127                 :             : {
     128                 :           0 :     CommandLine cmd;
     129         [ #  # ]:           0 :     cmd.args.reserve(argc);
     130         [ #  # ]:           0 :     for (int i = 1; i < argc; ++i) {
     131         [ #  # ]:           0 :         std::string_view arg = argv[i];
     132         [ #  # ]:           0 :         if (!cmd.command.empty()) {
     133         [ #  # ]:           0 :             cmd.args.emplace_back(argv[i]);
     134   [ #  #  #  # ]:           0 :         } else if (arg == "-m" || arg == "--multiprocess") {
     135                 :           0 :             cmd.use_multiprocess = true;
     136   [ #  #  #  # ]:           0 :         } else if (arg == "-M" || arg == "--monolithic") {
     137                 :           0 :             cmd.use_multiprocess = false;
     138   [ #  #  #  # ]:           0 :         } else if (arg == "-v" || arg == "--version") {
     139                 :           0 :             cmd.show_version = true;
     140   [ #  #  #  #  :           0 :         } else if (arg == "-h" || arg == "--help" || arg == "help") {
                   #  # ]
     141                 :           0 :             cmd.show_help = true;
     142         [ #  # ]:           0 :         } else if (arg.starts_with("-")) {
     143   [ #  #  #  # ]:           0 :             throw std::runtime_error(strprintf("Unknown option: %s", arg));
     144         [ #  # ]:           0 :         } else if (!arg.empty()) {
     145                 :           0 :             cmd.command = arg;
     146                 :             :         }
     147                 :             :     }
     148                 :           0 :     return cmd;
     149                 :           0 : }
     150                 :             : 
     151                 :           0 : bool UseMultiprocess(const CommandLine& cmd)
     152                 :             : {
     153                 :             :     // If -m or -M options were explicitly specified, there is no need to
     154                 :             :     // further parse arguments to determine which to use.
     155         [ #  # ]:           0 :     if (cmd.use_multiprocess) return *cmd.use_multiprocess;
     156                 :             : 
     157                 :           0 :     ArgsManager args;
     158         [ #  # ]:           0 :     args.SetDefaultFlags(ArgsManager::ALLOW_ANY);
     159         [ #  # ]:           0 :     std::string error_message;
     160         [ #  # ]:           0 :     auto argv{cmd.args};
     161         [ #  # ]:           0 :     argv.insert(argv.begin(), nullptr);
     162   [ #  #  #  #  :           0 :     if (!args.ParseParameters(argv.size(), argv.data(), error_message)) {
                   #  # ]
     163         [ #  # ]:           0 :         tfm::format(std::cerr, "Warning: failed to parse subcommand command line options: %s\n", error_message);
     164                 :             :     }
     165   [ #  #  #  # ]:           0 :     if (!args.ReadConfigFiles(error_message, true)) {
     166         [ #  # ]:           0 :         tfm::format(std::cerr, "Warning: failed to parse subcommand config: %s\n", error_message);
     167                 :             :     }
     168   [ #  #  #  # ]:           0 :     args.SelectConfigNetwork(args.GetChainTypeString());
     169                 :             : 
     170                 :             :     // If any -ipc* options are set these need to be processed by a
     171                 :             :     // multiprocess-capable binary.
     172   [ #  #  #  #  :           0 :     return args.IsArgSet("-ipcbind") || args.IsArgSet("-ipcconnect") || args.IsArgSet("-ipcfd");
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
             #  #  #  #  
                      # ]
     173                 :           0 : }
     174                 :             : 
     175                 :             : //! Execute the specified bitcoind, bitcoin-qt or other command line in `args`
     176                 :             : //! using src, bin and libexec directory paths relative to this executable, where
     177                 :             : //! the path to this executable is specified in `wrapper_argv0`.
     178                 :             : //!
     179                 :             : //! @param args Command line arguments to execute, where first argument should
     180                 :             : //!             be a relative path to a bitcoind, bitcoin-qt or other executable
     181                 :             : //!             that will be located on the PATH or relative to wrapper_argv0.
     182                 :             : //!
     183                 :             : //! @param wrapper_argv0 String containing first command line argument passed to
     184                 :             : //!                      main() to run the current executable. This is used to
     185                 :             : //!                      help determine the path to the current executable and
     186                 :             : //!                      how to look for new executables.
     187                 :             : //
     188                 :             : //! @note This function doesn't currently print anything but can be debugged
     189                 :             : //! from the command line using strace or dtrace like:
     190                 :             : //!
     191                 :             : //!     strace -e trace=execve -s 10000 build/bin/bitcoin ...
     192                 :             : //!     dtrace -n 'proc:::exec-success  /pid == $target/ { trace(curpsinfo->pr_psargs); }' -c ...
     193                 :           0 : static void ExecCommand(const std::vector<const char*>& args, std::string_view wrapper_argv0)
     194                 :             : {
     195                 :             :     // Construct argument string for execvp
     196                 :           0 :     std::vector<const char*> exec_args{args};
     197         [ #  # ]:           0 :     exec_args.emplace_back(nullptr);
     198                 :             : 
     199                 :             :     // Try to call ExecVp with given exe path.
     200                 :           0 :     auto try_exec = [&](fs::path exe_path, bool allow_notfound = true) {
     201         [ #  # ]:           0 :         std::string exe_path_str{fs::PathToString(exe_path)};
     202         [ #  # ]:           0 :         exec_args[0] = exe_path_str.c_str();
     203   [ #  #  #  # ]:           0 :         if (util::ExecVp(exec_args[0], (char*const*)exec_args.data()) == -1) {
     204   [ #  #  #  # ]:           0 :             if (allow_notfound && errno == ENOENT) return false;
     205   [ #  #  #  # ]:           0 :             throw std::system_error(errno, std::system_category(), strprintf("execvp failed to execute '%s'", exec_args[0]));
     206                 :             :         }
     207         [ #  # ]:           0 :         throw std::runtime_error("execvp returned unexpectedly");
     208                 :           0 :     };
     209                 :             : 
     210                 :             :     // Get the wrapper executable path.
     211         [ #  # ]:           0 :     const fs::path wrapper_path{util::GetExePath(wrapper_argv0)};
     212                 :             : 
     213                 :             :     // Try to resolve any symlinks and figure out the directory containing the wrapper executable.
     214         [ #  # ]:           0 :     std::error_code ec;
     215         [ #  # ]:           0 :     auto wrapper_dir{fs::weakly_canonical(wrapper_path, ec)};
     216   [ #  #  #  # ]:           0 :     if (wrapper_dir.empty()) wrapper_dir = wrapper_path; // Restore previous path if weakly_canonical failed.
     217         [ #  # ]:           0 :     wrapper_dir = wrapper_dir.parent_path();
     218                 :             : 
     219                 :             :     // Get path of the executable to be invoked.
     220   [ #  #  #  # ]:           0 :     const fs::path arg0{fs::PathFromString(args[0])};
     221                 :             : 
     222                 :             :     // Decide whether to fall back to the operating system to search for the
     223                 :             :     // specified executable. Avoid doing this if it looks like the wrapper
     224                 :             :     // executable was invoked by path, rather than by search, to avoid
     225                 :             :     // unintentionally launching system executables in a local build.
     226                 :             :     // (https://github.com/bitcoin/bitcoin/pull/31375#discussion_r1861814807)
     227   [ #  #  #  # ]:           0 :     const bool fallback_os_search{!fs::PathFromString(std::string{wrapper_argv0}).has_parent_path()};
     228                 :             : 
     229                 :             :     // If wrapper is installed in a bin/ directory, look for target executable
     230                 :             :     // in libexec/
     231   [ #  #  #  #  :           0 :     (wrapper_dir.filename() == "bin" && try_exec(wrapper_dir.parent_path() / "libexec" / arg0.filename())) ||
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     232                 :             : #ifdef WIN32
     233                 :             :     // Otherwise check the "daemon" subdirectory in a windows install.
     234                 :             :     (!wrapper_dir.empty() && try_exec(wrapper_dir / "daemon" / arg0.filename())) ||
     235                 :             : #endif
     236                 :             :     // Otherwise look for target executable next to current wrapper
     237   [ #  #  #  #  :           0 :     (!wrapper_dir.empty() && try_exec(wrapper_dir / arg0.filename(), fallback_os_search)) ||
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
          #  #  #  #  #  
                   #  # ]
     238                 :             :     // Otherwise just look on the system path.
     239   [ #  #  #  #  :           0 :     (fallback_os_search && try_exec(arg0.filename(), false));
             #  #  #  # ]
     240                 :           0 : }
        

Generated by: LCOV version 2.0-1