298 lines
6.0 KiB
C
298 lines
6.0 KiB
C
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/wait.h>
|
|
#include <dirent.h>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <assert.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#define TAILLE_BUFFER 200
|
|
char * path2;
|
|
|
|
void lire(char **, char **, char **);
|
|
char * lireChaine3();
|
|
void changeDirectory(char * path);
|
|
int subString (const char *chaine, int debut, int fin, char *result);
|
|
void erreur(char *s);
|
|
void executionPipe(char *arg1, char * arg3, char **env);
|
|
void execution(char *arg1, char *arg2, char *arg3, char **env);
|
|
void quitter(int signal);
|
|
|
|
int main(int argc, char **argv, char **env)
|
|
{
|
|
int commandeInterne;
|
|
char *arg1, *arg2, *arg3;
|
|
|
|
signal(SIGHUP, quitter);
|
|
signal(SIGINT, quitter);
|
|
signal(SIGQUIT, quitter);
|
|
|
|
int UUID;
|
|
UUID = geteuid();
|
|
// Boucle principale qui attend les commandes
|
|
while(1)
|
|
{
|
|
if(UUID == 0) // Si l'utilisateur est root alors il a droit à son prompt personnalisé
|
|
printf("[ root ] %s # ", (char *) getenv("PWD"));
|
|
else
|
|
printf("[ %s ] %s $ ",(char *) getenv("USER"), (char *) getenv("PWD"));
|
|
|
|
arg1 = arg2 = arg3 = NULL;
|
|
commandeInterne = 0;
|
|
|
|
lire(&arg1, &arg2, &arg3);
|
|
|
|
if(arg1 != NULL)
|
|
{
|
|
if(strcmp(arg1, "cd") == 0)
|
|
{
|
|
commandeInterne = 1;
|
|
// On change de répertoire
|
|
changeDirectory(arg2);
|
|
}
|
|
if(strcmp(arg1, "exit") == 0)
|
|
{
|
|
commandeInterne = 1; // Écrit simplement pour rester cohérent, mais un peu inutile :)
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
if(commandeInterne == 0)
|
|
{
|
|
execution(arg1, arg2, arg3, env);
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
void execution(char *arg1, char *arg2, char *arg3, char **env)
|
|
{
|
|
int pid;
|
|
char ** options = malloc(sizeof(char *)*3);
|
|
options[0] = arg1;
|
|
options[1] = NULL;
|
|
int status;
|
|
|
|
if(arg2 != NULL)
|
|
{
|
|
if(strcmp(arg2, "|") == 0)
|
|
executionPipe(arg1, arg3, env);
|
|
else
|
|
{
|
|
if((pid = fork()) == 0)
|
|
{
|
|
int fd0,fd1;
|
|
if(strcmp(arg2, "<") == 0) // On prend arg3 en entrée standard
|
|
{
|
|
if((fd0 = open(arg3, O_RDONLY)) == -1)
|
|
{
|
|
erreur("Ouverture fichier");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
close(0); dup(fd0); // Redirection de l'entrée standard
|
|
}
|
|
else if(strcmp(arg2, ">") == 0) // On redirige la sortie vers un fichier (arg3)
|
|
{
|
|
if((fd1 = open(arg3, O_WRONLY | O_CREAT | O_TRUNC , 0666)) == -1)
|
|
{
|
|
erreur("Redirection sortie standard vers fichier");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
close(1); dup(fd1); // Redirection de la sortie standard
|
|
}
|
|
else if(strcmp(arg2, "&") == 0) // Exécution en arrière plan, on a rien en entrée
|
|
{
|
|
if((fd0 = open("/dev/null", O_RDONLY)) == -1)
|
|
{
|
|
erreur("Ouverture /dev/null");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
close(0); dup(fd0);
|
|
}
|
|
else // Exécution simple (avec arguments)
|
|
{
|
|
free(options);
|
|
options = malloc(4 * sizeof(char *));
|
|
options[0] = arg1;
|
|
options[1] = arg2;
|
|
options[2] = arg3;
|
|
options[3] = NULL;
|
|
}
|
|
execvpe(arg1, options, env);
|
|
erreur("execvpe n'a pas fonctionné");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
else
|
|
{
|
|
if(strcmp(arg2, "&") == 0) // Si exécution en arrière plan
|
|
{
|
|
signal(SIGCHLD, SIG_IGN);
|
|
}
|
|
else // Sinon on attend la fin d'exécution du fils
|
|
{
|
|
signal(SIGINT, SIG_IGN);
|
|
waitpid(pid, &status, 0 );
|
|
signal(SIGINT, quitter);
|
|
|
|
if(status == EXIT_FAILURE )
|
|
erreur("Soucis avec le fils");
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
else // exécution basique
|
|
{
|
|
if((pid = fork()) == 0)
|
|
{
|
|
execvpe(arg1, options, env);
|
|
erreur("Soucis au niveau du exec");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
else
|
|
{
|
|
signal(SIGINT, SIG_IGN);
|
|
waitpid(pid, &status, 0);
|
|
signal(SIGINT, quitter);
|
|
}
|
|
}
|
|
if(options != NULL) free(options);
|
|
if(arg1 != NULL) free(arg1);
|
|
|
|
}
|
|
void changeDirectory(char * path)
|
|
{
|
|
if(path == NULL || strcmp(path, "") == 0)
|
|
{
|
|
chdir(getenv("HOME"));
|
|
setenv("PWD", (char *) getenv("HOME"), 1);
|
|
}
|
|
else
|
|
{
|
|
if(chdir(path) != 0)
|
|
{
|
|
erreur("Impossible de changer de répertoire");
|
|
}
|
|
else
|
|
{
|
|
if(path2 == NULL)
|
|
path2 = (char *) malloc(TAILLE_BUFFER * sizeof(char *));
|
|
|
|
getcwd(path2, TAILLE_BUFFER);
|
|
setenv("PWD",path2, 1);
|
|
}
|
|
}
|
|
}
|
|
void lire(char** arg1, char** arg2, char** arg3)
|
|
{
|
|
char *s;
|
|
|
|
s = lireChaine3();
|
|
|
|
*arg1 = strtok(s," ");
|
|
*arg2 = strtok((char *)0," ");
|
|
*arg3 = strtok((char *)0," ");
|
|
}
|
|
char *lireChaine3()
|
|
{
|
|
char *ptr, *ptr1 = NULL;
|
|
int c;
|
|
int i=0;
|
|
int nb=10;
|
|
|
|
ptr = malloc(nb);
|
|
assert(ptr);
|
|
|
|
while((c=getchar()) != '\n' )
|
|
{
|
|
// Si on envoit EOF (^D) alors on quitte le shell (comme sur les shells qu'on utilise habituellement)
|
|
if(c == EOF)
|
|
{
|
|
printf("\n");
|
|
exit(EXIT_SUCCESS);
|
|
}
|
|
if (i==nb-1)
|
|
{
|
|
ptr1=malloc(nb=nb*2);
|
|
assert(ptr1);
|
|
ptr[i]='\0';
|
|
strcpy(ptr1,ptr);
|
|
free(ptr);
|
|
ptr=ptr1;
|
|
}
|
|
ptr[i]=c;
|
|
i++;
|
|
}
|
|
ptr[i]='\0';
|
|
|
|
if(c == EOF && i == 0)
|
|
ptr = NULL;
|
|
else
|
|
if (i+1 != nb)
|
|
{
|
|
ptr1=malloc(i+1);
|
|
assert(ptr1);
|
|
strcpy(ptr1,ptr);
|
|
free(ptr);
|
|
ptr=ptr1;
|
|
}
|
|
ptr1 = NULL;
|
|
return ptr;
|
|
}
|
|
void erreur(char *s)
|
|
{
|
|
perror(s);
|
|
}
|
|
int subString (const char *chaine, int debut, int fin, char *result)
|
|
{
|
|
result[fin+1-debut] = '\0';
|
|
memcpy (result, (char *)chaine+debut, fin+1-debut);
|
|
return (fin+1-debut);
|
|
}
|
|
void executionPipe(char *arg1, char *arg3, char **env)
|
|
{
|
|
int pid, status;
|
|
if((pid = fork()) == 0)
|
|
{
|
|
int pipefd[2];
|
|
pipe(pipefd);
|
|
int pid2;
|
|
|
|
char ** options = malloc(sizeof(char *)*3);
|
|
options[0] = arg1;
|
|
options[1] = NULL;
|
|
|
|
if((pid2 = fork()) == 0) // Dans le fils : exécution de la première commande
|
|
{
|
|
close(pipefd[0]);
|
|
close(1); dup(pipefd[1]);
|
|
|
|
execvpe(arg1, options, env);
|
|
erreur("Soucis avec le exec, option 'PIPE'");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
else // Le père récupère en entrée la sortie du fils
|
|
{
|
|
close(pipefd[1]);
|
|
close(0); dup(pipefd[0]);
|
|
|
|
execvpe(arg3, options, env);
|
|
erreur("Soucis avec le exec, option 'PIPE'");
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
signal(SIGINT, SIG_IGN);
|
|
waitpid(pid, &status, 0);
|
|
signal(SIGINT, quitter);
|
|
}
|
|
}
|
|
void quitter(int signal)
|
|
{
|
|
printf("\nVous avez indiqué le signal avec le numéro : %d\n", signal);
|
|
exit(EXIT_SUCCESS);
|
|
}
|