Bitcoin Core 29.99.0
P2P Digital Currency
bitcoin.cpp
Go to the documentation of this file.
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 <util/fs.h>
9#include <util/exec.h>
10#include <util/strencodings.h>
11#include <util/translation.h>
12
13#include <iostream>
14#include <string>
15#include <tinyformat.h>
16#include <vector>
17
19
20static constexpr auto HELP_USAGE = R"(Usage: %s [OPTIONS] COMMAND...
21
22Options:
23 -m, --multiprocess Run multiprocess binaries bitcoin-node, bitcoin-gui.
24 -M, --monolithic Run monolithic binaries bitcoind, bitcoin-qt. (Default behavior)
25 -v, --version Show version information
26 -h, --help Show full help message
27
28Commands:
29 gui [ARGS] Start GUI, equivalent to running 'bitcoin-qt [ARGS]' or 'bitcoin-gui [ARGS]'.
30 node [ARGS] Start node, equivalent to running 'bitcoind [ARGS]' or 'bitcoin-node [ARGS]'.
31 rpc [ARGS] Call RPC method, equivalent to running 'bitcoin-cli -named [ARGS]'.
32 wallet [ARGS] Call wallet command, equivalent to running 'bitcoin-wallet [ARGS]'.
33 tx [ARGS] Manipulate hex-encoded transactions, equivalent to running 'bitcoin-tx [ARGS]'.
34 help Show full help message.
35)";
36
37static constexpr auto HELP_FULL = R"(
38Additional less commonly used commands:
39 bench [ARGS] Run bench command, equivalent to running 'bench_bitcoin [ARGS]'.
40 chainstate [ARGS] Run bitcoin kernel chainstate util, equivalent to running 'bitcoin-chainstate [ARGS]'.
41 test [ARGS] Run unit tests, equivalent to running 'test_bitcoin [ARGS]'.
42 test-gui [ARGS] Run GUI unit tests, equivalent to running 'test_bitcoin-qt [ARGS]'.
43)";
44
45static constexpr auto HELP_SHORT = R"(
46Run '%s help' to see additional commands (e.g. for testing and debugging).
47)";
48
50 bool use_multiprocess{false};
51 bool show_version{false};
52 bool show_help{false};
53 std::string_view command;
54 std::vector<const char*> args;
55};
56
57CommandLine ParseCommandLine(int argc, char* argv[]);
58static void ExecCommand(const std::vector<const char*>& args, std::string_view argv0);
59
60int main(int argc, char* argv[])
61{
62 try {
63 CommandLine cmd{ParseCommandLine(argc, argv)};
64 if (cmd.show_version) {
65 tfm::format(std::cout, "%s version %s\n%s", CLIENT_NAME, FormatFullVersion(), FormatParagraph(LicenseInfo()));
66 return EXIT_SUCCESS;
67 }
68
69 std::string exe_name{fs::PathToString(fs::PathFromString(argv[0]).filename())};
70 std::vector<const char*> args;
71 if (cmd.show_help || cmd.command.empty()) {
72 tfm::format(std::cout, HELP_USAGE, exe_name);
73 if (cmd.show_help) {
74 tfm::format(std::cout, HELP_FULL);
75 return EXIT_SUCCESS;
76 } else {
77 tfm::format(std::cout, HELP_SHORT, exe_name);
78 return EXIT_FAILURE;
79 }
80 } else if (cmd.command == "gui") {
81 args.emplace_back(cmd.use_multiprocess ? "bitcoin-gui" : "bitcoin-qt");
82 } else if (cmd.command == "node") {
83 args.emplace_back(cmd.use_multiprocess ? "bitcoin-node" : "bitcoind");
84 } else if (cmd.command == "rpc") {
85 args.emplace_back("bitcoin-cli");
86 // Since "bitcoin rpc" is a new interface that doesn't need to be
87 // backward compatible, enable -named by default so it is convenient
88 // for callers to use a mix of named and unnamed parameters. Callers
89 // can override this by specifying -nonamed, but should not need to
90 // unless they are passing string values containing '=' characters
91 // as unnamed parameters.
92 args.emplace_back("-named");
93 } else if (cmd.command == "wallet") {
94 args.emplace_back("bitcoin-wallet");
95 } else if (cmd.command == "tx") {
96 args.emplace_back("bitcoin-tx");
97 } else if (cmd.command == "bench") {
98 args.emplace_back("bench_bitcoin");
99 } else if (cmd.command == "chainstate") {
100 args.emplace_back("bitcoin-chainstate");
101 } else if (cmd.command == "test") {
102 args.emplace_back("test_bitcoin");
103 } else if (cmd.command == "test-gui") {
104 args.emplace_back("test_bitcoin-qt");
105 } else if (cmd.command == "util") {
106 args.emplace_back("bitcoin-util");
107 } else {
108 throw std::runtime_error(strprintf("Unrecognized command: '%s'", cmd.command));
109 }
110 if (!args.empty()) {
111 args.insert(args.end(), cmd.args.begin(), cmd.args.end());
112 ExecCommand(args, argv[0]);
113 }
114 } catch (const std::exception& e) {
115 tfm::format(std::cerr, "Error: %s\nTry '%s --help' for more information.\n", e.what(), argv[0]);
116 return EXIT_FAILURE;
117 }
118 return EXIT_SUCCESS;
119}
120
121CommandLine ParseCommandLine(int argc, char* argv[])
122{
124 cmd.args.reserve(argc);
125 for (int i = 1; i < argc; ++i) {
126 std::string_view arg = argv[i];
127 if (!cmd.command.empty()) {
128 cmd.args.emplace_back(argv[i]);
129 } else if (arg == "-m" || arg == "--multiprocess") {
130 cmd.use_multiprocess = true;
131 } else if (arg == "-M" || arg == "--monolithic") {
132 cmd.use_multiprocess = false;
133 } else if (arg == "-v" || arg == "--version") {
134 cmd.show_version = true;
135 } else if (arg == "-h" || arg == "--help" || arg == "help") {
136 cmd.show_help = true;
137 } else if (arg.starts_with("-")) {
138 throw std::runtime_error(strprintf("Unknown option: %s", arg));
139 } else if (!arg.empty()) {
140 cmd.command = arg;
141 }
142 }
143 return cmd;
144}
145
158//
164static void ExecCommand(const std::vector<const char*>& args, std::string_view wrapper_argv0)
165{
166 // Construct argument string for execvp
167 std::vector<const char*> exec_args{args};
168 exec_args.emplace_back(nullptr);
169
170 // Try to call ExecVp with given exe path.
171 auto try_exec = [&](fs::path exe_path, bool allow_notfound = true) {
172 std::string exe_path_str{fs::PathToString(exe_path)};
173 exec_args[0] = exe_path_str.c_str();
174 if (util::ExecVp(exec_args[0], (char*const*)exec_args.data()) == -1) {
175 if (allow_notfound && errno == ENOENT) return false;
176 throw std::system_error(errno, std::system_category(), strprintf("execvp failed to execute '%s'", exec_args[0]));
177 }
178 throw std::runtime_error("execvp returned unexpectedly");
179 };
180
181 // Get the wrapper executable path.
182 const fs::path wrapper_path{util::GetExePath(wrapper_argv0)};
183
184 // Try to resolve any symlinks and figure out the directory containing the wrapper executable.
185 std::error_code ec;
186 fs::path wrapper_dir{fs::weakly_canonical(wrapper_path, ec)};
187 if (wrapper_dir.empty()) wrapper_dir = wrapper_path; // Restore previous path if weakly_canonical failed.
188 wrapper_dir = wrapper_dir.parent_path();
189
190 // Get path of the executable to be invoked.
191 const fs::path arg0{fs::PathFromString(args[0])};
192
193 // Decide whether to fall back to the operating system to search for the
194 // specified executable. Avoid doing this if it looks like the wrapper
195 // executable was invoked by path, rather than by search, to avoid
196 // unintentionally launching system executables in a local build.
197 // (https://github.com/bitcoin/bitcoin/pull/31375#discussion_r1861814807)
198 const bool fallback_os_search{!fs::PathFromString(std::string{wrapper_argv0}).has_parent_path()};
199
200 // If wrapper is installed in a bin/ directory, look for target executable
201 // in libexec/
202 (wrapper_dir.filename() == "bin" && try_exec(fs::path{wrapper_dir.parent_path()} / "libexec" / arg0.filename())) ||
203#ifdef WIN32
204 // Otherwise check the "daemon" subdirectory in a windows install.
205 (!wrapper_dir.empty() && try_exec(wrapper_dir / "daemon" / arg0.filename())) ||
206#endif
207 // Otherwise look for target executable next to current wrapper
208 (!wrapper_dir.empty() && try_exec(wrapper_dir / arg0.filename(), fallback_os_search)) ||
209 // Otherwise just look on the system path.
210 (fallback_os_search && try_exec(arg0.filename(), false));
211}
const auto cmd
return EXIT_SUCCESS
int main(int argc, char *argv[])
Definition: bitcoin.cpp:60
static constexpr auto HELP_FULL
Definition: bitcoin.cpp:37
static constexpr auto HELP_SHORT
Definition: bitcoin.cpp:45
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,...
Definition: bitcoin.cpp:164
const TranslateFn G_TRANSLATION_FUN
Translate string to current locale using Qt.
Definition: bitcoin.cpp:18
static constexpr auto HELP_USAGE
Definition: bitcoin.cpp:20
CommandLine ParseCommandLine(int argc, char *argv[])
Definition: bitcoin.cpp:121
ArgsManager & args
Definition: bitcoind.cpp:277
std::string FormatFullVersion()
std::string LicenseInfo()
Returns licensing information (for -version)
static std::string PathToString(const path &path)
Convert path object to a byte string.
Definition: fs.h:151
static path PathFromString(const std::string &string)
Convert byte string to path object.
Definition: fs.h:174
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
int ExecVp(const char *file, char *const argv[])
Cross-platform wrapper for POSIX execvp function.
Definition: exec.cpp:21
fs::path GetExePath(std::string_view argv0)
Return path to current executable assuming it was invoked with argv0.
Definition: exec.cpp:40
std::string_view command
Definition: bitcoin.cpp:53
bool show_version
Definition: bitcoin.cpp:51
std::vector< const char * > args
Definition: bitcoin.cpp:54
bool show_help
Definition: bitcoin.cpp:52
bool use_multiprocess
Definition: bitcoin.cpp:50
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
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.