test-bpsys.cc 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. #include <vector>
  2. #include <utility>
  3. #include <algorithm>
  4. #include <memory>
  5. #include <map>
  6. #include <cstdlib>
  7. #include <cstring>
  8. #include <cerrno>
  9. #include "baseproc-sys.h"
  10. namespace {
  11. // which simulated file descriptors are currently "open"
  12. std::vector<bool> usedfds = {true, true, true};
  13. struct read_result
  14. {
  15. read_result(int errcode_p) : errcode(errcode_p) {}
  16. read_result(std::vector<char> &data_p) : errcode(0), data(data_p) {}
  17. read_result(std::vector<char> &&data_p) : errcode(0), data(std::move(data_p)) {}
  18. int errcode; // errno return
  19. std::vector<char> data; // data (if errcode == 0)
  20. };
  21. class read_cond : public std::vector<read_result>
  22. {
  23. public:
  24. using vector<read_result>::vector;
  25. // if blocking, return EAGAIN rather than end-of-file:
  26. bool is_blocking = false;
  27. };
  28. // map of fd to read results to supply for reads of that fd
  29. std::map<int,read_cond> read_data;
  30. // map of fd to the handler for writes to that fd
  31. std::map<int, std::unique_ptr<bp_sys::write_handler>> write_hndlr_map;
  32. // map of path to file content
  33. std::map<std::string, std::vector<char>> file_content_map;
  34. // environment variables, in "NAME=VALUE" form
  35. std::vector<char *> env_vars;
  36. } // anon namespace
  37. namespace bp_sys {
  38. char **environ = nullptr;
  39. int last_sig_sent = -1; // last signal number sent, accessible for tests.
  40. pid_t last_forked_pid = 1; // last forked process id (incremented each 'fork')
  41. // Test helper methods:
  42. void init_bpsys()
  43. {
  44. write_hndlr_map[0] = std::unique_ptr<bp_sys::write_handler> { new default_write_handler() };
  45. write_hndlr_map[1] = std::unique_ptr<bp_sys::write_handler> { new default_write_handler() };
  46. write_hndlr_map[2] = std::unique_ptr<bp_sys::write_handler> { new default_write_handler() };
  47. }
  48. // Allocate a file descriptor
  49. int allocfd()
  50. {
  51. return allocfd(new default_write_handler());
  52. }
  53. int allocfd(write_handler *whndlr)
  54. {
  55. auto f = std::find(usedfds.begin(), usedfds.end(), false);
  56. if (f == usedfds.end()) {
  57. int r = usedfds.size();
  58. usedfds.push_back(true);
  59. write_hndlr_map[r] = std::unique_ptr<bp_sys::write_handler>(whndlr);
  60. return r;
  61. }
  62. *f = true;
  63. auto r = f - usedfds.begin();
  64. write_hndlr_map[r] = std::unique_ptr<bp_sys::write_handler>(whndlr);
  65. return r;
  66. }
  67. // Supply data to be returned by read()
  68. void supply_read_data(int fd, std::vector<char> &data)
  69. {
  70. read_data[fd].emplace_back(data);
  71. }
  72. void supply_read_data(int fd, std::vector<char> &&data)
  73. {
  74. read_data[fd].emplace_back(std::move(data));
  75. }
  76. void set_blocking(int fd)
  77. {
  78. read_data[fd].is_blocking = true;
  79. }
  80. // retrieve data written via write()
  81. void extract_written_data(int fd, std::vector<char> &data)
  82. {
  83. auto &whandler = write_hndlr_map[fd];
  84. if (whandler == nullptr) abort();
  85. default_write_handler *dwhndlr = static_cast<default_write_handler *>(whandler.get());
  86. data = std::move(dwhndlr->data);
  87. }
  88. // Supply a file content
  89. void supply_file_content(const std::string &path, std::vector<char> &data)
  90. {
  91. file_content_map[path] = data;
  92. }
  93. void supply_file_content(const std::string &path, std::vector<char> &&data)
  94. {
  95. file_content_map[path] = std::move(data);
  96. }
  97. // Mock implementations of system calls:
  98. int open(const char *pathname, int flags)
  99. {
  100. auto i = file_content_map.find(pathname);
  101. if (i == file_content_map.end()) {
  102. errno = ENOENT;
  103. return -1;
  104. }
  105. int nfd = allocfd();
  106. supply_read_data(nfd, i->second);
  107. return nfd;
  108. }
  109. int pipe2(int fds[2], int flags)
  110. {
  111. fds[0] = allocfd();
  112. fds[1] = allocfd();
  113. return 0;
  114. }
  115. int close(int fd)
  116. {
  117. if (size_t(fd) >= usedfds.size()) abort();
  118. if (! usedfds[fd]) abort();
  119. usedfds[fd] = false;
  120. write_hndlr_map.erase(fd);
  121. return 0;
  122. }
  123. int kill(pid_t pid, int sig)
  124. {
  125. last_sig_sent = sig;
  126. return 0;
  127. }
  128. ssize_t read(int fd, void *buf, size_t count)
  129. {
  130. read_cond & rrs = read_data[fd];
  131. if (rrs.empty()) {
  132. if (rrs.is_blocking) {
  133. errno = EAGAIN;
  134. return -1;
  135. }
  136. return 0;
  137. }
  138. read_result &rr = rrs.front();
  139. if (rr.errcode != 0) {
  140. errno = rr.errcode;
  141. // Remove the result record:
  142. auto i = rrs.begin();
  143. i++;
  144. rrs.erase(rrs.begin(), i);
  145. return -1;
  146. }
  147. auto dsize = rr.data.size();
  148. if (dsize <= count) {
  149. // Consume entire result:
  150. std::copy_n(rr.data.begin(), dsize, (char *)buf);
  151. // Remove the result record:
  152. rrs.erase(rrs.begin());
  153. return dsize;
  154. }
  155. // Consume partial result:
  156. std::copy_n(rr.data.begin(), count, (char *)buf);
  157. rr.data.erase(rr.data.begin(), rr.data.begin() + count);
  158. return count;
  159. }
  160. ssize_t write(int fd, const void *buf, size_t count)
  161. {
  162. return write_hndlr_map[fd]->write(fd, buf, count);
  163. }
  164. ssize_t writev(int fd, const struct iovec *iov, int iovcnt)
  165. {
  166. ssize_t r = 0;
  167. for (int i = 0; i < iovcnt; i++) {
  168. ssize_t wr = write(fd, iov[i].iov_base, iov[i].iov_len);
  169. if (wr < 0) {
  170. if (r > 0) {
  171. return r;
  172. }
  173. return wr;
  174. }
  175. r += wr;
  176. if (size_t(wr) < iov[i].iov_len) {
  177. return r;
  178. }
  179. }
  180. return r;
  181. }
  182. char *getenv(const char *name)
  183. {
  184. size_t name_len = strlen(name);
  185. for (auto *var : env_vars) {
  186. if (strncmp(name, var, name_len) == 0) {
  187. if (var[name_len] == '=') {
  188. return &(var[name_len + 1]);
  189. }
  190. }
  191. }
  192. return nullptr;
  193. }
  194. int setenv(const char *name, const char *value, int overwrite)
  195. {
  196. size_t name_len = strlen(name);
  197. if (env_vars.empty()) {
  198. env_vars.push_back(nullptr);
  199. }
  200. else for (unsigned i = 0; i < (env_vars.size() - 1); ++i) {
  201. if (strncmp(name, env_vars[i], name_len) == 0) {
  202. if (env_vars[i][name_len] == '=') {
  203. // name matches, replace the value
  204. if (overwrite) {
  205. delete[](env_vars[i]);
  206. env_vars[i] = new char[name_len + 1 + strlen(value) + 1];
  207. strcpy(env_vars[i], name);
  208. env_vars[i][name_len] = '=';
  209. strcpy(env_vars[i] + name_len + 1, value);
  210. }
  211. return 0;
  212. }
  213. }
  214. }
  215. // not found, add
  216. char *new_var = new char[name_len + 1 + strlen(value) + 1];
  217. strcpy(new_var, name);
  218. new_var[name_len] = '=';
  219. strcpy(new_var + name_len + 1, value);
  220. env_vars[env_vars.size() - 1] = new_var;
  221. env_vars.push_back(nullptr);
  222. environ = env_vars.data();
  223. return 0;
  224. }
  225. int clearenv()
  226. {
  227. for (char *env_var : env_vars) {
  228. delete[](env_var);
  229. }
  230. env_vars.clear();
  231. environ = nullptr;
  232. return 0;
  233. }
  234. }