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