Quellcode durchsuchen

Merge pull request #14 from Loquicom/exec

Execution des commandes
Loquicom vor 6 Jahren
Ursprung
Commit
e85d1b9b01
15 geänderte Dateien mit 883 neuen und 88 gelöschten Zeilen
  1. 177 0
      command.c
  2. 55 0
      command.h
  3. 4 0
      constante.h
  4. 18 1
      error.c
  5. 9 1
      error.h
  6. 99 0
      execute.c
  7. 25 0
      execute.h
  8. 7 4
      makefile
  9. 350 37
      mysh.c
  10. 11 6
      mysh.h
  11. 49 15
      parser.c
  12. 1 1
      parser.h
  13. 7 3
      str.c
  14. 69 18
      wildcard.c
  15. 2 2
      wildcard.h

+ 177 - 0
command.c

@@ -0,0 +1,177 @@
+/* 
+ * File:   command.c
+ * Author: Arthur Brandao
+ *
+ * Created on 9 novembre 2018
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "error.h"
+#include "str.h"
+#include "parser.h"
+#include "mysh.h"
+#include "execute.h"
+#include "command.h"
+
+/* --- Extern --- */
+extern Error error;
+extern pid_t last;
+extern int status_cmd;
+extern int result_cmd;
+char* cmdlist[NB_CMD] = {
+    "cd",
+    "exit",
+    "status",
+    NULL
+};
+boolean exitsh = false;
+
+/* --- Fonctions publiques --- */
+void ini_pid_list(pid_list* pl) {
+    pl->first = NULL;
+    pl->last = NULL;
+}
+
+pid_node* add_pid(pid_list* pl, pid_t pid, int job) {
+    pid_node* pn = malloc(sizeof (pid_node));
+    pn->pid = pid;
+    pn->job = job;
+    pn->next = NULL;
+    if (pl->first == NULL) {
+        pn->prev = NULL;
+        pl->first = pn;
+        pl->last = pn;
+    } else {
+        pn->prev = pl->last;
+        pl->last->next = pn;
+        pl->last = pn;
+    }
+    return pn;
+}
+
+pid_node* search_pid(pid_list* pl, pid_t pid) {
+    pid_node* pn = pl->first;
+    while (pn != NULL) {
+        if (pn->pid == pid) {
+            return pn;
+        }
+        pn = pn->next;
+    }
+    return NULL;
+}
+
+void remove_pid(pid_list* pl, pid_node* pn) {
+    //Si 1er et seul
+    if (pn->prev == NULL && pn->next == NULL) {
+        pl->first = NULL;
+        pl->last = NULL;
+    }        
+    //Si 1er et non seul
+    else if (pn->prev == NULL && pn->next != NULL) {
+        pn->next->prev = NULL;
+        pl->first = pn->next;
+    }        
+    //Si dernier
+    else if (pn->next == NULL) {
+        pn->prev->next = NULL;
+        pl->last = pn->prev;
+    }        
+    //Sinon si il est au milieu
+    else {
+        pn->prev->next = pn->next;
+        pn->next->prev = pn->prev;
+    }
+    //Free
+    free(pn);
+}
+
+void clean_pid(pid_list* pl) {
+    pid_node* tmp, * pn = pl->first;
+    while (pn != NULL) {
+        tmp = pn->next;
+        free(pn);
+        pn = tmp;
+    }
+    pl->first = NULL;
+    pl->last = NULL;
+}
+
+boolean is_internal_cmd(const char* cmd) {
+    //Parcours tableau pour trouver correspondance
+    for (int i = 0; cmdlist[i] != NULL; i++) {
+        if (strncmp(cmd, cmdlist[i], strlen(cmd)) == 0) {
+            return true;
+        }
+    }
+    return false;
+}
+
+int launch_internal_command(Command* cmd) {
+    int result, length = strlen(cmd->name) + 1;
+    //cd
+    if (strncmp(cmd->name, cmdlist[0], length) == 0) {
+        result = cd(cmd->argc, cmd->argv);
+        return result;
+    } 
+    //exit
+    else if (strncmp(cmd->name, cmdlist[1], length) == 0) {
+        result = exit_sh(cmd->argc, cmd->argv);
+        return result;
+    }
+    //status
+    else if (strncmp(cmd->name, cmdlist[2], length) == 0) {
+        result = status(cmd->argc, cmd->argv);
+        return result;
+    }
+    //Aucune commande
+    else {
+        return SHELL_FAIL;
+    }
+}
+
+/* --- Commandes --- */
+int cd(int argc, char** argv) {
+    //Si trop d'arguments
+    if (argc > 2) {
+        error.print("too many arguments : 1 required, %d given\n", argc - 1);
+        return EXIT_FAILURE;
+    } else {
+        //Si aucun argument on va à la racine
+        if (argc == 1) {
+            if (chdir("/") == ERR) {
+                addperror("Erreur chdir()");
+                return EXIT_FAILURE;
+            }
+        }
+        //Sinon on va dans le dossier indiqué par l'utilisateur
+        else {
+            if (chdir(argv[1]) == ERR) {
+                error.print("path does not exist\n");
+                return EXIT_FAILURE;
+            }
+        }
+    }
+    return EXIT_SUCCESS;
+    //show_current_dir("current working directory is: ", "\n");
+}
+
+int exit_sh(int argc, char** argv){
+    exitsh = true;
+    return EXIT_SUCCESS;
+}
+
+int status(int argc, char** argv){
+    if(!(last != -1 && status_cmd != -1)){
+        error.print("Aucune commande executée\n");
+        return EXIT_FAILURE;
+    }
+    //En fonction du status
+    if(result_cmd == SHELL_FAIL){
+        printf("%d terminé anormalement\n", last);
+    } else {
+        printf("%d terminé avec comme code de retour %d\n", last, status_cmd);
+    }
+    return EXIT_SUCCESS;
+}

+ 55 - 0
command.h

@@ -0,0 +1,55 @@
+/* 
+ * File:   command.h
+ * Author: Arthur Brandao
+ *
+ * Created on 9 novembre 2018
+ */
+
+#ifndef COMMAND_H
+#define COMMAND_H
+
+/* --- Include --- */
+#include <sys/types.h>
+#include "constante.h"
+
+/* --- Constante --- */
+#define NB_CMD 4
+
+/* --- Structure --- */
+typedef struct pid_node pid_node;
+struct pid_node{
+    pid_t pid;
+    int job;
+    pid_node* prev;
+    pid_node* next;
+};
+typedef struct{
+    pid_node* first;
+    pid_node* last;
+}pid_list;
+
+/* --- Extern --- */
+extern char* cmdlist[NB_CMD];
+extern boolean exitsh;
+
+/* --- Fonctions --- */
+void ini_pid_list(pid_list*);
+pid_node* add_pid(pid_list*, pid_t, int);
+pid_node* search_pid(pid_list*, pid_t);
+void remove_pid(pid_list*, pid_node*);
+void clean_pid(pid_list*);
+boolean is_internal_cmd(const char*);
+int launch_internal_command(Command*);
+
+/* --- Commandes --- */
+/**
+ * Change le dossier de travail actuel
+ * @param int argc
+ * @param char** argv
+ */
+int cd(int, char**);
+int exit_sh(int, char**);
+int status(int, char**);
+
+#endif /* COMMAND_H */
+

+ 4 - 0
constante.h

@@ -19,6 +19,10 @@
 #define STDOUT 1
 #define STDERR 2
 
+/* --- Tube --- */
+#define TUBE_LECTURE 0
+#define TUBE_ECRITURE 1
+
 /* --- Separateur commande --- */
 #define SHELL_END 0 //Aucune autre commande après
 #define SHELL_NONE 1 //Aucun lien entre les 2 commandes

+ 18 - 1
error.c

@@ -40,7 +40,7 @@ void end(){
     fprintf(stderr, "----- Fin log processus %d (temps en seconde : %ld) -----\n", getpid(), temps);
     //On remet la sortie standard des erreurs
     fd = redirect_fd(STDERR_FILENO, error.errfd);
-    if(error.errfd == ERR){
+    if(fd == ERR){
         adderror("Impossible de rediriger la sortie d'erreur standard");
         return;
     }
@@ -130,6 +130,23 @@ int redirect_fd(int fd1, int fd2){
     return tmpfd;
 }
 
+int redirect_fd2(int fd1, int fd2){
+    int tmpfd;
+    //On duplique le 1er fd
+    tmpfd = dup(fd1);
+    if(tmpfd == ERR){
+        addperror("Erreur pendant la duplication");
+        return ERR;
+    }
+    //On fait en sorte que fd1 soit lié au fichier de fd2
+    if(dup2(fd2, fd1) == ERR){
+        addperror("Erreur pendant le changement de fd");
+        return ERR;
+    }
+    //On retourne le nouveau fd de fd1
+    return tmpfd;
+}
+
 void error_init(){
     //Creation nom fichier puis initialisation
     char filename[19];

+ 9 - 1
error.h

@@ -60,11 +60,19 @@ extern Error error;
 /**
  * Change un fd par la valeur d'un autre fd
  * @param int fd accueil
- * @param int fd source
+ * @param int fd source fermé par la fonction
  * @return int Le nouveau fd du fichier qui avait le fd d'accueil
  */
 int redirect_fd(int, int);
 
+/**
+ * Change un fd par la valeur d'un autre fd
+ * @param int fd accueil
+ * @param int fd source
+ * @return int Le nouveau fd du fichier qui avait le fd d'accueil
+ */
+int redirect_fd2(int, int);
+
 /**
  * Initialise la gestion d'erreur
  * Le log sera nommé err-timestamp.log

+ 99 - 0
execute.c

@@ -0,0 +1,99 @@
+/* 
+ * File:   execute.c
+ * Author: Arthur Brandao
+ *
+ * Created on 9 novembre 2018
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <wait.h>
+#include "error.h"
+#include "execute.h"
+
+/* --- Extern --- */
+extern Error error;
+pid_t active = -1;
+pid_t last = -1;
+
+/* --- Fonctions publiques --- */
+boolean is_executable_file(const char * cmd) {
+    int result;
+    result = access(cmd, X_OK);
+    if(result == ERR){
+        return false;
+    }
+    return true;
+}
+
+int exec_shell(char* name, char** argv){
+    pid_t pid;  
+    int result;
+    //Fork pour l'exec
+    pid = fork();
+    if(pid == ERR){
+        addperror("Erreur lors du fork pour la commande execvp");
+        return EXIT_FAILURE;
+    }
+    //Fils
+    else if(pid == 0){
+        //Reset sortie erreur
+        result = redirect_fd(STDERR, error.errfd);
+        if(result == ERR){
+            adderror("Impossible de redefinir la sortie d'erreur standard");
+            exit(EXIT_FAILURE);
+        }
+        //Execute commande
+        execvp(name, argv);
+        //Si on arrive ici alors erreur
+        addperror("Impossible d'executer la commande");
+        exit(EXIT_FAILURE);
+    }
+    //Pere
+    active = pid;
+    wait(&result);
+    last = pid;
+    active = -1;
+    //Retourne retour fils
+    if(WIFEXITED(result)){
+        return WEXITSTATUS(result);
+    }
+    return EXIT_FAILURE;
+}
+
+int exec_file(char* name, char** argv){
+    pid_t pid;  
+    int result;
+    //Fork pour l'exec
+    pid = fork();
+    if(pid == ERR){
+        addperror("Erreur lors du fork pour la commande execvp");
+        return EXIT_FAILURE;
+    }
+    //Fils
+    else if(pid == 0){
+        //Reset sortie erreur
+        result = redirect_fd(STDERR, error.errfd);
+        if(result == ERR){
+            adderror("Impossible de redefinir la sortie d'erreur standard");
+            exit(EXIT_FAILURE);
+        }
+        //Execute commande
+        execv(name, argv);
+        //Si on arrive ici alors erreur
+        addperror("Impossible d'executer la commande");
+        exit(EXIT_FAILURE);
+    }
+    //Pere
+    active = pid;
+    wait(&result);
+    last = pid;
+    active = -1;
+    //Retourne retour fils
+    if(WIFEXITED(result)){
+        return WEXITSTATUS(result);
+    }
+    return EXIT_FAILURE;
+}

+ 25 - 0
execute.h

@@ -0,0 +1,25 @@
+/* 
+ * File:   execute.h
+ * Author: Arthur Brandao
+ *
+ * Created on 9 novembre 2018
+ */
+
+#ifndef EXECUTE_H
+#define EXECUTE_H
+
+/* --- Include --- */
+#include <sys/types.h>
+#include "constante.h"
+
+/* --- Extern --- */
+extern pid_t active;
+extern pid_t last;
+
+/* --- Fonctions publiques --- */
+boolean is_executable_file(const char *);
+int exec_shell(char*, char**);
+int exec_file(char*, char**);
+
+#endif /* EXECUTE_H */
+

+ 7 - 4
makefile

@@ -3,7 +3,7 @@
 #
 
 EXEC = mysh
-OBJETS = error.o str.o parser.o wildcard.o
+OBJETS = error.o str.o parser.o wildcard.o command.o execute.o
 NOM_PROJET = mini-shell
 
 #
@@ -88,8 +88,11 @@ archive: clean
 	@echo "Termine."
 
 # DEPENDANCES
-error.o: error.c error.h
+error.o: error.c str.h error.h
 str.o: str.c str.h
-parser.o: parser.c error.h wildcard.h constante.h parser.h str.h
+parser.o: parser.c error.h str.h wildcard.h constante.h parser.h
 wildcard.o: wildcard.c error.h wildcard.h constante.h
-mysh.o: mysh.c error.h parser.h constante.h str.h mysh.h
+command.o: command.c error.h str.h parser.h constante.h command.h
+execute.o: execute.c error.h execute.h constante.h
+mysh.o: mysh.c error.h str.h parser.h constante.h command.h execute.h \
+ mysh.h

+ 350 - 37
mysh.c

@@ -4,20 +4,35 @@
  *
  * Created on 31 octobre 2018, 12:43
  */
+#define _POSIX_C_SOURCE 2
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <wait.h>
+#include <signal.h>
 #include "error.h"
 #include "str.h"
 #include "parser.h"
+#include "command.h"
+#include "execute.h"
 #include "mysh.h"
 
-#include <sys/types.h>
-#include <sys/stat.h>
-
 /* --- Extern --- */
 extern Error error;
+extern boolean exitsh;
+extern pid_t active;
+int status_cmd = -1;
+int result_cmd = -1;
+
+/* --- Global --- */
+pid_list pidlist;
+boolean fond = false;
+
+int job = 1;
 
 /* --- Fonctions privées --- */
 void test_write() {
@@ -26,31 +41,29 @@ void test_write() {
     printf("%d\n", tmp);
 }
 
-/* --- Fonctions utilitaires --- */
-void show_current_dir(const char* before, const char* after) {
-    char buffer[BUFFER_SIZE];
-    if (getcwd(buffer, sizeof (buffer)) == NULL) {
-        addperror("Erreur getcwd()");
-    } else {
-        if(before == NULL && after == NULL){
-            printf("%s", buffer);
-        } else if(before == NULL){
-            printf("%s%s", buffer, after);
-        } else if(after == NULL){
-            printf("%s%s", before, buffer);
-        } else {
-            printf("%s%s%s", before, buffer, after);
-        }
-    }
+void test_tmp_file(){
+    int a;
+    FILE* f = tmpfile();
+    printf("F : %d\n", f == NULL);
+    int fd = fileno(f);
+    printf("%d : %ld\n", fd, write(fd, "bonjour", 8));
+    a = lseek(fd, 0L, SEEK_SET);
+    sleep(2);
+    char buf[10];
+    memset(buf, 0 , 10);
+    a = read(fd, buf, 10);
+    printf("%d : %s\n", a, buf);
+    close(fd);
 }
 
-/* --- Main --- */
-int main(int argc, char* argv[]) { 
+void test(){
     CommandTab ct;
     char str[BUFFER_SIZE];
     int a;
-    //Initialisation erreur
+    //Initialisation structures
     error_finit("mysh.log");
+    ini_pid_list(&pidlist);
+    
     //Recup ligne
     //printf("%s\n", fgets(str, 500, stdin));&
     memset(str, 0, 500);
@@ -76,29 +89,329 @@ int main(int argc, char* argv[]) {
             printf("    Argument %d : %s\n", j, c->argv[j]);
         }
         printf("Commande en fond : %d\n\n", ct.bck);
+        //Si c'est une commande interne on l'execute
+        if(is_internal_cmd(ct.cmd[i]->name)){
+            show_current_dir(NULL, "\n");
+            printf("Result : %d\n", launch_internal_command(ct.cmd[i]));
+            show_current_dir(NULL, "\n");
+        }
     }
-    //Supprime
+    //Nettoyage structures
     clean_command(&ct);
+    clean_pid(&pidlist);
     error.exit();
 }
 
-/* --- Commandes internes --- */
-void cd(int argc, char** argv) {
-    //Si trop d'arguments
-    if (argc > 2) {
-        error.print("too many arguments : 1 required, %d given\n", argc - 1);
+/* --- Fonctions utilitaires --- */
+void show_current_dir(const char* before, const char* after) {
+    char buffer[BUFFER_SIZE];
+    if (getcwd(buffer, sizeof (buffer)) == NULL) {
+        addperror("Erreur getcwd()");
     } else {
-        //Si aucun argument on va à la racine
-        if (argc == 1) {
-            if (chdir("/") == ERR) {
-                addperror("Erreur chdir()");
+        if(before == NULL && after == NULL){
+            printf("%s", buffer);
+        } else if(before == NULL){
+            printf("%s%s", buffer, after);
+        } else if(after == NULL){
+            printf("%s%s", before, buffer);
+        } else {
+            printf("%s%s%s", before, buffer, after);
+        }
+    }
+    fflush(stdout);
+}
+
+int get_line(char* buffer){
+    memset(buffer, 0, BUFFER_SIZE);
+    if(read(STDIN, buffer, BUFFER_SIZE) == ERR){
+        addperror("Impossible de lire dans STDIN");
+        return SHELL_ERR;
+    }
+    return SHELL_OK;
+}
+
+int get_tmp_file(){
+    FILE* f = tmpfile();
+    if(f == NULL){
+        adderror("Impossible de créer un fichier temporaire");
+        return SHELL_ERR;
+    }
+    return fileno(f);
+}
+
+/* --- Main --- */
+int main(int argc, char* argv[]) { 
+    //Declaration variables
+    CommandTab ct;
+    int result;
+    char line[BUFFER_SIZE], before[BUFFER_SIZE];
+    sigset_t sigs_new, sigs_old, sigs_block;
+    //Initialisation structures
+    error_finit("mysh.log");
+    ini_pid_list(&pidlist);
+    //Preparation affichage
+    sprintf(before, "\x1b[32m%s:\x1b[36m", getlogin());
+    //Traitement des signeaux
+    result = sigemptyset(&sigs_new);
+    if(result == ERR){	
+	addperror("Impossible de récuperer un ensemble de signaux vide");
+        error.print("Erreur pendant l'initialisation\n");
+        clean_pid(&pidlist);
+        error.exit_err();
+    }
+    //On bloque que sigchld
+    result = sigaddset(&sigs_new, SIGCHLD);
+    if(result == -1){
+	addperror("Impossible d'ajouter SIGCHLD à l'ensemble de signaux");
+        error.print("Erreur pendant l'initialisation\n");
+        clean_pid(&pidlist);
+        error.exit_err();
+    }
+    result = sigprocmask(SIG_BLOCK, &sigs_new, &sigs_old);
+    if(result == -1){
+	addperror("Impossible de bloquer les signaux de l'ensemble");
+        error.print("Erreur pendant l'initialisation\n");
+        clean_pid(&pidlist);
+        error.exit_err();
+    }
+    //Gestion interuption
+    signal(SIGINT, handler);
+    //Boucle infini de lecture
+    while(!exitsh){
+        //On regarde si un fils en fond est mort
+	if(sigpending(&sigs_block) == ERR){
+            addperror("Impossible de recuperer les signaux en attentes");
+	} else if(sigismember(&sigs_block, SIGCHLD)){
+            job--;
+	}
+        //Affichage repertoire
+        show_current_dir(before, ">\x1b[0m ");      
+        //Lecture ligne
+        if(get_line(line) == SHELL_ERR){
+            //error.print("Impossible de lire les commandes\n");
+            continue;
+        }
+        //Parse la ligne et commandes
+        result = parse_line(&ct, line);
+        if(result == SHELL_ERR){
+            error.print("Impossible d'analyser la ligne\n");
+            addserror("Erreur lors du parse de la ligne");
+            continue;
+        }
+        //Si aucune commande on passe
+        printf("Nb cmd : %d\n", ct.length);
+        if(ct.length == 0){
+            clean_command(&ct);
+            continue;
+        }
+        //Parse les commandes
+        result = parse_all_command(&ct);
+        if(result == SHELL_FAIL){
+            error.print("Impossible d'analyser la commande\n");
+            addserror("Erreur lors du parse des commandes");
+            continue;
+        }
+        //Execute
+        result_cmd = run(ct, &status_cmd);
+        printf("Result : %d\n", result_cmd);
+        //Vide le resultat du parse de la ligne de commande
+        clean_command(&ct);
+    }
+    //Nettoyage
+    clean_pid(&pidlist);
+    error.end();
+    return EXIT_SUCCESS;
+}
+
+int run(CommandTab ct, int* status){
+    pid_t pid;
+    int result = 0;
+    //Si en fond creation d'un fork pour executer les commandes
+    printf("bck : %d\n", ct.bck);
+    if(ct.bck){
+        pid = fork();
+        if(pid == ERR){
+            addperror("Erreur lors du fork pour l'execution des commandes");
+            error.print("Erreur systeme, impossible de continuer\n");
+            return SHELL_ERR;
+        }
+        //Fils
+        if(pid == 0){
+            int stat = 0;
+            ct.bck = 0;
+            fond = true;
+            result = run(ct, &stat);
+            //Message de fin + retour
+            if(result == SHELL_FAIL){
+                printf("\n%s (jobs=[%d], pid=%d) terminée avec status=-1\n", ct.line, job, getpid());
+                exit(EXIT_FAILURE);
+            }
+            printf("\n%s (jobs=[%d], pid=%d) terminée avec status=%d\n", ct.line, job, getpid(), stat);
+            exit(EXIT_SUCCESS);
+        }
+        printf("[%d] %d\n", job, pid);
+        //Ajout du fils dans la liste des pid
+        add_pid(&pidlist, pid, job++);
+        //Pour le pere c'est fini
+        return SHELL_OK;
+    }
+    //Sinon execution de chaque commande
+    Command* c;
+    int tube[ct.length][2];
+    int tubepos = 0;
+    int infd = -1, outfd = -1, errfd = -1;
+    boolean bpipe = false, skippipe = false, skip = false;
+    //Parcours les commandes
+    for(int i = 0; i < ct.length; i++){
+        c = ct.cmd[i];
+        //Si on skip
+        if(skip){
+            skip = false;
+            continue;
+        }
+        //Si pipe avant
+        if(skippipe){
+            //Si fin chaine pipe
+            if(c->next != SHELL_PIPE){
+                skippipe = false;
+            }
+            //Passe la commande
+            continue;
+        }
+        //Si pipe creation d'un fichier commun
+        skippipe = c->next == SHELL_PIPE ;
+        if(c->next == SHELL_PIPE && c->output == STDOUT){
+            skippipe = false;
+            bpipe = true;
+            //Creation tube
+            if(pipe(tube[tubepos]) == ERR){
+                addperror("Impossible de créer un tube");
+                return SHELL_FAIL;
+            }
+            //Redirection
+            c->output = tube[tubepos][TUBE_ECRITURE];
+            if(ct.cmd[i + 1]->input == STDIN){
+                ct.cmd[i + 1]->input = tube[tubepos][TUBE_LECTURE];
+            }
+        }
+        //Effectue les redirections IO
+        if(c->input != STDIN){
+            infd = redirect_fd2(STDIN, c->input);
+            if(infd == ERR){
+                return SHELL_FAIL;
+            }
+        }
+        if(c->output != STDOUT){
+            outfd = redirect_fd2(STDOUT, c->output);
+            if(outfd == ERR){
+                return SHELL_FAIL;
+            }
+        }
+        if(c->error != STDERR){
+            errfd = redirect_fd2(STDERR, c->error);
+            if(errfd == ERR){
+                return SHELL_FAIL;
+            }
+        }
+        //Execute la commande
+        if(is_internal_cmd(c->name)){
+            result = launch_internal_command(c);
+        } else if(is_executable_file(c->name)){
+            result = exec_file(c->name, c->argv);
+        } else {
+            result = exec_shell(c->name, c->argv);
+        }
+        //Si on a une variable pour stocker le status de retoure
+        if(status != NULL){
+            *status = result;
+        }
+        //Reset IO
+        if(c->input != STDIN){
+            infd = redirect_fd(STDIN, infd);
+            if(infd == ERR){
+                return SHELL_FAIL;
+            }
+        }
+        if(c->output != STDOUT){
+            outfd = redirect_fd(STDOUT, outfd);
+            if(outfd == ERR){
+                return SHELL_FAIL;
             }
-        }            //Sinon on va dans le dossier indiqué par l'utilisateur
-        else {
-            if (chdir(argv[1]) == ERR) {
-                error.print("path does not exist\n");
+        }
+        if(c->error != STDERR){
+            errfd = redirect_fd(STDERR, errfd);
+            if(errfd == ERR){
+                return SHELL_FAIL;
             }
         }
+        //Fermeture tube
+        if(bpipe){
+            bpipe = false;
+            if(close(outfd) == ERR){
+                addperror("Impossible de fermer tube ecriture");
+                return SHELL_FAIL;
+            }
+            if(close(c->output) == ERR){
+                addperror("Impossible de fermer tube ecriture");
+                return SHELL_FAIL;
+            }
+            c->output = STDOUT;
+        }
+        //Agit en fonction de la jointure avec la prochaine commande
+        if(c->next == SHELL_IF){
+            if(result != EXIT_SUCCESS){
+                skip = true;
+            }
+        } else if(c->next == SHELL_ELSE){
+            if(result == EXIT_SUCCESS){
+                skip = true;
+            }
+        }
+    }
+    if(result != EXIT_SUCCESS){
+        return SHELL_FAIL;
+    }
+    return SHELL_OK;
+}
+
+void handler(int sig){
+    char reponse = ' ';
+    pid_node* pn;
+    //Repositionne le gestionnaire (Ne marche plus apres 1 utilisation)
+    signal(SIGINT, handler);
+    //Si on est en fond on est non concerné
+    if(fond){
+        return;
+    }
+    //Si il y a un process actif on le coupe
+    printf("Active : %d\n", active);
+    if(active != -1){
+        if(kill(active, SIGINT) == ERR){
+            addperror("Impossible de tuer le processus en cours");
+        }
+        active = -1;
+        return;
     }
-    //show_current_dir("current working directory is: ", "\n");
+    //Sinon demande comfirmation pour finir le programme
+    while(reponse != 'o' && reponse != 'O' && reponse != 'n' && reponse != 'N'){
+        printf("Voulez vous vraiment quitter ? [O/N] ");
+        if(scanf("%c", &reponse) == 0){
+            reponse = ' ';
+        }
+    }
+    //Si oui
+    if(reponse == 'n' || reponse == 'N'){
+        return;
+    }
+    //Coupe tous les processus en fond
+    pn = pidlist.first;
+    while(pn != NULL){
+        if(kill(pn->pid, SIGINT) == ERR){
+            addperror("Impossible de tuer le processus en fond");
+        }
+        pn = pn->next;
+    }
+    //Termine l'execution
+    clean_pid(&pidlist);
+    error.exit();
 }

+ 11 - 6
mysh.h

@@ -8,7 +8,11 @@
 #ifndef MYSH_H
 #define MYSH_H
 
-/* --- Fonctions utilitaires --- */
+/* --- Extern --- */
+extern int status_cmd;
+extern int result_cmd;
+
+/* --- Fonctions --- */
 /**
  * Affiche le dossier de travail actuel
  * @param char* Chaine à afficher avant le dossier
@@ -16,13 +20,14 @@
  */
 void show_current_dir(const char*, const char*);
 
-/* --- Commandes internes --- */
 /**
- * Change le dossier de travail actuel
- * @param int argc
- * @param char** argv
+ * Execute l'ensemble des commandes d'une ligne
+ * @param CommandTab La ligne de commande parser
+ * @return 
  */
-void cd(int, char**);
+int run(CommandTab, int*);
+
+void handler(int);
 
 #endif /* MYSH_H */
 

+ 49 - 15
parser.c

@@ -29,8 +29,13 @@ extern int serrno;
 int nb_commands(char* line){
     //Initialisation variable
     int compteur = 0;
+    boolean vide = true;
     //Parcours chaine pour chercher séparateur et compter le nombre de commande
     while(*line){
+        //Si on croise un caractère
+        if(vide && *line != ' ' && *line != '\0'){
+            vide = false;
+        }
         //Si un ;
         if(*line == ';'){
             compteur++;
@@ -69,7 +74,9 @@ int nb_commands(char* line){
         line++;
     }
     //Ajoute la dernière commande
-    compteur++;
+    if(!vide){
+        compteur++;
+    }
     return compteur;
 }
 
@@ -128,8 +135,6 @@ int get_command(Command* c, char* line){
     c->input = STDIN;
     c->output = STDOUT;
     c->error = STDERR;
-    c->erase[0] = false;
-    c->erase[1] = false;
     //Retour
     return length + separator;
 }
@@ -142,8 +147,17 @@ int get_command(Command* c, char* line){
  * @return int SHELL_OK si réussite, SHELL_ERR sinon
  */
 int set_io(Command* c, char* filename, int redir){
+    printf("Redir : %d\n", redir);
     //Declaration variable
     int file;
+    //Si fichier existe et on supprime
+    if((redir == SHELLRE_OUT || redir == SHELLRE_ERR || redir == SHELLRE_ALL) && access(filename, F_OK) != ERR){
+        if(unlink(filename) == ERR){
+            addperror("Impossible de supprimer le fichier");
+            serrno = SEOPENF;
+            return SHELL_ERR;
+        }
+    }
     //Ouverture du fichier
     file = open(filename, O_CREAT | O_RDWR, S_IRWXU);
     if(file == ERR){
@@ -151,6 +165,14 @@ int set_io(Command* c, char* filename, int redir){
         serrno = SEOPENF;
         return SHELL_ERR;
     }
+    //On se met à la fin du fichier si sortie ou erreur
+    if(redir != SHELLR_IN){
+        if(lseek(file, 0L, SEEK_END) == ERR){
+            addperror("Impossible de se deplacer dans le fichier");
+            serrno = SEOPENF;
+            return SHELL_ERR;
+        }
+    }
     //Analyse dans quel descripteur il doit etre mis
     switch(redir){
         case SHELLR_IN:
@@ -174,9 +196,6 @@ int set_io(Command* c, char* filename, int redir){
                 }
             }
             c->output = file;
-            if(redir == SHELLRE_OUT){
-                c->erase[STDOUT - 1] = true;
-            }
             break;
         case SHELLR_ERR:
         case SHELLRE_ERR:
@@ -188,9 +207,6 @@ int set_io(Command* c, char* filename, int redir){
                 }
             }
             c->error = file;
-            if(redir == SHELLRE_ERR){
-                c->erase[STDERR - 1] = true;
-            }
             break;
         case SHELLR_ALL:
         case SHELLRE_ALL:
@@ -209,10 +225,6 @@ int set_io(Command* c, char* filename, int redir){
             }
             c->output = file;
             c->error = file;
-            if(redir == SHELLRE_ALL){
-                c->erase[STDOUT - 1] = true;
-                c->erase[STDERR - 1] = true;
-            }
             break;
         default :
             serrno = SEREDIRTYPE;
@@ -270,7 +282,7 @@ int set_redirection(Command* c){
                                     return SHELL_ERR;
                                 }
                                 buffer++;
-                                redir = SHELLRE_ALL;
+                                redir = SHELLR_ALL;
                             }
                             //Sinon toujours >>
                             else {
@@ -419,6 +431,16 @@ int split_command(Command* c, char* cmd){
                 cmd++;
                 delim = '"';
             } 
+            //Cote
+            else if(*cmd == '\''){
+                //Verif que ce n'est pas la fin
+                if(!(*(cmd + 1))){
+                    serrno = SEBADCMD;
+                    return SHELL_ERR;
+                }
+                cmd++;
+                delim = '\'';
+            } 
             //Mot sans guillemet autour
             else {
                 length = 0;
@@ -454,6 +476,13 @@ int split_command(Command* c, char* cmd){
                 length = 0;
                 delim = '"';
             } 
+            //Cote
+            else if(*cmd == '\''){
+                cmd++;
+                deb = cmd;
+                length = 0;
+                delim = '\'';
+            }
             //Mot sans guillemet autour
             else {
                 deb = cmd;
@@ -477,7 +506,7 @@ int split_command(Command* c, char* cmd){
     if(chercheFin){
         c->argv[i] = malloc(sizeof(char) * (length + 1));
         memset(c->argv[i], 0, length + 1);
-        strncpy(c->argv[i++], deb, length);  
+        strncpy(c->argv[i++], deb, length); 
     }
     //Set la dernière case du tableau à null
     c->argv[i] = NULL;
@@ -496,6 +525,10 @@ int parse_line(CommandTab* ct, char* line){
         return SHELL_ERR;
     }
     //Initialisation structure
+    tmp = strlen(line);
+    ct->line = malloc(sizeof(char) * (tmp + 1));
+    memset(ct->line, 0, tmp + 1);
+    strncpy(ct->line, line, tmp);
     ct->cmd = malloc(sizeof(Command*) * compteur);
     ct->length = compteur;
     ct->bck = line[strlen(line) - 1] == '&';
@@ -605,4 +638,5 @@ void clean_command(CommandTab* ct){
     }
     //Met à 0 la taille du tableau
     ct->length = 0;
+    free(ct->line);
 }

+ 1 - 1
parser.h

@@ -20,11 +20,11 @@ typedef struct {
     int input; //Descripteur de fichier d'entré
     int output; //Descripteur de fichier de sortie
     int error; //Descripteur de fihier d'erreur
-    boolean erase[2]; //Si on efface le fichier
     int next; //Lien avec la prochaine commande
 } Command;
 
 typedef struct {
+    char* line; //La ligne de commande
     Command** cmd; //Tableau avec toutes les commandes
     int length; //Taille du tableau
     boolean bck; //Si l'ensemble de commande se fait en fond

+ 7 - 3
str.c

@@ -20,13 +20,15 @@ char* ltrim(char* str, char mask){
     }
     //Si aucun espace au debut
     if(cmpt == 0){
-        res = malloc(sizeof(char) * strlen(str));
+        res = malloc(sizeof(char) * (strlen(str) + 1));
+        memset(res, 0, strlen(str) + 1);
         strcpy(res, str);
         return res;
     }
     //Sinon creation nouvelle chaine
     res = malloc(sizeof(char) * (strlen(str) - cmpt + 1));
-    for(int i = 0, j = cmpt; i < (strlen(str) - cmpt); i++, j++){
+    memset(res, 0, strlen(str) - cmpt + 1);
+    for(int i = 0, j = cmpt; j < (strlen(str)); i++, j++){
         res[i] = str[j];
     }
     //Retour nouvelle chaine
@@ -43,13 +45,15 @@ char* rtrim(char* str, char mask){
     }
     //Si aucun espace au debut
     if(cmpt == strlen(str) - 1){
-        res = malloc(sizeof(char) * strlen(str));
+        res = malloc(sizeof(char) * (strlen(str) + 1));
+        memset(res, 0, strlen(str) + 1);
         strcpy(res, str);
         return res;
     }
     cmpt++;
     //Sinon creation nouvelle chaine
     res = malloc(sizeof(char) * (cmpt + 2));
+    memset(res, 0, cmpt + 2);
     for(int i = 0; i < cmpt; i++){
         res[i] = str[i];
     }

+ 69 - 18
wildcard.c

@@ -18,12 +18,45 @@
 #include "error.h"
 #include "wildcard.h"
 
-int wildcard_result(const char* seq) {
+/* --- Fonctions privées --- */
+
+/**
+ * Determine la position de separation entre le chemin et la wildcard
+ * @param char* La chaine
+ * @return int Position dans la chaine
+ */
+int wilcard_begin(const char* seq) {
+    int pos = 0, compteur = 1;
+    while (*seq) {
+        if (*seq == '/') {
+            pos = compteur;
+        }
+        seq++;
+        compteur++;
+    }
+    return pos;
+}
+
+/* --- Fonctions publiques --- */
+int wildcard_result(char* seq) {
     //Declaration variable
     struct dirent **namelist;
-    int nbFile, nbRes = 0;
+    int nbFile, nbRes = 0, wcpos;
+    char* wc, *path;
+    //Trouve la wildcard
+    wcpos = wilcard_begin(seq);
+    if (!wcpos) {
+        path = malloc(sizeof (char) * 2);
+        strcpy(path, ".");
+        wc = seq;
+    } else {
+        path = malloc(sizeof (char) * wcpos);
+        memset(path, 0, wcpos);
+        strncpy(path, seq, wcpos - 1); //Pour ne pas prendre le / final
+        wc = seq + wcpos;
+    }
     //Recup la liste des fichiers dans le dossier courant
-    nbFile = scandir(".", &namelist, 0, alphasort);
+    nbFile = scandir(path, &namelist, 0, alphasort);
     if (nbFile < 0) {
         addperror("Erreur scandir()");
         return ERR;
@@ -33,9 +66,9 @@ int wildcard_result(const char* seq) {
         //Si c'est bien un fichier (et non un dossier)
         if (namelist[nbFile]->d_type == DT_REG) {
             //Test par rapport au wildcard
-            if (fnmatch(seq, namelist[nbFile]->d_name, 0) == 0) {
+            if (fnmatch(wc, namelist[nbFile]->d_name, 0) == 0) {
                 //Regarde si le resultat est bien different de la wildcard
-                if (strcmp(seq, namelist[nbFile]->d_name) != 0) {
+                if (strcmp(wc, namelist[nbFile]->d_name) != 0) {
                     nbRes++;
                 }
             }
@@ -47,16 +80,29 @@ int wildcard_result(const char* seq) {
     return nbRes;
 }
 
-int wildcard(const char* seq, int size, char** result) {
+int wildcard(char* seq, int size, char** result) {
     //Declaration variable
     struct dirent **namelist;
-    int nbFile, nbRes = 0;
+    int nbFile, nbRes = 0, wcpos;
+    char* wc, *path;
     //Verification parametre
     if (size < 1) {
-        return ERR;
+        return -1;
+    }
+    //Trouve la wildcard
+    wcpos = wilcard_begin(seq);
+    if (!wcpos) {
+        path = malloc(sizeof (char) * 2);
+        strcpy(path, ".");
+        wc = seq;
+    } else {
+        path = malloc(sizeof (char) * wcpos);
+        memset(path, 0, wcpos);
+        strncpy(path, seq, wcpos - 1);
+        wc = seq + wcpos;
     }
     //Recup la liste des fichiers dans le dossier courant
-    nbFile = scandir(".", &namelist, 0, alphasort);
+    nbFile = scandir(path, &namelist, 0, alphasort);
     if (nbFile < 0) {
         addperror("Erreur scandir()");
         return ERR;
@@ -67,9 +113,17 @@ int wildcard(const char* seq, int size, char** result) {
         //Si c'est bien un fichier (et non un dossier)
         if (namelist[nbFile]->d_type == DT_REG) {
             //Test par rapport au wildcard
-            if (fnmatch(seq, namelist[nbFile]->d_name, 0) == 0) {
-                result[i] = malloc(strlen(namelist[nbFile]->d_name) * sizeof (char));
-                strcpy(result[i++], namelist[nbFile]->d_name);
+            if (fnmatch(wc, namelist[nbFile]->d_name, 0) == 0) {
+                //Si il y a un chemin
+                if (wcpos) {
+                    result[i] = malloc(sizeof (char) * (strlen(path) + strlen(namelist[nbFile]->d_name) + 2));
+                    memset(result[i], 0, strlen(path) + strlen(namelist[nbFile]->d_name) + 2);
+                    sprintf(result[i++], "%s/%s", path, namelist[nbFile]->d_name);
+                } else {
+                    result[i] = malloc(sizeof (char) * (strlen(namelist[nbFile]->d_name) + 1));
+                    memset(result[i], 0, strlen(namelist[nbFile]->d_name) + 1);
+                    sprintf(result[i++], "%s", namelist[nbFile]->d_name);
+                }
                 nbRes++;
             }
         }
@@ -118,8 +172,7 @@ char** insert_array(int pos, char** array, int arraysize, char** insert, int ins
         //Si l'element est null
         if (array[i] == NULL) {
             newarray[i] = NULL;
-        }            
-        //Sinon on le copie
+        }            //Sinon on le copie
         else {
             newarray[i] = malloc(strlen(array[i]) * sizeof (char));
             strcpy(newarray[i], array[i]);
@@ -131,8 +184,7 @@ char** insert_array(int pos, char** array, int arraysize, char** insert, int ins
         //Si l'element est null
         if (insert[j] == NULL) {
             newarray[i] = NULL;
-        }            
-        //Sinon on le copie
+        }            //Sinon on le copie
         else {
             newarray[i] = malloc(strlen(insert[j]) * sizeof (char));
             strcpy(newarray[i], insert[j]);
@@ -144,8 +196,7 @@ char** insert_array(int pos, char** array, int arraysize, char** insert, int ins
         //Si l'element est null
         if (array[j] == NULL) {
             newarray[i] = NULL;
-        }            
-        //Sinon on le copie
+        }            //Sinon on le copie
         else {
             newarray[i] = malloc(strlen(array[j]) * sizeof (char));
             strcpy(newarray[i], array[j]);

+ 2 - 2
wildcard.h

@@ -19,7 +19,7 @@
  * @return int Le nombre de fichiers correspondant (0 si aucun ou si le nom du
  * fichier est identique à la sequence)
  */
-int wildcard_result(const char*);
+int wildcard_result(char*);
 
 /**
  * Recupere les fichiers correspondant à une sequence
@@ -29,7 +29,7 @@ int wildcard_result(const char*);
  * @return int Le nombre d'élement mis dans le tableau (ne depasse jamais la
  * capacité indiqué en paramètre)
  */
-int wildcard(const char*, int, char**);
+int wildcard(char*, int, char**);
 
 /**
  * Insert un tableau à la place d'une valeur d'un autre tableau