mysh.c 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. /*
  2. * File: mysh.c
  3. * Author: Arthur Brandao
  4. *
  5. * Created on 31 octobre 2018, 12:43
  6. */
  7. #define _POSIX_C_SOURCE 2
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <unistd.h>
  11. #include <fcntl.h>
  12. #include <sys/stat.h>
  13. #include <wait.h>
  14. #include "error.h"
  15. #include "str.h"
  16. #include "parser.h"
  17. #include "command.h"
  18. #include "execute.h"
  19. #include "mysh.h"
  20. #include "pipe_cste.h"
  21. /* --- Extern --- */
  22. extern Error error;
  23. extern boolean exitsh;
  24. /* --- Global --- */
  25. pid_list pidlist;
  26. pid_node* active = NULL;
  27. /* --- Fonctions privées --- */
  28. void test_write() {
  29. char* a = "azerty\n";
  30. int tmp = write(1, a, strlen(a));
  31. printf("%d\n", tmp);
  32. }
  33. void test_tmp_file(){
  34. int a;
  35. FILE* f = tmpfile();
  36. printf("F : %d\n", f == NULL);
  37. int fd = fileno(f);
  38. printf("%d : %ld\n", fd, write(fd, "bonjour", 8));
  39. a = lseek(fd, 0L, SEEK_SET);
  40. sleep(2);
  41. char buf[10];
  42. memset(buf, 0 , 10);
  43. a = read(fd, buf, 10);
  44. printf("%d : %s\n", a, buf);
  45. close(fd);
  46. }
  47. void test(){
  48. CommandTab ct;
  49. char str[BUFFER_SIZE];
  50. int a;
  51. //Initialisation structures
  52. error_finit("mysh.log");
  53. ini_pid_list(&pidlist);
  54. //Recup ligne
  55. //printf("%s\n", fgets(str, 500, stdin));&
  56. memset(str, 0, 500);
  57. a = read(STDIN, str, 500);
  58. printf("%s\n", str);
  59. //Separe les commandes
  60. a = parse_line(&ct, str);
  61. if(a == SHELL_ERR){
  62. addserror("Erreur lors du parse de la ligne");
  63. error.exit_err();
  64. }
  65. //Parse les commandes
  66. a = parse_all_command(&ct);
  67. if(a == SHELL_FAIL){
  68. addserror("Erreur lors du parse des commandes");
  69. error.exit_err();
  70. }
  71. //Affiche resultat
  72. for (int i = 0; i < ct.length; i++) {
  73. Command* c = ct.cmd[i];
  74. printf("Commande %d (%s) : \n", i, c->name);
  75. for (int j = 0; j < c->argc; j++) {
  76. printf(" Argument %d : %s\n", j, c->argv[j]);
  77. }
  78. printf("Commande en fond : %d\n\n", ct.bck);
  79. //Si c'est une commande interne on l'execute
  80. if(is_internal_cmd(ct.cmd[i]->name)){
  81. show_current_dir(NULL, "\n");
  82. printf("Result : %d\n", launch_internal_command(ct.cmd[i]));
  83. show_current_dir(NULL, "\n");
  84. }
  85. }
  86. //Nettoyage structures
  87. clean_command(&ct);
  88. clean_pid(&pidlist);
  89. error.exit();
  90. }
  91. /* --- Fonctions utilitaires --- */
  92. void show_current_dir(const char* before, const char* after) {
  93. char buffer[BUFFER_SIZE];
  94. if (getcwd(buffer, sizeof (buffer)) == NULL) {
  95. addperror("Erreur getcwd()");
  96. } else {
  97. if(before == NULL && after == NULL){
  98. printf("%s", buffer);
  99. } else if(before == NULL){
  100. printf("%s%s", buffer, after);
  101. } else if(after == NULL){
  102. printf("%s%s", before, buffer);
  103. } else {
  104. printf("%s%s%s", before, buffer, after);
  105. }
  106. }
  107. fflush(stdout);
  108. }
  109. int get_line(char* buffer){
  110. memset(buffer, 0, BUFFER_SIZE);
  111. if(read(STDIN, buffer, BUFFER_SIZE) == ERR){
  112. addperror("Impossible de lire dans STDIN");
  113. return SHELL_ERR;
  114. }
  115. return SHELL_OK;
  116. }
  117. int get_tmp_file(){
  118. FILE* f = tmpfile();
  119. if(f == NULL){
  120. adderror("Impossible de créer un fichier temporaire");
  121. return SHELL_ERR;
  122. }
  123. return fileno(f);
  124. }
  125. /* --- Main --- */
  126. int main(int argc, char* argv[]) {
  127. //Declaration variables
  128. CommandTab ct;
  129. int result;
  130. char line[BUFFER_SIZE], before[BUFFER_SIZE];
  131. //Initialisation structures
  132. error_finit("mysh.log");
  133. ini_pid_list(&pidlist);
  134. //Preparation affichage
  135. sprintf(before, "\x1b[32m%s:\x1b[36m", getlogin());
  136. //Boucle infini de lecture
  137. while(!exitsh){
  138. //Affichage repertoire
  139. show_current_dir(before, ">\x1b[0m ");
  140. //Lecture ligne
  141. if(get_line(line) == SHELL_ERR){
  142. error.print("Impossible de lire les commandes\n");
  143. clean_pid(&pidlist);
  144. error.exit_err();
  145. }
  146. //Parse la ligne et commandes
  147. result = parse_line(&ct, line);
  148. if(result == SHELL_ERR){
  149. error.print("Impossible d'analyser la ligne\n");
  150. addserror("Erreur lors du parse de la ligne");
  151. continue;
  152. }
  153. //Si aucune commande on passe
  154. printf("%d\n", ct.length);
  155. if(ct.length == 0){
  156. clean_command(&ct);
  157. continue;
  158. }
  159. //Parse les commandes
  160. result = parse_all_command(&ct);
  161. if(result == SHELL_FAIL){
  162. error.print("Impossible d'analyser la commande\n");
  163. addserror("Erreur lors du parse des commandes");
  164. continue;
  165. }
  166. //Execute
  167. result = run(ct);
  168. printf("Result : %d\n", result);
  169. //Vide le resultat du parse de la ligne de commande
  170. clean_command(&ct);
  171. }
  172. //Nettoyage
  173. clean_pid(&pidlist);
  174. error.end();
  175. return EXIT_SUCCESS;
  176. }
  177. int run(CommandTab ct){
  178. pid_t pid;
  179. int result = 0;
  180. //Si en fond creation d'un fork pour executer les commandes
  181. printf("bck : %d\n", ct.bck);
  182. if(ct.bck && false/*ToDo - Test plus tard*/){
  183. pid = fork();
  184. if(pid == ERR){
  185. addperror("Erreur lors du fork pour l'execution des commandes");
  186. error.print("Erreur systeme, impossible de continuer\n");
  187. return SHELL_ERR;
  188. }
  189. //Fils
  190. if(pid == 0){
  191. ct.bck = 0;
  192. result = run(ct);
  193. if(result == SHELL_FAIL){
  194. exit(EXIT_FAILURE);
  195. }
  196. exit(EXIT_SUCCESS);
  197. }
  198. //Ajout du fils dans la liste des pid
  199. add_pid(&pidlist, pid);
  200. //Pour le pere c'est fini
  201. return SHELL_OK;
  202. }
  203. //Sinon execution de chaque commande
  204. Command* c;
  205. int* tube[ct.length];
  206. int tubepos = 0;
  207. int infd = -1, outfd = -1, errfd = -1;
  208. //Parcours les commandes
  209. for(int i = 0; i < ct.length; i++){
  210. c = ct.cmd[i];
  211. printf("Cmd : %s\n", c->name);
  212. //Si pipe creation d'un fichier commun
  213. if(c->next == SHELL_PIPE){
  214. int tab[2];
  215. tube[tubepos] = tab;
  216. //Si il n'y a pas deja une redirection de sortie
  217. if(c->output == STDOUT){
  218. //Creation tube
  219. if(pipe(tube[tubepos]) == ERR){
  220. addperror("Impossible de créer un tube");
  221. return SHELL_FAIL;
  222. }
  223. //Tube non bloquant
  224. c->output = tube[tubepos][TUBE_ECRITURE];
  225. //Redirige l'entrée du suivant
  226. if(ct.cmd[i + 1]->input == STDIN){
  227. ct.cmd[i + 1]->input = tube[tubepos][TUBE_LECTURE];
  228. }
  229. }
  230. }
  231. //Effectue les redirections IO
  232. if(c->input != STDIN){
  233. infd = redirect_fd(STDIN, c->input);
  234. if(infd == ERR){
  235. return SHELL_FAIL;
  236. }
  237. }
  238. if(c->output != STDOUT){
  239. outfd = redirect_fd(STDOUT, c->output);
  240. if(outfd == ERR){
  241. return SHELL_FAIL;
  242. }
  243. }
  244. if(c->error != STDERR){
  245. errfd = redirect_fd(STDERR, c->error);
  246. if(errfd == ERR){
  247. return SHELL_FAIL;
  248. }
  249. }
  250. //Execute la commande
  251. if(is_internal_cmd(c->name)){
  252. result = launch_internal_command(c);
  253. } else if(is_executable_file(c->name)){
  254. result = exec_file(c->name, c->argv);
  255. } else {
  256. result = exec_shell(c->name, c->argv);
  257. }
  258. printf("%d\n", result);
  259. //Reset IO
  260. if(c->input != STDIN){
  261. infd = redirect_fd(STDIN, infd);
  262. if(infd == ERR){
  263. return SHELL_FAIL;
  264. }
  265. }
  266. if(c->output != STDOUT){
  267. outfd = redirect_fd(STDOUT, outfd);
  268. if(outfd == ERR){
  269. return SHELL_FAIL;
  270. }
  271. }
  272. if(c->error != STDERR){
  273. errfd = redirect_fd(STDERR, errfd);
  274. if(errfd == ERR){
  275. return SHELL_FAIL;
  276. }
  277. }
  278. //Fermeture tube
  279. if(c->next == SHELL_PIPE){
  280. if(close(tube[tubepos++][TUBE_ECRITURE]) == ERR){
  281. addperror("Impossible de fermer tube ecriture");
  282. return SHELL_FAIL;
  283. }
  284. c->output = STDOUT;
  285. }
  286. //Agit en fonction de la jointure avec la prochaine commande
  287. /*ToDo*/
  288. }
  289. if(result != EXIT_SUCCESS){
  290. return SHELL_FAIL;
  291. }
  292. return SHELL_OK;
  293. }