Coverage Report

Created: 2025-08-24 07:05

/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 */