]> sourceware.org Git - systemtap.git/blob - util.h
testsuite procfs_bpf.exp: tolerate stapbpf early exit
[systemtap.git] / util.h
1 #ifndef UTIL_H
2 #define UTIL_H
3
4 #include "config.h"
5 #include <cstdlib>
6 #include <cstring>
7 #include <cerrno>
8 #include <string>
9 #include <vector>
10 #include <iostream>
11 #include <sstream>
12 #include <stdexcept>
13 #include <cctype>
14 #include <set>
15 #include <iomanip>
16 #include <map>
17 #include <algorithm>
18 #include <limits>
19
20 extern "C" {
21 #if ENABLE_NLS
22 #include <libintl.h>
23 #include <locale.h>
24 #endif
25 #include <signal.h>
26 #include <stdint.h>
27 #include <spawn.h>
28 #include <assert.h>
29 #include <poll.h>
30 }
31
32 // Sanity check C++11 support. We're only requiring GCC 4.4's level of
33 // functionality, so trust either __cplusplus or the GNUC macros.
34 #if !(__cplusplus >= 201103L || \
35 (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)))
36 #error "C++11 support is required!"
37 #endif
38
39 // NB: GCC didn't add C++11 final/override until 4.7, but until then it also
40 // only had __cplusplus=1 regardless of -std (GCC PR1773). So checking new
41 // __cplusplus is probably good enough here; otherwise we should autoconf it.
42 #if __cplusplus >= 201103L
43 #define cxx_final final
44 #define cxx_override override
45 #else
46 #define cxx_final
47 #define cxx_override
48 #endif
49
50 #include "privilege.h"
51 #include "stringtable.h"
52
53 #if ENABLE_NLS
54 #define _(string) gettext(string)
55 #define _N(string, string_plural, count) \
56 ngettext((string), (string_plural), (count))
57 #else
58 #define _(string) (string)
59 #define _N(string, string_plural, count) \
60 ( (count) == 1 ? (string) : (string_plural) )
61 #endif
62 #define _F(format, ...) autosprintf(_(format), __VA_ARGS__)
63 #define _NF(format, format_plural, count, ...) \
64 autosprintf(_N((format), (format_plural), (count)), __VA_ARGS__)
65 #define _STRINGIFY_MORE(s) #s
66 #define _STRINGIFY(s) _STRINGIFY_MORE(s)
67 #define ERR_SRC (std::string(__FILE__) + ":" + _STRINGIFY(__LINE__))
68 #define SEMANTIC_ERROR(...) semantic_error(ERR_SRC, __VA_ARGS__)
69 #define PARSE_ERROR(...) parse_error(ERR_SRC, __VA_ARGS__)
70
71 const char *get_home_directory(void);
72 size_t get_file_size(const std::string &path);
73 size_t get_file_size(int fd);
74 bool file_exists (const std::string &path);
75 bool dir_exists(const std::string &path);
76 bool copy_file(const std::string& src, const std::string& dest,
77 bool verbose=false);
78 int create_dir(const char *dir, int mode = 0777);
79 int remove_file_or_dir(const char *dir);
80 extern "C" gid_t get_gid (const char *group_name);
81 int appendenv (const char *env_name, const std::string source);
82 bool in_group_id (gid_t target_gid);
83 std::string getmemusage ();
84 void tokenize(const std::string& str, std::vector<std::string>& tokens,
85 const std::string& delimiters = " ");
86 void tokenize_full(const std::string& str, std::vector<std::string>& tokens,
87 const std::string& delimiters = " ");
88 void tokenize_cxx(const std::string& str, std::vector<std::string>& tokens);
89 std::vector<std::pair<const char*,int> > split_lines(const char *buf, size_t n);
90 std::string find_executable(const std::string& name);
91 std::string find_executable(const std::string& name,
92 const std::string& sysroot,
93 const std::map<std::string,std::string>& sysenv,
94 const std::string& env_path = "PATH");
95 bool is_fully_resolved(const std::string& name,
96 const std::string& sysroot,
97 const std::map<std::string,std::string>& sysenv,
98 const std::string& env_path = "PATH");
99 const std::string cmdstr_quoted(const std::string& cmd);
100 const std::string detox_path(const std::string& str);
101 const std::string cmdstr_join(const std::vector<std::string>& cmds);
102 const std::string join(const std::vector<std::string>& cmds,
103 const std::string& delim);
104 int stap_waitpid(int verbose, pid_t pid);
105 pid_t stap_spawn(int verbose, const std::vector<std::string>& args);
106 pid_t stap_spawn(int verbose, const std::vector<std::string>& args,
107 posix_spawn_file_actions_t* fa, const std::vector<std::string>& envVec = std::vector<std::string> ());
108 pid_t stap_spawn_piped(int verbose, const std::vector<std::string>& args,
109 int* child_in=NULL, int* child_out=NULL, int* child_err=NULL);
110 int stap_system(int verbose, const std::string& description,
111 const std::vector<std::string>& args,
112 bool null_out=false, bool null_err=false);
113 inline int stap_system(int verbose, const std::vector<std::string>& args,
114 bool null_out=false, bool null_err=false)
115 { return stap_system(verbose, args.front(), args, null_out, null_err); }
116 int stap_system_read(int verbose, const std::vector<std::string>& args, std::ostream& out);
117 std::pair<bool,int> stap_fork_read(int verbose, std::ostream& out);
118 int kill_stap_spawn(int sig);
119 void assert_regexp_match (const std::string& name, const std::string& value, const std::string& re);
120 int regexp_match (const std::string& value, const std::string& re, std::vector<std::string>& matches);
121 bool contains_glob_chars (const std::string &str);
122 std::string escape_glob_chars (const std::string& str);
123 std::string unescape_glob_chars (const std::string& str);
124 std::string csh_to_ksh (const std::string& csh);
125 bool identifier_string_needs_escape (const std::string& str);
126 std::string escaped_identifier_string (const std::string& str);
127 std::string escaped_character (unsigned c);
128 std::string escaped_literal_string (const std::string& str);
129 std::string kernel_release_from_build_tree (const std::string &kernel_build_tree, int verbose = 0);
130 std::string normalize_machine(const std::string& machine);
131 int elf_class_from_normalized_machine(const std::string& machine);
132 std::string autosprintf(const char* format, ...) __attribute__ ((format (printf, 1, 2)));
133 const std::set<std::string>& localization_variables();
134 std::string get_self_path();
135 bool is_valid_pid (pid_t pid, std::string& err_msg);
136
137 // stringification generics
138
139
140 template <typename IN>
141 inline std::string lex_cast(IN const & in)
142 {
143 std::ostringstream ss;
144 if (!(ss << in))
145 throw std::runtime_error(_("bad lexical cast"));
146 return ss.str();
147 }
148
149 #if __cplusplus < 201103L
150 // Older C++0x only had the "long long" implementations, so we cast up.
151 #define INT_TO_STRING(IN) \
152 LEX_CAST_TO_STRING(signed IN, long long) \
153 LEX_CAST_TO_STRING(unsigned IN, unsigned long long)
154 #else
155 // Otherwise, keep the values native.
156 #define INT_TO_STRING(IN) \
157 LEX_CAST_TO_STRING(signed IN, signed IN) \
158 LEX_CAST_TO_STRING(unsigned IN, unsigned IN)
159 #endif
160
161 #define LEX_CAST_TO_STRING(IN, CAST) \
162 template <> \
163 inline std::string lex_cast(IN const & in) \
164 { \
165 return std::to_string(static_cast<CAST>(in)); \
166 }
167
168 INT_TO_STRING(char)
169 INT_TO_STRING(short)
170 INT_TO_STRING(int)
171 INT_TO_STRING(long)
172 INT_TO_STRING(long long)
173
174 #undef INT_TO_STRING
175 #undef LEX_CAST_TO_STRING
176
177
178 template <typename OUT>
179 inline OUT lex_cast(std::string const & in)
180 {
181 std::istringstream ss(in);
182 OUT out;
183 if (!(ss >> out && ss.eof()))
184 throw std::runtime_error(_("bad lexical cast"));
185 return out;
186 }
187
188
189 // We want [u]int8_t to be treated numerically, not just extracting a char.
190 template <>
191 inline int8_t lex_cast(std::string const & in)
192 {
193 int16_t out = lex_cast<int16_t>(in);
194 if (out < -128 || out > 127)
195 throw std::runtime_error(_("bad lexical cast"));
196 return out;
197 }
198 template <>
199 inline uint8_t lex_cast(std::string const & in)
200 {
201 uint16_t out = lex_cast<uint16_t>(in);
202 if (out > 0xff && out < 0xff80) // don't error if it looks sign-extended
203 throw std::runtime_error(_("bad lexical cast"));
204 return out;
205 }
206
207
208 template <typename IN>
209 inline std::string
210 lex_cast_hex(IN const & in)
211 {
212 std::ostringstream ss;
213 if (!(ss << std::showbase << std::hex << in << std::dec))
214 throw std::runtime_error(_("bad lexical cast"));
215 return ss.str();
216 }
217
218 //Convert binary data to hex data.
219 template <typename IN>
220 inline std::string
221 hex_dump(IN const & in, size_t len)
222 {
223 std::ostringstream ss;
224 unsigned i;
225 if (!(ss << std::hex << std::setfill('0')))
226 throw std::runtime_error(_("bad lexical cast"));
227
228 for(i = 0; i < len; i++)
229 {
230 int temp = in[i];
231 ss << std::setw(2) << temp;
232 }
233 std::string hex = ss.str();
234 assert(hex.length() == 2 * len);
235 return hex;
236 }
237
238 // Return as quoted string, so that when compiled as a C literal, it
239 // would print to the user out nicely.
240 template <typename IN>
241 inline std::string
242 lex_cast_qstring(IN const & in)
243 {
244 std::stringstream ss;
245 if (!(ss << in))
246 throw std::runtime_error(_("bad lexical cast"));
247 return lex_cast_qstring(ss.str());
248 }
249
250
251 template <>
252 inline std::string
253 lex_cast_qstring(std::string const & in)
254 {
255 std::string out;
256 out += '"';
257 for (const char *p = in.c_str(); *p; ++p)
258 {
259 unsigned char c = *p;
260 if (! isprint(c))
261 {
262 out += '\\';
263 // quick & dirty octal converter
264 out += "01234567" [(c >> 6) & 0x07];
265 out += "01234567" [(c >> 3) & 0x07];
266 out += "01234567" [(c >> 0) & 0x07];
267 }
268 else if (c == '"' || c == '\\')
269 {
270 out += '\\';
271 out += c;
272 }
273 else
274 out += c;
275 }
276 out += '"';
277 return out;
278 }
279
280
281 // Delete all values from a map-like container and clear it
282 // (The template is permissive -- be good!)
283 template <typename T>
284 void delete_map(T& t)
285 {
286 for (typename T::iterator i = t.begin(); i != t.end(); ++i)
287 delete i->second;
288 t.clear();
289 }
290
291
292 // Automatically save a variable, and restore it at the
293 // end of the function.
294 template <class V>
295 class save_and_restore
296 {
297 V* ptr;
298 V previous_value;
299
300 public:
301 // Optionally pass a second argument to the constructor to initialize the
302 // variable to some value, after saving its old value.
303 save_and_restore(V* ptr_in, V value_in): ptr(ptr_in), previous_value(*ptr_in) { *ptr_in = value_in; }
304 save_and_restore(V*ptr_in): ptr(ptr_in), previous_value(*ptr_in){}
305
306 // Retrieve the old value and restore it in the destructor
307 ~save_and_restore() { *ptr = previous_value; }
308 };
309
310 template <typename T>
311 inline bool vector_has(std::vector<T>& v, T item)
312 {
313 return std::find(v.begin(), v.end(), item) != v.end();
314 }
315
316 // Returns whether a string starts with the given prefix
317 inline bool
318 startswith(const std::string & s, const char * prefix)
319 {
320 return (s.compare(0, std::strlen(prefix), prefix) == 0);
321 }
322
323 inline bool
324 startswith(const std::string & s, const std::string & prefix)
325 {
326 return (s.compare(0, prefix.length(), prefix) == 0);
327 }
328
329 // Returns whether a string ends with the given suffix
330 inline bool
331 endswith(const std::string & s, const char * suffix)
332 {
333 size_t s_len = s.size(), suffix_len = std::strlen(suffix);
334 if (suffix_len > s_len)
335 return false;
336 return (s.compare(s_len - suffix_len, suffix_len, suffix) == 0);
337 }
338
339
340 // Mask our usual signals for the life of this object.
341 struct stap_sigmasker {
342 sigset_t old;
343 stap_sigmasker()
344 {
345 sigset_t mask;
346 sigemptyset (&mask);
347 sigaddset (&mask, SIGHUP);
348 sigaddset (&mask, SIGPIPE);
349 sigaddset (&mask, SIGINT);
350 sigaddset (&mask, SIGTERM);
351 sigprocmask (SIG_BLOCK, &mask, &old);
352 }
353 stap_sigmasker(const sigset_t *mask)
354 {
355 sigprocmask (SIG_BLOCK, mask, &old);
356 }
357 ~stap_sigmasker()
358 {
359 sigprocmask (SIG_SETMASK, &old, NULL);
360 }
361 };
362
363 // Convert a possibly-relative path to a full path
364 inline std::string
365 resolve_path(const std::string& path)
366 {
367 std::string result(path);
368 char* resolved_path = realpath(path.c_str(), NULL);
369 if (resolved_path)
370 {
371 result = resolved_path;
372 std::free(resolved_path);
373 }
374 return result;
375 }
376
377 // Used in levenshtein
378 template<typename T>
379 class Array2D
380 {
381 private:
382 T * data;
383 public:
384 const unsigned width;
385 const unsigned height;
386 T& operator() (unsigned x, unsigned y) { return data[y*width + x]; }
387 Array2D(const unsigned w, const unsigned h) : width(w), height(h) { data = new T[w*h]; }
388 ~Array2D() { delete [] data; }
389 };
390
391 // String sorter using the Levenshtein algorithm
392 unsigned levenshtein(const std::string& a, const std::string& b);
393
394 // Returns comma-separated list of set elements closest to the target string.
395 // Print a maximum amount of 'max' elements, with a maximum levenshtein score
396 // of 'threshold'.
397 std::string levenshtein_suggest(const std::string& target,
398 const std::set<std::string>& elems,
399 unsigned max = std::numeric_limits<unsigned>::max(),
400 unsigned threshold = std::numeric_limits<unsigned>::max());
401
402 std::string levenshtein_suggest(const std::string& target,
403 const std::set<interned_string>& elems,
404 unsigned max = std::numeric_limits<unsigned>::max(),
405 unsigned threshold = std::numeric_limits<unsigned>::max());
406
407 #ifndef HAVE_PPOLL
408 // This is a poor-man's ppoll; see the implementation for more details...
409 int ppoll(struct pollfd *fds, nfds_t nfds,
410 const struct timespec *timeout_ts,
411 const sigset_t *sigmask);
412 #endif
413
414
415 int read_from_file (const std::string &fname, int &data);
416 template <class T>
417 int write_to_file (const std::string &fname, const T &data);
418 int flush_to_stream (const std::string &fname, std::ostream &o);
419
420 void ltrim(std::string &s);
421 void rtrim(std::string &s);
422 void trim(std::string &s);
423
424 bool get_distro_info(std::vector<std::string> &info);
425 #endif // UTIL_H
426
427 /* vim: set sw=2 ts=8 cino=>4,n-2,{2,^-2,t0,(0,u0,w1,M1 : */
This page took 0.061108 seconds and 5 git commands to generate.