mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-07-07 08:50:26 +02:00
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.
This commit is contained in:
@ -9,6 +9,7 @@ add_library(bitcoin_util STATIC EXCLUDE_FROM_ALL
|
||||
bytevectorhash.cpp
|
||||
chaintype.cpp
|
||||
check.cpp
|
||||
exec.cpp
|
||||
exception.cpp
|
||||
feefrac.cpp
|
||||
fs.cpp
|
||||
|
75
src/util/exec.cpp
Normal file
75
src/util/exec.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
// Copyright (c) 2025 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include <util/exec.h>
|
||||
|
||||
#include <util/fs.h>
|
||||
#include <util/subprocess.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <process.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
namespace util {
|
||||
int ExecVp(const char* file, char* const argv[])
|
||||
{
|
||||
#ifndef WIN32
|
||||
return execvp(file, argv);
|
||||
#else
|
||||
std::vector<std::wstring> escaped_args;
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||
for (char* const* arg_ptr{argv}; *arg_ptr; ++arg_ptr) {
|
||||
subprocess::util::quote_argument(converter.from_bytes(*arg_ptr), escaped_args.emplace_back(), false);
|
||||
}
|
||||
|
||||
std::vector<const wchar_t*> new_argv;
|
||||
new_argv.reserve(escaped_args.size() + 1);
|
||||
for (const auto& s : escaped_args) new_argv.push_back(s.c_str());
|
||||
new_argv.push_back(nullptr);
|
||||
return _wexecvp(converter.from_bytes(file).c_str(), new_argv.data());
|
||||
#endif
|
||||
}
|
||||
|
||||
fs::path GetExePath(std::string_view argv0)
|
||||
{
|
||||
// Try to figure out where executable is located. This does a simplified
|
||||
// search that won't work perfectly on every platform and doesn't need to,
|
||||
// as it is only currently being used in a convenience wrapper binary to try
|
||||
// to prioritize locally built or installed executables over system
|
||||
// executables.
|
||||
const fs::path argv0_path{fs::PathFromString(std::string{argv0})};
|
||||
fs::path path{argv0_path};
|
||||
std::error_code ec;
|
||||
#ifndef WIN32
|
||||
// If argv0 doesn't contain a path separator, it was invoked from the system
|
||||
// PATH and can be searched for there.
|
||||
if (!argv0_path.has_parent_path()) {
|
||||
if (const char* path_env = std::getenv("PATH")) {
|
||||
size_t start{0}, end{0};
|
||||
for (std::string_view paths{path_env}; end != std::string_view::npos; start = end + 1) {
|
||||
end = paths.find(':', start);
|
||||
fs::path candidate = fs::path(paths.substr(start, end - start)) / argv0_path;
|
||||
if (fs::is_regular_file(candidate, ec)) {
|
||||
path = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
wchar_t module_path[MAX_PATH];
|
||||
if (GetModuleFileNameW(nullptr, module_path, MAX_PATH) > 0) {
|
||||
path = fs::path{module_path};
|
||||
}
|
||||
#endif
|
||||
return path;
|
||||
}
|
||||
|
||||
} // namespace util
|
23
src/util/exec.h
Normal file
23
src/util/exec.h
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2025 The Bitcoin Core developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_UTIL_EXEC_H
|
||||
#define BITCOIN_UTIL_EXEC_H
|
||||
|
||||
#include <util/fs.h>
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace util {
|
||||
//! Cross-platform wrapper for POSIX execvp function.
|
||||
//! Arguments and return value are the same as for POSIX execvp, and the argv
|
||||
//! array should consist of null terminated strings and be null terminated
|
||||
//! itself, like the POSIX function.
|
||||
int ExecVp(const char* file, char* const argv[]);
|
||||
//! Return path to current executable assuming it was invoked with argv0.
|
||||
//! If path could not be determined, returns an empty path.
|
||||
fs::path GetExePath(std::string_view argv0);
|
||||
} // namespace util
|
||||
|
||||
#endif // BITCOIN_UTIL_EXEC_H
|
Reference in New Issue
Block a user