Skip to content

Commit b9699e6

Browse files
committed
libexec: PathResolver is a separate class
1 parent d0f7f8c commit b9699e6

File tree

4 files changed

+193
-120
lines changed

4 files changed

+193
-120
lines changed

source/intercept-library/library/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ add_library(exec_a OBJECT
1111
source/Executor.cc
1212
source/Logger.cc
1313
source/Paths.cc
14+
source/PathResolver.cc
1415
source/Resolver.cc
1516
source/Session.cc
1617
)

source/intercept-library/library/source/Executor.cc

Lines changed: 6 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,16 @@
2222
#include "er/Flags.h"
2323

2424
#include "Array.h"
25-
#include "Environment.h"
2625
#include "Logger.h"
27-
#include "Paths.h"
26+
#include "PathResolver.h"
2827
#include "Resolver.h"
2928
#include "Session.h"
3029

3130
#include <algorithm>
3231
#include <cerrno>
33-
#include <climits>
34-
#include <string_view>
35-
36-
#include <unistd.h>
3732

3833
namespace {
3934

40-
constexpr char DIR_SEPARATOR = '/';
41-
4235
constexpr el::log::Logger LOGGER("Executor.cc");
4336

4437
constexpr el::Executor::Result failure(int const error_code) noexcept
@@ -71,10 +64,10 @@ namespace {
7164
: session(session)
7265
, path(path)
7366
, argv(argv)
74-
{
75-
}
67+
{ }
7668

77-
[[nodiscard]] constexpr size_t length() const noexcept
69+
[[nodiscard]]
70+
constexpr size_t length() const noexcept
7871
{
7972
return (session.verbose ? 6 : 7) + el::array::length(argv) + 1;
8073
}
@@ -99,7 +92,8 @@ namespace {
9992
*it = nullptr;
10093
}
10194

102-
[[nodiscard]] constexpr const char* file() const noexcept
95+
[[nodiscard]]
96+
constexpr const char* file() const noexcept
10397
{
10498
return session.reporter;
10599
}
@@ -109,114 +103,6 @@ namespace {
109103
const char* path;
110104
char* const* const argv;
111105
};
112-
113-
class PathResolver {
114-
public:
115-
struct Result {
116-
const char* return_value;
117-
const int error_code;
118-
119-
constexpr explicit operator bool() const noexcept {
120-
return (return_value != nullptr) && (error_code == 0);
121-
}
122-
};
123-
124-
public:
125-
explicit PathResolver(el::Resolver const &resolver);
126-
127-
Result from_current_directory(std::string_view const &file);
128-
Result from_path(std::string_view const &file, char* const* envp);
129-
Result from_search_path(std::string_view const &file, const char *search_path);
130-
131-
PathResolver(PathResolver const &) = delete;
132-
PathResolver(PathResolver &&) noexcept = delete;
133-
134-
PathResolver &operator=(PathResolver const &) = delete;
135-
PathResolver &&operator=(PathResolver &&) noexcept = delete;
136-
137-
private:
138-
static bool contains_dir_separator(std::string_view const &candidate);
139-
140-
private:
141-
el::Resolver const &resolver_;
142-
char result_[PATH_MAX];
143-
};
144-
145-
PathResolver::PathResolver(const el::Resolver &resolver)
146-
: resolver_(resolver)
147-
, result_()
148-
{ }
149-
150-
PathResolver::Result PathResolver::from_current_directory(std::string_view const &file) {
151-
// create absolute path to the given file.
152-
if (nullptr == resolver_.realpath(file.begin(), result_)) {
153-
return PathResolver::Result {nullptr, ENOENT };
154-
}
155-
// check if it's okay to execute.
156-
if (0 == resolver_.access(result_, X_OK)) {
157-
return PathResolver::Result { result_, 0 };
158-
}
159-
// try to set a meaningful error value.
160-
if (0 == resolver_.access(result_, F_OK)) {
161-
return PathResolver::Result {nullptr, EACCES };
162-
}
163-
return PathResolver::Result {nullptr, ENOENT };
164-
}
165-
166-
PathResolver::Result PathResolver::from_path(std::string_view const &file, char* const* envp) {
167-
if (contains_dir_separator(file)) {
168-
// the file contains a dir separator, it is treated as path.
169-
return from_current_directory(file);
170-
} else {
171-
// otherwise use the PATH variable to locate the executable.
172-
const char *paths = el::env::get_env_value(const_cast<const char **>(envp), "PATH");
173-
if (paths != nullptr) {
174-
return from_search_path(file, paths);
175-
}
176-
// fall back to `confstr` PATH value if the environment has no value.
177-
const size_t search_path_length = resolver_.confstr(_CS_PATH, nullptr, 0);
178-
if (search_path_length != 0) {
179-
char search_path[search_path_length];
180-
if (resolver_.confstr(_CS_PATH, search_path, search_path_length) != 0) {
181-
return from_search_path(file, search_path);
182-
}
183-
}
184-
return PathResolver::Result {nullptr, ENOENT };
185-
}
186-
}
187-
188-
PathResolver::Result PathResolver::from_search_path(std::string_view const &file, const char *search_path) {
189-
if (contains_dir_separator(file)) {
190-
// the file contains a dir separator, it is treated as path.
191-
return from_current_directory(file);
192-
} else {
193-
// otherwise use the given search path to locate the executable.
194-
for (auto path : el::Paths(search_path)) {
195-
// ignore empty entries
196-
if (path.empty()) {
197-
continue;
198-
}
199-
// create a path
200-
char candidate[PATH_MAX];
201-
{
202-
auto it = el::array::copy(path.begin(), path.end(), candidate, candidate + PATH_MAX);
203-
*it++ = DIR_SEPARATOR;
204-
it = el::array::copy(file.begin(), file.end(), it, candidate + PATH_MAX);
205-
*it = 0;
206-
}
207-
// check if it's okay to execute.
208-
if (auto result = from_current_directory(candidate); result) {
209-
return result;
210-
}
211-
}
212-
// if all attempt were failing, then quit with a failure.
213-
return PathResolver::Result {nullptr, ENOENT };
214-
}
215-
}
216-
217-
bool PathResolver::contains_dir_separator(std::string_view const &candidate) {
218-
return std::find(candidate.begin(), candidate.end(), DIR_SEPARATOR) != candidate.end();
219-
}
220106
}
221107

222108
#pragma GCC diagnostic push
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/* Copyright (C) 2012-2020 by László Nagy
2+
This file is part of Bear.
3+
4+
Bear is a tool to generate compilation database for clang tooling.
5+
6+
Bear is free software: you can redistribute it and/or modify
7+
it under the terms of the GNU General Public License as published by
8+
the Free Software Foundation, either version 3 of the License, or
9+
(at your option) any later version.
10+
11+
Bear is distributed in the hope that it will be useful,
12+
but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
GNU General Public License for more details.
15+
16+
You should have received a copy of the GNU General Public License
17+
along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
#include "PathResolver.h"
21+
22+
#include "Array.h"
23+
#include "Environment.h"
24+
#include "Paths.h"
25+
26+
#include <algorithm>
27+
#include <cerrno>
28+
#include <unistd.h>
29+
30+
namespace {
31+
32+
constexpr char DIR_SEPARATOR = '/';
33+
34+
bool contains_dir_separator(std::string_view const &candidate) {
35+
return std::find(candidate.begin(), candidate.end(), DIR_SEPARATOR) != candidate.end();
36+
}
37+
}
38+
39+
namespace el {
40+
41+
PathResolver::PathResolver(const el::Resolver &resolver)
42+
: resolver_(resolver)
43+
, result_()
44+
{ }
45+
46+
PathResolver::Result PathResolver::from_current_directory(std::string_view const &file) {
47+
// create absolute path to the given file.
48+
if (nullptr == resolver_.realpath(file.begin(), result_)) {
49+
return PathResolver::Result { nullptr, ENOENT };
50+
}
51+
// check if it's okay to execute.
52+
if (0 == resolver_.access(result_, X_OK)) {
53+
return PathResolver::Result { result_, 0 };
54+
}
55+
// try to set a meaningful error value.
56+
if (0 == resolver_.access(result_, F_OK)) {
57+
return PathResolver::Result {nullptr, EACCES };
58+
}
59+
return PathResolver::Result {nullptr, ENOENT };
60+
}
61+
62+
PathResolver::Result PathResolver::from_path(std::string_view const &file, char* const* envp) {
63+
if (contains_dir_separator(file)) {
64+
// the file contains a dir separator, it is treated as path.
65+
return from_current_directory(file);
66+
} else {
67+
// otherwise use the PATH variable to locate the executable.
68+
const char *paths = el::env::get_env_value(const_cast<const char **>(envp), "PATH");
69+
if (paths != nullptr) {
70+
return from_search_path(file, paths);
71+
}
72+
// fall back to `confstr` PATH value if the environment has no value.
73+
const size_t search_path_length = resolver_.confstr(_CS_PATH, nullptr, 0);
74+
if (search_path_length != 0) {
75+
char search_path[search_path_length];
76+
if (resolver_.confstr(_CS_PATH, search_path, search_path_length) != 0) {
77+
return from_search_path(file, search_path);
78+
}
79+
}
80+
return PathResolver::Result {nullptr, ENOENT };
81+
}
82+
}
83+
84+
PathResolver::Result PathResolver::from_search_path(std::string_view const &file, const char *search_path) {
85+
if (contains_dir_separator(file)) {
86+
// the file contains a dir separator, it is treated as path.
87+
return from_current_directory(file);
88+
} else {
89+
// otherwise use the given search path to locate the executable.
90+
for (auto path : el::Paths(search_path)) {
91+
// ignore empty entries
92+
if (path.empty()) {
93+
continue;
94+
}
95+
// create a path
96+
char candidate[PATH_MAX];
97+
{
98+
auto it = el::array::copy(path.begin(), path.end(), candidate, candidate + PATH_MAX);
99+
*it++ = DIR_SEPARATOR;
100+
it = el::array::copy(file.begin(), file.end(), it, candidate + PATH_MAX);
101+
*it = 0;
102+
}
103+
// check if it's okay to execute.
104+
if (auto result = from_current_directory(candidate); result) {
105+
return result;
106+
}
107+
}
108+
// if all attempt were failing, then quit with a failure.
109+
return PathResolver::Result {nullptr, ENOENT };
110+
}
111+
}
112+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/* Copyright (C) 2012-2020 by László Nagy
2+
This file is part of Bear.
3+
4+
Bear is a tool to generate compilation database for clang tooling.
5+
6+
Bear is free software: you can redistribute it and/or modify
7+
it under the terms of the GNU General Public License as published by
8+
the Free Software Foundation, either version 3 of the License, or
9+
(at your option) any later version.
10+
11+
Bear is distributed in the hope that it will be useful,
12+
but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
GNU General Public License for more details.
15+
16+
You should have received a copy of the GNU General Public License
17+
along with this program. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
#pragma once
21+
22+
#include "Resolver.h"
23+
24+
#include <climits>
25+
#include <string_view>
26+
27+
namespace el {
28+
29+
/**
30+
* This class implements the logic how the program execution resolves the
31+
* executable path from the system environment.
32+
*
33+
* The resolution logic implemented as a class to be able to unit test
34+
* the code and avoid memory allocation.
35+
*/
36+
class PathResolver {
37+
public:
38+
/**
39+
* Represents the resolution result. The result can be accessed only
40+
* when the PathResolver is still "alive" on the stack. When the value
41+
* is NULL, then the error code shall be non zero.
42+
*/
43+
struct Result {
44+
const char *return_value;
45+
const int error_code;
46+
47+
constexpr explicit operator bool() const noexcept {
48+
return (return_value != nullptr) && (error_code == 0);
49+
}
50+
};
51+
52+
public:
53+
explicit PathResolver(el::Resolver const &resolver);
54+
55+
/**
56+
* Resolve the executable from system environments.
57+
*
58+
* @return resolved executable path as absolute path.
59+
*/
60+
Result from_current_directory(std::string_view const &file);
61+
Result from_path(std::string_view const &file, char *const *envp);
62+
Result from_search_path(std::string_view const &file, const char *search_path);
63+
64+
PathResolver(PathResolver const &) = delete;
65+
PathResolver(PathResolver &&) noexcept = delete;
66+
67+
PathResolver &operator=(PathResolver const &) = delete;
68+
PathResolver &&operator=(PathResolver &&) noexcept = delete;
69+
70+
private:
71+
el::Resolver const &resolver_;
72+
char result_[PATH_MAX];
73+
};
74+
}

0 commit comments

Comments
 (0)