A quick and dirty shell implementation for A.U.TH. (Operating systems Lab)
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 

275 linhas
8.3 KiB

  1. /*
  2. * child.cpp
  3. *
  4. * Created on: Feb 11, 2019
  5. * Author: hoo2
  6. */
  7. #include "sequencer.h"
  8. namespace snel {
  9. //! A type-safe memcpy
  10. template <typename T>
  11. void memcpy (T* to, const T* from, size_t n) {
  12. for (size_t i=0 ; i<n ; ++i)
  13. *to++ = *from++;
  14. }
  15. /*!
  16. * Split a string to tokens and store them in a container, using a delimiter
  17. * character.
  18. * \note
  19. * Requires: container with push_back functionality
  20. * @param str
  21. * @param cont
  22. * @param delim
  23. */
  24. template <typename T, typename Container>
  25. void split(const std::basic_string<T>& str, Container& cont, T delim) {
  26. std::basic_stringstream<T> ss(str);
  27. std::basic_string<T> token;
  28. while (std::getline(ss, token, delim)) {
  29. cont.push_back(token);
  30. }
  31. }
  32. std::string filter (const std::string in) {
  33. std::string out;
  34. char prev {0}, cur, next {0};
  35. for (auto i = in.begin(); i != in.end() ; ++i) {
  36. cur = *i;
  37. if (cur == '|') {
  38. if (prev != ' ') out += ' ';
  39. next = *++i;
  40. if (next == '|' || next == ' ') {
  41. out += cur; cur = next; // syntax ok
  42. }
  43. else {
  44. // syntax problem, insert a space
  45. out += cur; out += ' '; cur = next;
  46. }
  47. }
  48. prev = cur;
  49. out += cur;
  50. }
  51. return out;
  52. }
  53. /*
  54. * ========== ArgList ==========
  55. */
  56. ArgList::~ArgList() {
  57. for (vtype p : args_) {
  58. if (p != nullptr)
  59. delete[] p;
  60. }
  61. }
  62. ArgList& ArgList::push_back(const std::string& item) {
  63. vtype it = new type[item.length()+1];
  64. // get data
  65. memcpy (it, item.c_str(), item.length());
  66. it[item.length()] = 0;
  67. // update the argument vector
  68. args_.back() = it;
  69. args_.push_back(nullptr);
  70. return *this;
  71. }
  72. /*
  73. * ========== Child ==========
  74. */
  75. Child::~Child () {
  76. for (int i=0 ; i<3 ; ++i)
  77. restore_std_if(i);
  78. // close any leaked pipes
  79. // if (pipe_.fd[0] != -1) close(pipe_.fd[0]);
  80. // if (pipe_.fd[1] != -1) close(pipe_.fd[1]);
  81. }
  82. void Child::redirect_std_if(std::string fn, fd_t std_fd) {
  83. if (fn != "") {
  84. if ((files[std_fd] = openat(AT_FDCWD, fn.c_str(), O_RDWR | O_CREAT, 0640)) == -1)
  85. throw Error ("Child: Can not open file");
  86. if ((sstd[std_fd] = dup (std_fd)) == -1) // save STDxxx
  87. throw Error ("Child: Can not create file descriptor");
  88. if ((dup2(files[std_fd], std_fd)) == -1) // use input as STDIN_
  89. throw Error ("Child: Can not redirect file descriptor");
  90. }
  91. }
  92. void Child::restore_std_if(fd_t std_fd) {
  93. if (sstd[std_fd] != -1) {
  94. dup2(sstd[std_fd], std_fd);
  95. close (sstd[std_fd]);
  96. sstd[std_fd] = -1;
  97. }
  98. if (files[std_fd] != -1) {
  99. close (files[std_fd]);
  100. files[std_fd] = -1;
  101. }
  102. }
  103. Child& Child::make_arguments () {
  104. bool in{false}, out{false}, err{false};
  105. bool CanRedirectIn = (!pipe_.from) ? true : false;
  106. bool CanRedirectOut = (!pipe_.to) ? true : false;
  107. for (auto& t: command) {
  108. if (t == "" || t== " " || t=="|") continue; // skip crap
  109. if (t == "&&") logic = LogicOp::AND;
  110. else if (t == "||") logic = LogicOp::OR;
  111. // one pass redirection parsing
  112. else if (CanRedirectIn && !t.compare(0, 1, "<"))
  113. filenames[STDIN_] = t.substr(1);
  114. else if (CanRedirectOut&& !t.compare(0, 1, ">"))
  115. filenames[STDOUT_] = t.substr(1);
  116. else if (CanRedirectOut&& !t.compare(0, 2, "1>"))
  117. filenames[STDOUT_] = t.substr(2);
  118. else if (!t.compare(0, 2, "2>"))
  119. filenames[STDERR_] = t.substr(2);
  120. // two pass redirection parsing (if redirection came in 2 arguments)
  121. else if (t == "<") in = true;
  122. else if (t == "1>" || t == ">") out = true;
  123. else if (t == "2>") err = true;
  124. else if (in) {
  125. if (CanRedirectIn)
  126. filenames[STDIN_] = t;
  127. in = false;
  128. }
  129. else if (out) {
  130. if (CanRedirectOut)
  131. filenames[STDOUT_] = t;
  132. out = false;
  133. }
  134. else if (err) {
  135. filenames[STDERR_] = t; err = false;
  136. }
  137. else
  138. arguments.push_back(t);
  139. }
  140. return *this;
  141. }
  142. bool Child::execute(std::vector<Child>::iterator it, bool first) {
  143. bool stop = {false};
  144. if (!first) --it;
  145. Child& previous = *it;
  146. // Check parent redirection
  147. redirect_std_if (filenames[STDIN_], STDIN_);
  148. redirect_std_if (filenames[STDOUT_], STDOUT_);
  149. redirect_std_if (filenames[STDERR_], STDERR_);
  150. // Check parent pipe control
  151. if (pipe_.to) {
  152. if((::pipe (pipe_.fd)) == -1)
  153. throw Error("Child: Can not create pipe");
  154. }
  155. pid_t pid = fork();
  156. if (pid < 0) {
  157. throw Error("Child: Can not create child process");
  158. }
  159. else if (pid == 0) { // child
  160. // Some extra pipe checking while we still have our data
  161. if (pipe_.to) { // transmitting child
  162. close(pipe_.fd[0]); // close the read end
  163. if ((dup2(pipe_.fd[1], STDOUT_)) == -1) // redirect output
  164. throw Error("Child pipe[to]: Can not redirect through pipe");
  165. }
  166. else if (!first && pipe_.from) { // receiveing child
  167. close (previous.pipe().fd[1]); // close the write end
  168. if ((dup2(previous.pipe().fd[0], STDIN_)) == -1) // redirect input
  169. throw Error("Child pipe[from]: Can not redirect through pipe");
  170. }
  171. execvp(arguments.front(), arguments.data());
  172. // error if we got here
  173. std::cout << "Can not invoke: " << arguments.front() << std::endl;
  174. throw Error("Child: Can not run child process");
  175. }
  176. else { // parent
  177. if (pipe_.to) close (pipe_.fd[1]);
  178. else if (!first && pipe_.from)
  179. close (previous.pipe().fd[0]);
  180. int exit_status;
  181. waitpid(pid, &exit_status, 0); // wait child process to finish
  182. restore_std_if (STDIN_);
  183. restore_std_if (STDOUT_);
  184. restore_std_if (STDERR_);
  185. switch (logic) {
  186. case LogicOp::AND:
  187. if (exit_status) stop = true;
  188. break;
  189. case LogicOp::OR:
  190. if (!exit_status) stop = true;
  191. break;
  192. default: break;
  193. }
  194. }
  195. return stop;
  196. }
  197. /*
  198. * ======== Sequencer ===========
  199. */
  200. Sequencer& Sequencer::parse (const std::string& input) {
  201. std::vector<std::string> commands;
  202. std::vector<std::string> tokens;
  203. Child::command_t command;
  204. split (input, commands, ';'); // split all commands
  205. for (auto& s : commands) {
  206. command.clear(); //clear child tokens
  207. tokens.clear(); // make a new token vector for command
  208. split (s, tokens, ' ');
  209. seq_.emplace_back(std::vector<Child>{}); // make a new child for command
  210. // check tokens inside command
  211. bool from = false;
  212. for (auto& t: tokens) {
  213. command.push_back(t); // get current token
  214. if (is_seperator(t)) {
  215. // construct a child with what we have so far and clear command
  216. seq_.back().emplace_back(command);
  217. command.clear();
  218. if (from) {
  219. seq_.back().back().pipe().from = from;
  220. from = false;
  221. }
  222. if (is_pipe(t)) {
  223. seq_.back().back().pipe().to = true;
  224. from = true;
  225. }
  226. }
  227. }
  228. seq_.back().emplace_back(command); // construct the child with tokens
  229. if (from)
  230. seq_.back().back().pipe().from = from;
  231. }
  232. return *this;
  233. }
  234. Sequencer& Sequencer::execute() {
  235. for (auto& batch : seq_) {
  236. bool first;
  237. first = true;
  238. for (auto it = batch.begin() ; it != batch.end(); ++it) {
  239. Child& command = *it;
  240. if (command.make_arguments().execute(it, first))
  241. break;
  242. first = false;
  243. }
  244. }
  245. seq_.clear();
  246. return *this;
  247. }
  248. }