Bitcoin Core  31.0.0
P2P Digital Currency
bitcoin.cpp
Go to the documentation of this file.
1 // Copyright (c) 2025-present 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 
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 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 int main(int argc, char* argv[])
64 {
66 
67  try {
68  CommandLine cmd{ParseCommandLine(argc, argv)};
69  if (cmd.show_version) {
70  tfm::format(std::cout, "%s version %s\n%s", CLIENT_NAME, FormatFullVersion(), FormatParagraph(LicenseInfo()));
71  return EXIT_SUCCESS;
72  }
73 
74  std::string exe_name{fs::PathToString(fs::PathFromString(argv[0]).filename())};
75  std::vector<const char*> args;
76  if (cmd.show_help || cmd.command.empty()) {
77  tfm::format(std::cout, HELP_USAGE, exe_name);
78  if (cmd.show_help) {
79  tfm::format(std::cout, HELP_FULL);
80  return EXIT_SUCCESS;
81  } else {
82  tfm::format(std::cout, HELP_SHORT, exe_name);
83  return EXIT_FAILURE;
84  }
85  } else if (cmd.command == "gui") {
86  args.emplace_back(UseMultiprocess(cmd) ? "bitcoin-gui" : "bitcoin-qt");
87  } else if (cmd.command == "node") {
88  args.emplace_back(UseMultiprocess(cmd) ? "bitcoin-node" : "bitcoind");
89  } else if (cmd.command == "rpc") {
90  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 it handles parameters
95  // that contain '=' characters, so -nonamed should rarely be needed.
96  args.emplace_back("-named");
97  } else if (cmd.command == "wallet") {
98  args.emplace_back("bitcoin-wallet");
99  } else if (cmd.command == "tx") {
100  args.emplace_back("bitcoin-tx");
101  } else if (cmd.command == "bench") {
102  args.emplace_back("bench_bitcoin");
103  } else if (cmd.command == "chainstate") {
104  args.emplace_back("bitcoin-chainstate");
105  } else if (cmd.command == "test") {
106  args.emplace_back("test_bitcoin");
107  } else if (cmd.command == "test-gui") {
108  args.emplace_back("test_bitcoin-qt");
109  } else if (cmd.command == "util") {
110  args.emplace_back("bitcoin-util");
111  } else {
112  throw std::runtime_error(strprintf("Unrecognized command: '%s'", cmd.command));
113  }
114  if (!args.empty()) {
115  args.insert(args.end(), cmd.args.begin(), cmd.args.end());
116  ExecCommand(args, argv[0]);
117  }
118  } catch (const std::exception& e) {
119  tfm::format(std::cerr, "Error: %s\nTry '%s --help' for more information.\n", e.what(), argv[0]);
120  return EXIT_FAILURE;
121  }
122  return EXIT_SUCCESS;
123 }
124 
125 CommandLine ParseCommandLine(int argc, char* argv[])
126 {
128  cmd.args.reserve(argc);
129  for (int i = 1; i < argc; ++i) {
130  std::string_view arg = argv[i];
131  if (!cmd.command.empty()) {
132  cmd.args.emplace_back(argv[i]);
133  } else if (arg == "-m" || arg == "--multiprocess") {
134  cmd.use_multiprocess = true;
135  } else if (arg == "-M" || arg == "--monolithic") {
136  cmd.use_multiprocess = false;
137  } else if (arg == "-v" || arg == "--version") {
138  cmd.show_version = true;
139  } else if (arg == "-h" || arg == "--help" || arg == "help") {
140  cmd.show_help = true;
141  } else if (arg.starts_with("-")) {
142  throw std::runtime_error(strprintf("Unknown option: %s", arg));
143  } else if (!arg.empty()) {
144  cmd.command = arg;
145  }
146  }
147  return cmd;
148 }
149 
151 {
152  // If -m or -M options were explicitly specified, there is no need to
153  // further parse arguments to determine which to use.
154  if (cmd.use_multiprocess) return *cmd.use_multiprocess;
155 
158  std::string error_message;
159  auto argv{cmd.args};
160  argv.insert(argv.begin(), nullptr);
161  if (!args.ParseParameters(argv.size(), argv.data(), error_message)) {
162  tfm::format(std::cerr, "Warning: failed to parse subcommand command line options: %s\n", error_message);
163  }
164  if (!args.ReadConfigFiles(error_message, true)) {
165  tfm::format(std::cerr, "Warning: failed to parse subcommand config: %s\n", error_message);
166  }
168 
169  // If any -ipc* options are set these need to be processed by a
170  // multiprocess-capable binary.
171  return args.IsArgSet("-ipcbind") || args.IsArgSet("-ipcconnect") || args.IsArgSet("-ipcfd");
172 }
173 
186 //
192 static void ExecCommand(const std::vector<const char*>& args, std::string_view wrapper_argv0)
193 {
194  // Construct argument string for execvp
195  std::vector<const char*> exec_args{args};
196  exec_args.emplace_back(nullptr);
197 
198  // Try to call ExecVp with given exe path.
199  auto try_exec = [&](fs::path exe_path, bool allow_notfound = true) {
200  std::string exe_path_str{fs::PathToString(exe_path)};
201  exec_args[0] = exe_path_str.c_str();
202  if (util::ExecVp(exec_args[0], (char*const*)exec_args.data()) == -1) {
203  if (allow_notfound && errno == ENOENT) return false;
204  throw std::system_error(errno, std::system_category(), strprintf("execvp failed to execute '%s'", exec_args[0]));
205  }
206  throw std::runtime_error("execvp returned unexpectedly");
207  };
208 
209  // Get the wrapper executable path.
210  const fs::path wrapper_path{util::GetExePath(wrapper_argv0)};
211 
212  // Try to resolve any symlinks and figure out the directory containing the wrapper executable.
213  std::error_code ec;
214  auto wrapper_dir{fs::weakly_canonical(wrapper_path, ec)};
215  if (wrapper_dir.empty()) wrapper_dir = wrapper_path; // Restore previous path if weakly_canonical failed.
216  wrapper_dir = wrapper_dir.parent_path();
217 
218  // Get path of the executable to be invoked.
219  const fs::path arg0{fs::PathFromString(args[0])};
220 
221  // Decide whether to fall back to the operating system to search for the
222  // specified executable. Avoid doing this if it looks like the wrapper
223  // executable was invoked by path, rather than by search, to avoid
224  // unintentionally launching system executables in a local build.
225  // (https://github.com/bitcoin/bitcoin/pull/31375#discussion_r1861814807)
226  const bool fallback_os_search{!fs::PathFromString(std::string{wrapper_argv0}).has_parent_path()};
227 
228  // If wrapper is installed in a bin/ directory, look for target executable
229  // in libexec/
230  (wrapper_dir.filename() == "bin" && try_exec(wrapper_dir.parent_path() / "libexec" / arg0.filename())) ||
231 #ifdef WIN32
232  // Otherwise check the "daemon" subdirectory in a windows install.
233  (!wrapper_dir.empty() && try_exec(wrapper_dir / "daemon" / arg0.filename())) ||
234 #endif
235  // Otherwise look for target executable next to current wrapper
236  (!wrapper_dir.empty() && try_exec(wrapper_dir / arg0.filename(), fallback_os_search)) ||
237  // Otherwise just look on the system path.
238  (fallback_os_search && try_exec(arg0.filename(), false));
239 }
bool ReadConfigFiles(std::string &error, bool ignore_invalid_keys=false)
Definition: config.cpp:122
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
Definition: args.cpp:375
return EXIT_SUCCESS
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
bool UseMultiprocess(const CommandLine &cmd)
Definition: bitcoin.cpp:150
const TranslateFn G_TRANSLATION_FUN
Translate string to current locale using Qt.
Definition: bitcoin.cpp:20
int main(int argc, char *argv[])
Definition: bitcoin.cpp:63
CommandLine ParseCommandLine(int argc, char *argv[])
Definition: bitcoin.cpp:125
void SetDefaultFlags(std::optional< unsigned int >)
Set default flags to return for an unknown arg.
Definition: args.cpp:270
void SelectConfigNetwork(const std::string &network)
Select the network in use.
Definition: args.cpp:171
const auto cmd
SetupEnvironment()
Definition: system.cpp:64
bool ParseParameters(int argc, const char *const argv[], std::string &error)
Definition: args.cpp:177
bool show_help
Definition: bitcoin.cpp:54
std::string LicenseInfo()
Returns licensing information (for -version)
void format(std::ostream &out, FormatStringCheck< sizeof...(Args)> fmt, const Args &... args)
Format list of arguments to the stream according to given format string.
Definition: tinyformat.h:1079
fs::path GetExePath(std::string_view argv0)
Return path to current executable assuming it was invoked with argv0.
Definition: exec.cpp:40
disable validation
Definition: args.h:110
std::string GetChainTypeString() const
Returns the appropriate chain type string from the program arguments.
Definition: args.cpp:815
ArgsManager & args
Definition: bitcoind.cpp:277
std::function< std::string(const char *)> TranslateFn
Translate a message to the native language of the user.
Definition: translation.h:16
std::string FormatParagraph(std::string_view in, size_t width, size_t indent)
Format a paragraph of text to a fixed width, adding spaces for indentation to any added line...
std::string_view command
Definition: bitcoin.cpp:55
static void ExecCommand(const std::vector< const char *> &args, std::string_view argv0)
Execute the specified bitcoind, bitcoin-qt or other command line in args using src, bin and libexec directory paths relative to this executable, where the path to this executable is specified in wrapper_argv0.
Definition: bitcoin.cpp:192
std::vector< const char * > args
Definition: bitcoin.cpp:56
std::string FormatFullVersion()
static constexpr auto HELP_FULL
Definition: bitcoin.cpp:39
static std::string PathToString(const path &path)
Convert path object to a byte string.
Definition: fs.h:157
static constexpr auto HELP_USAGE
Definition: bitcoin.cpp:22
int ExecVp(const char *file, char *const argv[])
Cross-platform wrapper for POSIX execvp function.
Definition: exec.cpp:21
static path PathFromString(const std::string &string)
Convert byte string to path object.
Definition: fs.h:180
static constexpr auto HELP_SHORT
Definition: bitcoin.cpp:47
std::optional< bool > use_multiprocess
Definition: bitcoin.cpp:52
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:33
bool show_version
Definition: bitcoin.cpp:53