Skip to content

Commit 5076d20

Browse files
committed
util: Add cross-platform ExecVp and GetExePath functions
These functions are just meant to serve the needs of the bitcoin wrapper executable, and are intentionally not very general purpose so they can be simple.
1 parent 663a9ca commit 5076d20

File tree

3 files changed

+99
-0
lines changed

3 files changed

+99
-0
lines changed

src/util/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ add_library(bitcoin_util STATIC EXCLUDE_FROM_ALL
99
bytevectorhash.cpp
1010
chaintype.cpp
1111
check.cpp
12+
exec.cpp
1213
exception.cpp
1314
feefrac.cpp
1415
fs.cpp

src/util/exec.cpp

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
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 <util/exec.h>
6+
7+
#include <util/fs.h>
8+
#include <util/subprocess.h>
9+
10+
#include <string>
11+
#include <vector>
12+
13+
#ifdef WIN32
14+
#include <process.h>
15+
#include <windows.h>
16+
#else
17+
#include <unistd.h>
18+
#endif
19+
20+
namespace util {
21+
int ExecVp(const char* file, char* const argv[])
22+
{
23+
#ifndef WIN32
24+
return execvp(file, argv);
25+
#else
26+
std::vector<std::wstring> escaped_args;
27+
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
28+
for (char* const* arg_ptr{argv}; *arg_ptr; ++arg_ptr) {
29+
subprocess::util::quote_argument(converter.from_bytes(*arg_ptr), escaped_args.emplace_back(), false);
30+
}
31+
32+
std::vector<const wchar_t*> new_argv;
33+
new_argv.reserve(escaped_args.size() + 1);
34+
for (const auto& s : escaped_args) new_argv.push_back(s.c_str());
35+
new_argv.push_back(nullptr);
36+
return _wexecvp(converter.from_bytes(file).c_str(), new_argv.data());
37+
#endif
38+
}
39+
40+
fs::path GetExePath(std::string_view argv0)
41+
{
42+
// Try to figure out where executable is located. This does a simplified
43+
// search that won't work perfectly on every platform and doesn't need to,
44+
// as it is only currently being used in a convenience wrapper binary to try
45+
// to prioritize locally built or installed executables over system
46+
// executables.
47+
const fs::path argv0_path{fs::PathFromString(std::string{argv0})};
48+
fs::path path{argv0_path};
49+
std::error_code ec;
50+
#ifndef WIN32
51+
// If argv0 doesn't contain a path separator, it was invoked from the system
52+
// PATH and can be searched for there.
53+
if (!argv0_path.has_parent_path()) {
54+
if (const char* path_env = std::getenv("PATH")) {
55+
size_t start{0}, end{0};
56+
for (std::string_view paths{path_env}; end != std::string_view::npos; start = end + 1) {
57+
end = paths.find(':', start);
58+
fs::path candidate = fs::path(paths.substr(start, end - start)) / argv0_path;
59+
if (fs::is_regular_file(candidate, ec)) {
60+
path = candidate;
61+
break;
62+
}
63+
}
64+
}
65+
}
66+
#else
67+
wchar_t module_path[MAX_PATH];
68+
if (GetModuleFileNameW(nullptr, module_path, MAX_PATH) > 0) {
69+
path = fs::path{module_path};
70+
}
71+
#endif
72+
return path;
73+
}
74+
75+
} // namespace util

src/util/exec.h

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
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+
#ifndef BITCOIN_UTIL_EXEC_H
6+
#define BITCOIN_UTIL_EXEC_H
7+
8+
#include <util/fs.h>
9+
10+
#include <string_view>
11+
12+
namespace util {
13+
//! Cross-platform wrapper for POSIX execvp function.
14+
//! Arguments and return value are the same as for POSIX execvp, and the argv
15+
//! array should consist of null terminated strings and be null terminated
16+
//! itself, like the POSIX function.
17+
int ExecVp(const char* file, char* const argv[]);
18+
//! Return path to current executable assuming it was invoked with argv0.
19+
//! If path could not be determined, returns an empty path.
20+
fs::path GetExePath(std::string_view argv0);
21+
} // namespace util
22+
23+
#endif // BITCOIN_UTIL_EXEC_H

0 commit comments

Comments
 (0)