/src/usbguard/src/Common/Utility.hpp
Line | Count | Source (jump to first uncovered line) |
1 | | // |
2 | | // Copyright (C) 2015 Red Hat, Inc. |
3 | | // |
4 | | // This program is free software; you can redistribute it and/or modify |
5 | | // it under the terms of the GNU General Public License as published by |
6 | | // the Free Software Foundation; either version 2 of the License, or |
7 | | // (at your option) any later version. |
8 | | // |
9 | | // This program is distributed in the hope that it will be useful, |
10 | | // but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 | | // GNU General Public License for more details. |
13 | | // |
14 | | // You should have received a copy of the GNU General Public License |
15 | | // along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | | // |
17 | | // Authors: Daniel Kopecek <dkopecek@redhat.com> |
18 | | // |
19 | | #pragma once |
20 | | #ifdef HAVE_BUILD_CONFIG_H |
21 | | #include <build-config.h> |
22 | | #endif |
23 | | |
24 | | #include "usbguard/Exception.hpp" |
25 | | #include "usbguard/Typedefs.hpp" |
26 | | |
27 | | #include <functional> |
28 | | #include <iomanip> |
29 | | #include <iostream> |
30 | | #include <regex> |
31 | | #include <sstream> |
32 | | #include <string> |
33 | | #include <utility> |
34 | | #include <vector> |
35 | | #include <memory> |
36 | | |
37 | | #include <dirent.h> |
38 | | #include <sys/stat.h> |
39 | | #include <sys/types.h> |
40 | | #include <unistd.h> |
41 | | |
42 | | namespace usbguard |
43 | | { |
44 | | /** |
45 | | * Wrappers for the __builtin_expect function. |
46 | | */ |
47 | | #if defined(__GNUC__) |
48 | | #define likely(expr) __builtin_expect(!!(expr), 1) |
49 | | #define unlikely(expr) __builtin_expect(!!(expr), 0) |
50 | | #else |
51 | | #define likely(expr) (expr) |
52 | | #define unlikely(expr) (expr) |
53 | | #endif |
54 | | |
55 | | int runCommand(const char* path, const char* arg1, int timeout_secs = 10); |
56 | | int runCommand(const char* path, const char* arg1, const char* arg2, int timeout_secs = 10); |
57 | | int runCommand(const std::string& path, const std::vector<std::string>& args = std::vector<std::string>(), |
58 | | int timeout_secs = 10); |
59 | | |
60 | | /** |
61 | | * Tokenize a std::string compatible type using delimiters specified in a string. |
62 | | * |
63 | | * Splits the given string using delimiters found in the delimiter string (each |
64 | | * character in the delimiter string is considered as a delimiter) and stores the |
65 | | * token in a vector. If trim_empty is set to true, empty tokens won't be included |
66 | | * in the vector. |
67 | | */ |
68 | | template<typename StringType> |
69 | | void tokenizeString(const StringType& str, std::vector<StringType>& tokens, |
70 | | const typename std::vector<StringType>::value_type delimiters, const bool trim_empty = false) |
71 | 101k | { |
72 | 101k | typename StringType::size_type pos, last_pos = 0; |
73 | | |
74 | 222k | while (true) { |
75 | 222k | pos = str.find_first_of(delimiters, last_pos); |
76 | | |
77 | 222k | if (pos == StringType::npos) { |
78 | 101k | pos = str.length(); |
79 | | |
80 | 101k | if (pos != last_pos || !trim_empty) { |
81 | 101k | tokens.push_back(StringType(str.data() + last_pos, pos - last_pos)); |
82 | 101k | } |
83 | | |
84 | 101k | break; |
85 | 101k | } |
86 | 120k | else { |
87 | 120k | if (pos != last_pos || !trim_empty) { |
88 | 120k | tokens.push_back(StringType(str.data() + last_pos, pos - last_pos)); |
89 | 120k | } |
90 | 120k | } |
91 | | |
92 | 120k | last_pos = pos + 1; |
93 | 120k | } |
94 | 101k | } |
95 | | |
96 | | /** |
97 | | * Convert a number of type T to its string |
98 | | * representation. |
99 | | */ |
100 | | template<typename T> |
101 | | std::string numberToString(const T number, const std::string& prefix = std::string(), const int base = 10, const int align = -1, |
102 | | const char align_char = ' ') |
103 | 0 | { |
104 | 0 | std::ostringstream ss; |
105 | 0 | ss << std::setbase(base); |
106 | 0 | ss << number; |
107 | 0 | const std::string number_string = ss.str(); |
108 | 0 | std::string result; |
109 | 0 | result.append(prefix); |
110 | |
|
111 | 0 | if (align > 0 && number_string.size() < (size_t)align) { |
112 | 0 | size_t chars_to_add = (size_t)align - number_string.size(); |
113 | |
|
114 | 0 | for (; chars_to_add > 0; --chars_to_add) { |
115 | 0 | result += align_char; |
116 | 0 | } |
117 | 0 | } |
118 | |
|
119 | 0 | result.append(number_string); |
120 | 0 | return result; |
121 | 0 | } Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > usbguard::numberToString<unsigned short>(unsigned short, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, int, int, char) Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > usbguard::numberToString<int>(int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, int, int, char) |
122 | | |
123 | | template<> |
124 | | std::string numberToString(const uint8_t number, const std::string& prefix, const int base, const int align, |
125 | | const char align_char); |
126 | | |
127 | | /** |
128 | | * Convert a string representation of a number |
129 | | * to a number of type T. |
130 | | */ |
131 | | template<typename T> |
132 | | T stringToNumber(const std::string& s, const int base = 10) |
133 | 23.9k | { |
134 | 23.9k | std::istringstream ss(s); |
135 | 23.9k | T num; |
136 | 23.9k | ss >> std::setbase(base) >> num; |
137 | 23.9k | return num; |
138 | 23.9k | } |
139 | | |
140 | | template<> |
141 | | uint8_t stringToNumber(const std::string& s, const int base); |
142 | | |
143 | | bool isNumericString(const std::string& s); |
144 | | |
145 | | /** |
146 | | * Return the filename part of a path. If include_extension is set to |
147 | | * false, then any characters after the last dot character '.' will be |
148 | | * removed including the dot. |
149 | | * |
150 | | * Examples: "/foo/bar/baz" => "baz" |
151 | | * "/foo/bar/baz.txt" (include_extension=false) => "baz" |
152 | | * "/foo/bar/baz.txt" (include_extension=true) => "baz.txt" |
153 | | * "/foo/bar/baz.woo.txt" (include_extension=false) => "baz.woo" |
154 | | * "foo.txt" (include_extension=true) => "foo.txt" |
155 | | */ |
156 | | std::string filenameFromPath(const std::string& filepath, bool include_extension = false); |
157 | | |
158 | | /** |
159 | | * Return the parent path part of a path. |
160 | | */ |
161 | | std::string parentPath(const std::string& path); |
162 | | |
163 | | /** |
164 | | * Return the number of path components. |
165 | | */ |
166 | | std::size_t countPathComponents(const std::string& path); |
167 | | |
168 | | /** |
169 | | * Remove whitespace characters from the right side of a string. |
170 | | */ |
171 | | std::string trimRight(const std::string& s, const std::string& delimiters = " \f\n\r\t\v"); |
172 | | |
173 | | /** |
174 | | * Remove whitespace characters from the left side of a string. |
175 | | */ |
176 | | std::string trimLeft(const std::string& s, const std::string& delimiters = " \f\n\r\t\v"); |
177 | | |
178 | | /** |
179 | | * Remove whitespace characters from the left & right side of a string. |
180 | | */ |
181 | | std::string trim(const std::string& s, const std::string& delimiters = " \f\n\r\t\v"); |
182 | | |
183 | | /** |
184 | | * Call a void(*)(const std::string&) compatible method for every file in a directory |
185 | | * matching a regular expression. The function does not recursively descent into |
186 | | * subdirectories. |
187 | | */ |
188 | | int loadFiles(const std::string& directory, |
189 | | std::function<std::string(const std::string&, const struct dirent*)> filter, |
190 | | std::function<int(const std::string&, const std::string&)> loader, |
191 | | std::function<bool(const std::pair<std::string, std::string>&, const std::pair<std::string, std::string>&)> sorter = \ |
192 | | [](const std::pair<std::string, std::string>& a, const std::pair<std::string, std::string>& b) -> bool { |
193 | | return a.first < b.first; |
194 | | }, |
195 | | bool directory_required = true); |
196 | | |
197 | | /** |
198 | | * Remove prefix from string. |
199 | | */ |
200 | | std::string removePrefix(const std::string& prefix, const std::string& value); |
201 | | |
202 | | /** |
203 | | * Test whether a string value has a prefix/suffix. |
204 | | */ |
205 | | bool hasSuffix(const std::string& value, const std::string& suffix); |
206 | | bool hasPrefix(const std::string& value, const std::string& prefix); |
207 | | |
208 | | /** |
209 | | * Read symlink destination. |
210 | | */ |
211 | | std::string symlinkPath(const std::string& linkpath, struct stat* st_user = nullptr); |
212 | | |
213 | | /* |
214 | | * Normalize path string: |
215 | | * - remove // |
216 | | * - remove ./ |
217 | | * - resolve foo/../bar/ to bar |
218 | | * - resolve /foo/../bar/ to /bar |
219 | | */ |
220 | | std::string normalizePath(const std::string& path); |
221 | | |
222 | | /* |
223 | | * Get files in directory |
224 | | */ |
225 | | std::vector<std::string> getConfigsFromDir(const std::string& path); |
226 | | |
227 | | |
228 | | /* |
229 | | * Restorer class |
230 | | */ |
231 | | template<typename Tvar, typename Tval> |
232 | | class Restorer |
233 | | { |
234 | | public: |
235 | | Restorer(Tvar& var, Tval transient, Tval restored) |
236 | | : _ref(var), |
237 | | _val(restored) |
238 | | { |
239 | | _ref = transient; |
240 | | } |
241 | | |
242 | | ~Restorer() |
243 | | { |
244 | | _ref = _val; |
245 | | } |
246 | | |
247 | | private: |
248 | | Tvar& _ref; |
249 | | Tval _val; |
250 | | }; |
251 | | |
252 | | struct FreeDeleter { |
253 | | void operator()(void* p) |
254 | 0 | { |
255 | 0 | free(p); |
256 | 0 | } |
257 | | }; |
258 | | |
259 | | template<typename T, typename... Params> |
260 | | std::unique_ptr<T> make_unique(Params&& ... params) |
261 | 120k | { |
262 | 120k | return std::unique_ptr<T>(new T(std::forward<Params>(params)...)); |
263 | 120k | } std::__1::unique_ptr<usbguard::RulePrivate, std::__1::default_delete<usbguard::RulePrivate> > usbguard::make_unique<usbguard::RulePrivate>() Line | Count | Source | 261 | 120k | { | 262 | 120k | return std::unique_ptr<T>(new T(std::forward<Params>(params)...)); | 263 | 120k | } |
Unexecuted instantiation: std::__1::unique_ptr<usbguard::RulePrivate, std::__1::default_delete<usbguard::RulePrivate> > usbguard::make_unique<usbguard::RulePrivate, usbguard::RulePrivate&>(usbguard::RulePrivate&) |
264 | | |
265 | | /* |
266 | | * Scoped File Descriptor |
267 | | */ |
268 | | class ScopedFD |
269 | | { |
270 | | public: |
271 | | ScopedFD(int fd) |
272 | 0 | : _fd(fd) {} |
273 | | |
274 | | ScopedFD(const ScopedFD&) = delete; |
275 | | |
276 | | ~ScopedFD() |
277 | 0 | { |
278 | 0 | if (_fd >= 0) { |
279 | 0 | ::close(_fd); |
280 | 0 | _fd = -1; |
281 | 0 | } |
282 | 0 | } |
283 | | |
284 | | operator int() const noexcept |
285 | 0 | { |
286 | 0 | return _fd; |
287 | 0 | } |
288 | | |
289 | | bool operator<(int rhs) const noexcept |
290 | 0 | { |
291 | 0 | return _fd < rhs; |
292 | 0 | } |
293 | | |
294 | | bool operator==(int rhs) const noexcept |
295 | 0 | { |
296 | 0 | return _fd == rhs; |
297 | 0 | } |
298 | | |
299 | | private: |
300 | | int _fd{-1}; |
301 | | }; |
302 | | |
303 | | |
304 | | template<typename T> |
305 | | std::string joinElements(T begin, T end, const std::string& separator = " ") |
306 | | { |
307 | | std::ostringstream ss; |
308 | | |
309 | | if (begin != end) { |
310 | | ss << *(begin++); |
311 | | } |
312 | | |
313 | | while (begin != end) { |
314 | | ss << separator << *(begin++); |
315 | | } |
316 | | |
317 | | return ss.str(); |
318 | | } |
319 | | |
320 | | /** |
321 | | * @brief Checks whether a given name is a valid group/user name |
322 | | * |
323 | | * |
324 | | * @param name Name to check |
325 | | * @return True if given name is valid, false otherwise |
326 | | */ |
327 | | bool isValidNameOrUID(const std::string& name); |
328 | | |
329 | | } /* namespace usbguard */ |
330 | | |
331 | | /* vim: set ts=2 sw=2 et */ |