|
@@ -4,27 +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 "ipc.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;
|
|
|
+char base_path[BUFFER_SIZE];
|
|
|
+pid_list pidlist;
|
|
|
|
|
|
-/* --- Fonctions privées --- */
|
|
|
-void test_write() {
|
|
|
- char* a = "azerty\n";
|
|
|
- int tmp = write(1, a, strlen(a));
|
|
|
- printf("%d\n", tmp);
|
|
|
-}
|
|
|
+/* --- Globale --- */
|
|
|
+int job = 1;
|
|
|
|
|
|
/* --- Fonctions utilitaires --- */
|
|
|
void show_current_dir(const char* before, const char* after) {
|
|
@@ -42,63 +50,316 @@ void show_current_dir(const char* before, const char* after) {
|
|
|
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[]) {
|
|
|
+int main(int argc, char* argv[], char* envp[]) {
|
|
|
+ //Declaration variables
|
|
|
CommandTab ct;
|
|
|
- char str[BUFFER_SIZE];
|
|
|
- int a;
|
|
|
- //Initialisation erreur
|
|
|
- error_finit("mysh.log");
|
|
|
- //Recup ligne
|
|
|
- //printf("%s\n", fgets(str, 500, stdin));&
|
|
|
- memset(str, 0, 500);
|
|
|
- a = read(STDIN, str, 500);
|
|
|
- printf("%s\n", str);
|
|
|
- //Separe les commandes
|
|
|
- a = parse_line(&ct, str);
|
|
|
- if(a == SHELL_ERR){
|
|
|
- addserror("Erreur lors du parse de la ligne");
|
|
|
+ int result;
|
|
|
+ char line[BUFFER_SIZE], before[BUFFER_SIZE];
|
|
|
+ sigset_t sigs_new, sigs_old, sigs_block;
|
|
|
+ //Initialisation structures
|
|
|
+ error_init();
|
|
|
+ ini_pid_list(&pidlist);
|
|
|
+ //Recup chemain de base de l'application
|
|
|
+ if (getcwd(base_path, sizeof (base_path)) == NULL) {
|
|
|
+ addperror("Impossible de récuperer le chemin actuel");
|
|
|
+ error.print("Erreur pendant l'initialisation\n");
|
|
|
+ clean_pid(&pidlist);
|
|
|
+ error.exit_err();
|
|
|
+ }
|
|
|
+ //Lancement ipc
|
|
|
+ if(!setup_ipc(envp)){
|
|
|
+ error.print("Erreur pendant l'initialisation\n");
|
|
|
+ clean_pid(&pidlist);
|
|
|
+ error.exit_err();
|
|
|
+ }
|
|
|
+ //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();
|
|
|
}
|
|
|
- //Parse les commandes
|
|
|
- a = parse_all_command(&ct);
|
|
|
- if(a == SHELL_FAIL){
|
|
|
- addserror("Erreur lors du parse des commandes");
|
|
|
+ //On bloque que sigchld
|
|
|
+ result = sigaddset(&sigs_new, SIGCHLD);
|
|
|
+ if(result == ERR){
|
|
|
+ addperror("Impossible d'ajouter SIGCHLD à l'ensemble de signaux");
|
|
|
+ error.print("Erreur pendant l'initialisation\n");
|
|
|
+ clean_pid(&pidlist);
|
|
|
error.exit_err();
|
|
|
}
|
|
|
- //Affiche resultat
|
|
|
- for (int i = 0; i < ct.length; i++) {
|
|
|
- Command* c = ct.cmd[i];
|
|
|
- printf("Commande %d (%s) : \n", i, c->name);
|
|
|
- for (int j = 0; j < c->argc; j++) {
|
|
|
- printf(" Argument %d : %s\n", j, c->argv[j]);
|
|
|
+ result = sigprocmask(SIG_BLOCK, &sigs_new, &sigs_old);
|
|
|
+ if(result == -ERR){
|
|
|
+ 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
|
|
|
+ if(ct.length == 0){
|
|
|
+ clean_command(&ct);
|
|
|
+ continue;
|
|
|
}
|
|
|
- printf("Commande en fond : %d\n\n", ct.bck);
|
|
|
+ //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);
|
|
|
+ //Vide le resultat du parse de la ligne de commande
|
|
|
+ clean_command(&ct);
|
|
|
}
|
|
|
- //Supprime
|
|
|
- clean_command(&ct);
|
|
|
- error.exit();
|
|
|
+ //Nettoyage
|
|
|
+ if(!end_ipc()){
|
|
|
+ adderror("Impossible de terminer correctement les IPC");
|
|
|
+ }
|
|
|
+ clean_pid(&pidlist);
|
|
|
+ error.end();
|
|
|
+ return EXIT_SUCCESS;
|
|
|
}
|
|
|
|
|
|
-/* --- 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);
|
|
|
- } else {
|
|
|
- //Si aucun argument on va à la racine
|
|
|
- if (argc == 1) {
|
|
|
- if (chdir("/") == ERR) {
|
|
|
- addperror("Erreur chdir()");
|
|
|
+int run(CommandTab ct, int* status){
|
|
|
+ pid_t pid;
|
|
|
+ int result = 0;
|
|
|
+ //Si en fond creation d'un fork pour executer les commandes
|
|
|
+ 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;
|
|
|
+ //Ignore les sigint
|
|
|
+ signal(SIGINT, SIG_IGN);
|
|
|
+ //Lance commande
|
|
|
+ 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++, ct.line);
|
|
|
+ //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;
|
|
|
}
|
|
|
- } //Sinon on va dans le dossier indiqué par l'utilisateur
|
|
|
- else {
|
|
|
- if (chdir(argv[1]) == ERR) {
|
|
|
- error.print("path does not exist\n");
|
|
|
+ //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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ 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 il y a un process actif on le coupe
|
|
|
+ if(active != -1){
|
|
|
+ if(kill(active, SIGINT) == ERR){
|
|
|
+ addperror("Impossible de tuer le processus en cours");
|
|
|
+ }
|
|
|
+ active = -1;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ //Sinon demande comfirmation pour finir le programme
|
|
|
+ while(reponse != 'o' && reponse != 'O' && reponse != 'n' && reponse != 'N'){
|
|
|
+ //Recup la valeur
|
|
|
+ printf("Voulez vous vraiment quitter ? [O/N] ");
|
|
|
+ if((reponse = getchar()) == EOF){
|
|
|
+ reponse = ' ';
|
|
|
+ }
|
|
|
+ //Vide l'entrée standard
|
|
|
+ while(getchar() != '\n');
|
|
|
+ }
|
|
|
+ //Si oui
|
|
|
+ if(reponse == 'n' || reponse == 'N'){
|
|
|
+ return;
|
|
|
}
|
|
|
- //show_current_dir("current working directory is: ", "\n");
|
|
|
+ //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
|
|
|
+ if(!end_ipc()){
|
|
|
+ adderror("Impossible de terminer correctement les IPC");
|
|
|
+ }
|
|
|
+ clean_pid(&pidlist);
|
|
|
+ error.exit();
|
|
|
}
|