Aktualizr
C++ SOTA Client
All Classes Namespaces Files Functions Variables Enumerations Enumerator Pages
fault_injection.h
1 // This file is a modified version of fiu-local.h, adapted to fit our style conventions
2 // + some custom additions
3 
4 /* libfiu - Fault Injection in Userspace
5  *
6  * This header, part of libfiu, is meant to be included in your project to
7  * avoid having libfiu as a mandatory build-time dependency.
8  *
9  * You can add it to your project, and #include it instead of fiu.h.
10  * The real fiu.h will be used only when FIU_ENABLE is defined.
11  *
12  * This header, as the rest of libfiu, is in the public domain.
13  *
14  * You can find more information about libfiu at
15  * http://blitiri.com.ar/p/libfiu.
16  */
17 
18 #ifndef _FAULT_INJECTION_H
19 #define _FAULT_INJECTION_H
20 
21 /* Only define the stubs when fiu is disabled, otherwise use the real fiu.h
22  * header */
23 #ifndef FIU_ENABLE
24 
25 #define fiu_init(flags) 0
26 #define fiu_fail(name) 0
27 #define fiu_failinfo() NULL
28 #define fiu_do_on(name, action)
29 #define fiu_exit_on(name)
30 #define fiu_return_on(name, retval)
31 
32 // Note: was `#define fault_injection_last_info() ""` but it triggers
33 static inline std::string fault_injection_last_info() { return ""; }
34 
35 #else
36 
37 #include <stdlib.h>
38 #include <sys/types.h>
39 #include <unistd.h>
40 #include <fstream>
41 #include <mutex>
42 #include <string>
43 
44 #include <fiu-control.h>
45 #include <fiu.h>
46 
47 static constexpr size_t fault_injection_info_bs = 256;
48 
49 static inline const char *fault_injection_info_fn() {
50  static std::mutex mutex;
51  static std::array<char, 128> info_fn{};
52 
53  std::lock_guard<std::mutex> lock(mutex);
54 
55  if (info_fn[0] != '\0') {
56  return info_fn.data();
57  }
58 
59  snprintf(info_fn.data(), info_fn.size(), "/tmp/fiu-ctrl-info-%lu", static_cast<uint64_t>(getpid()));
60 
61  return info_fn.data();
62 }
63 
64 static inline std::string fault_injection_last_info() {
65  auto info_id = reinterpret_cast<uint64_t>(fiu_failinfo());
66 
67  std::array<char, fault_injection_info_bs> arr{};
68  std::streamoff offset = (info_id & 0xfffffff) * fault_injection_info_bs;
69  std::ifstream f;
70  f.exceptions(std::ifstream::failbit | std::ifstream::badbit);
71 
72  try {
73  // check high bit of info_id to see if it should look into FIU_INFO_FILE or
74  // pid-dependent file name
75  const char *fn = nullptr;
76  if ((info_id & (1LU << 31)) != 0) {
77  fn = getenv("FIU_INFO_FILE");
78  } else {
79  fn = fault_injection_info_fn();
80  }
81  f.open(fn, std::ios::binary);
82  f.seekg(offset);
83  f.get(arr.data(), arr.size());
84 
85  std::string info(arr.data());
86  return info;
87  } catch (std::ifstream::failure &e) {
88  return "";
89  }
90 }
91 
92 // proxy for fiu_enable, with persisted failinfo (through a file)
93 static inline int fault_injection_enable(const char *name, int failnum, const std::string &failinfo,
94  unsigned int flags) {
95  std::array<char, fault_injection_info_bs> arr{};
96  std::copy(failinfo.cbegin(), failinfo.cend(), arr.data());
97 
98  size_t failinfo_id = 0;
99 
100  if (failinfo != "") {
101  std::ofstream f;
102  f.exceptions(std::ifstream::failbit | std::ifstream::badbit);
103 
104  try {
105  f.open(fault_injection_info_fn(), std::ios::binary | std::ios::app);
106  size_t fi_id = static_cast<size_t>(f.tellp()) / fault_injection_info_bs;
107  f.write(arr.data(), arr.size());
108  failinfo_id = fi_id;
109  } catch (std::ofstream::failure &e) {
110  }
111  }
112 
113  return fiu_enable(name, failnum, reinterpret_cast<void *>(failinfo_id), flags);
114 }
115 
116 // proxy for fiu_init, but also explicitly clears the persisted failinfo, in
117 // case it is lingering from a previous test case.
118 static inline void fault_injection_init() {
119  fiu_init(0);
120  std::ofstream f;
121  try {
122  f.open(fault_injection_info_fn(), std::ios::binary);
123  } catch (std::ofstream::failure &e) {
124  }
125 }
126 
127 #define fault_injection_disable fiu_disable
128 
129 #endif /* FIU_ENABLE */
130 
131 #endif /* _FAULT_INJECTION_H */