diff --git a/main.c b/main.c new file mode 100644 index 0000000..af89d42 --- /dev/null +++ b/main.c @@ -0,0 +1,139 @@ +#include +#include +#include +#include +#include +#include +#include +#include "readcmd.h" +#include "processlist.h" + +#define BUFFERSIZE 255 + +process * list; +int sortie = 0; +int errno; +int cpt = 0; + + +void suivi_fils (int sig) { + + int etat_fils, pid_fils; + + do { + pid_fils = waitpid(-1, &etat_fils, WNOHANG | WUNTRACED | WCONTINUED); + if ((pid_fils == -1) && (errno != ECHILD)) { + perror("waitpid"); + exit(EXIT_FAILURE); + } else if (pid_fils > 0) { + if (WIFSTOPPED(etat_fils)) { + list = setStatus(list,pid_fils,0); + } else if (WIFCONTINUED(etat_fils)) { + list = setStatus(list,pid_fils,1); + } else if (WIFEXITED(etat_fils)) { + list = supprimer(list, pid_fils); + printf("suppression"); + } else if (WIFSIGNALED(etat_fils)) { + //if(WSTOPSIG(etat_fils) == ) + } + } + } while (pid_fils > 0); + +} + + + +char * copyCommandText(char ** cmd){ + char * cmdtxt = malloc(BUFFERSIZE * sizeof(char)); + int x=0; + while( cmd[x]!= NULL){ + strcat(cmdtxt, cmd[x]); + x++; + } + return cmdtxt; +} + +void executerCommande(char ** commande, int backgrounded){ + if(strcmp(commande[0], "cd") == 0){ + char *s = malloc(sizeof(char)*250); + getcwd(s, 255); + // cas de la commande cd sans argument + if(commande[1] == NULL){ + chdir(getenv("HOME")); + } + // cas de cd avec chemin relatif ou absolu + else if(chdir(commande[1]) == 0 || chdir(strcat(s, commande[1])) == 0){} + // cas ou le repertoire renseigné n'existe pas + else{ + printf("Repertoire non accessible %s", s); + } + free(s); + } + else if(strcmp(commande[0], "list") == 0){ + printf("%-12s%-12s%-12s%s\n", "ID", "PID", "STATUS", "COMMANDE"); + afficherProcess(list); + } + else if(strcmp(commande[0], "stop") == 0){ + if(commande[1] == NULL) + printf("Utilisation : stop id\n"); + else{ + int pid = getPID(list, atoi(commande[1])); + //printf("%d", pid); + kill(pid , SIGSTOP); + setStatus(list, pid, 0); + } + } + else if(strcmp(commande[0], "exit") == 0){ + sortie = 1; + } + else{ + int status; + int pid = fork(); + list = inserer(list, cpt, pid, 1, copyCommandText(commande)); + cpt++; + if(pid == 0) { + //sigset_t ens_signaux; + //sigemptyset(&ens_signaux); + //sigaddset(&ens_signaux, SIGINT); + //sigaddset(&ens_signaux, SIGUSR1); + //printf("Masquage de SIGINT et SIGUSR1\n\n"); + //sigprocmask(SIG_SETMASK, &ens_signaux, NULL); + execvp(commande[0],commande); + printf("Erreur sur la commande\n"); + exit(3); + } + else if (pid == -1) { + printf("Une erreur est sur venu au niveau du fork\n"); + exit(2); + } + if(backgrounded < 1){ + int ret = waitpid(pid, &status, 0); + list = supprimer(list, pid); + if(ret == -1){ + perror("Erreur sur le wait\n"); + exit(3); + } + } + } +} + + +int main() +{ + //signal(SIGINT, handler_SIG); + //signal(20, handler_SIG); + struct cmdline *cmd; + int i; + while(sortie != 1){ + printf("minishell$ "); + cmd = readcmd(); + i = 0; + while(cmd->seq[i] != NULL){ + if(cmd->backgrounded == NULL) + executerCommande(cmd->seq[i], 0); + else + executerCommande(cmd->seq[i], 1); + i++; + } + } +} diff --git a/processlist.c b/processlist.c new file mode 100644 index 0000000..583a3e4 --- /dev/null +++ b/processlist.c @@ -0,0 +1,80 @@ +#include +#include +#include +#include "processlist.h" + +process * setStatus(process * pr ,int pid_proc, int status){ + if(pr == NULL){} + else if(pr->pid == pid_proc){ + pr->status = status; + } + else{ + setStatus(pr->procSuivant, pid_proc, status); + } + return pr; +} + +process * supprimer(process* pr ,int pid_proc){ + process * toDel; + if(pr == NULL){} + else{ + if(pr->pid == pid_proc){ + toDel = pr; + pr = pr->procSuivant; + } + else{ + process * tmp = pr; + while(tmp->procSuivant->pid != pid_proc){ + tmp = tmp->procSuivant; + } + toDel = tmp ->procSuivant; + tmp->procSuivant = tmp->procSuivant->procSuivant; + } + free(toDel->commande); + free(toDel); + } + + return pr; +} + +process * inserer(process * pr , int id, int pid, int status, char * commande){ + process * toAdd = malloc(sizeof(process)); + toAdd->id = id; + toAdd->pid = pid; + toAdd->status = status; + toAdd->commande = commande; + toAdd->procSuivant = pr; + pr = toAdd; + + return pr; +} + +int taille(process * pr){ + if(pr == NULL) + return 0; + else + return 1 + taille(pr->procSuivant); +} + +int getPID(const process * pr, int idMinishell){ + if(pr == NULL) + return -1; + if(pr->id == idMinishell){ + return pr->pid; + } + else return getPID(pr->procSuivant, idMinishell); +} + +void afficherProcess(process * pr){ + if(pr != NULL){ + printf("%-12d%-12d", pr->id, pr->pid); + if(pr->status>0) + printf("%-12s", "actif"); + else + printf("%-12s", "suspendu"); + printf("%s", pr->commande); + printf("\n"); + afficherProcess(pr->procSuivant); + } + +} diff --git a/processlist.h b/processlist.h new file mode 100644 index 0000000..cdbed80 --- /dev/null +++ b/processlist.h @@ -0,0 +1,20 @@ +#ifndef PROCESSLIST_H_INCLUDED +#define PROCESSLIST_H_INCLUDED + +typedef struct process process; +struct process { + int id; + int pid; + int status; + char * commande; + process * procSuivant; +}; + +process * inserer(process *pr , int id, int pid, int status, char * commande); +process * setStatus(process* pr ,int pid_proc, int status); +process * supprimer(process* pr ,int pid_proc); +int getPID(const process * pr, int idMinishell); +void afficherProcess(process *pr); +int taille(process * pr); + +#endif // PROCESSLIST_H_INCLUDED diff --git a/readcmd.c b/readcmd.c new file mode 100644 index 0000000..b03a525 --- /dev/null +++ b/readcmd.c @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2002, Simon Nieuviarts + */ + +/* + * Backgrounding added. [PM] Ajout d'une rustine nécessaire : lignes 153 et 293 commentées + */ + +#include +#include +#include +#include +#include +#include +#include "readcmd.h" + + +static void memory_error(void) +{ + errno = ENOMEM; + perror(0); + exit(1); +} + + +static void *xmalloc(size_t size) +{ + void *p = malloc(size); + if (!p) memory_error(); + return p; +} + + +static void *xrealloc(void *ptr, size_t size) +{ + void *p = realloc(ptr, size); + if (!p) memory_error(); + return p; +} + + +/* Read a line from standard input and put it in a char[] */ +static char *readline(void) +{ + size_t buf_len = 16; + char *buf = xmalloc(buf_len * sizeof(char)); + + if (fgets(buf, buf_len, stdin) == NULL) { + free(buf); + return NULL; + } + + do { + size_t l = strlen(buf); + if ((l > 0) && (buf[l-1] == '\n')) { + l--; + buf[l] = 0; + return buf; + } + if (buf_len >= (INT_MAX / 2)) memory_error(); + buf_len *= 2; + buf = xrealloc(buf, buf_len * sizeof(char)); + if (fgets(buf + l, buf_len - l, stdin) == NULL) return buf; + } while (1); +} + + +/* Split the string in words, according to the simple shell grammar. */ +static char **split_in_words(char *line) +{ + char *cur = line; + char **tab = 0; + size_t l = 0; + char c; + + while ((c = *cur) != 0) { + char *w = 0; + char *start; + switch (c) { + case ' ': + case '\t': + /* Ignore any whitespace */ + cur++; + break; + case '<': + w = "<"; + cur++; + break; + case '>': + w = ">"; + cur++; + break; + case '|': + w = "|"; + cur++; + break; + case '&': + w = "&"; + cur++; + break; + default: + /* Another word */ + start = cur; + while (c) { + c = *++cur; + switch (c) { + case 0: + case ' ': + case '\t': + case '<': + case '>': + case '|': + case '&': + c = 0; + break; + default: ; + } + } + w = xmalloc((cur - start + 1) * sizeof(char)); + strncpy(w, start, cur - start); + w[cur - start] = 0; + } + if (w) { + tab = xrealloc(tab, (l + 1) * sizeof(char *)); + tab[l++] = w; + } + } + tab = xrealloc(tab, (l + 1) * sizeof(char *)); + tab[l++] = 0; + return tab; +} + + +static void freeseq(char ***seq) +{ + int i, j; + + for (i=0; seq[i]!=0; i++) { + char **cmd = seq[i]; + + for (j=0; cmd[j]!=0; j++) free(cmd[j]); + free(cmd); + } + free(seq); +} + + +/* Free the fields of the structure but not the structure itself */ +static void freecmd(struct cmdline *s) +{ + if (s->in) free(s->in); + if (s->out) free(s->out); +// if (s->backgrounded) free(s->backgrounded); + if (s->seq) freeseq(s->seq); +} + + +struct cmdline *readcmd(void) +{ + static struct cmdline *static_cmdline = 0; + struct cmdline *s = static_cmdline; + char *line; + char **words; + int i; + char *w; + char **cmd; + char ***seq; + size_t cmd_len, seq_len; + + line = readline(); + if (line == NULL) { + if (s) { + freecmd(s); + free(s); + } + return static_cmdline = 0; + } + + cmd = xmalloc(sizeof(char *)); + cmd[0] = 0; + cmd_len = 0; + seq = xmalloc(sizeof(char **)); + seq[0] = 0; + seq_len = 0; + + words = split_in_words(line); + free(line); + + if (!s) + static_cmdline = s = xmalloc(sizeof(struct cmdline)); + else + freecmd(s); + s->err = 0; + s->in = 0; + s->out = 0; + s->backgrounded = 0; + s->seq = 0; + + i = 0; + while ((w = words[i++]) != 0) { + switch (w[0]) { + case '&': + if(s->backgrounded){ + s->err = "error on &"; + goto error; + } + s->backgrounded = &w[0]; + break; + case '<': + /* Tricky : the word can only be "<" */ + if (s->in) { + s->err = "only one input file supported"; + goto error; + } + if (words[i] == 0) { + s->err = "filename missing for input redirection"; + goto error; + } + s->in = words[i++]; + break; + case '>': + /* Tricky : the word can only be ">" */ + if (s->out) { + s->err = "only one output file supported"; + goto error; + } + if (words[i] == 0) { + s->err = "filename missing for output redirection"; + goto error; + } + s->out = words[i++]; + break; + case '|': + /* Tricky : the word can only be "|" */ + if (cmd_len == 0) { + s->err = "misplaced pipe"; + goto error; + } + + seq = xrealloc(seq, (seq_len + 2) * sizeof(char **)); + seq[seq_len++] = cmd; + seq[seq_len] = 0; + + cmd = xmalloc(sizeof(char *)); + cmd[0] = 0; + cmd_len = 0; + break; + default: + cmd = xrealloc(cmd, (cmd_len + 2) * sizeof(char *)); + cmd[cmd_len++] = w; + cmd[cmd_len] = 0; + } + } + + if (cmd_len != 0) { + seq = xrealloc(seq, (seq_len + 2) * sizeof(char **)); + seq[seq_len++] = cmd; + seq[seq_len] = 0; + } else if (seq_len != 0) { + s->err = "misplaced pipe"; + i--; + goto error; + } else + free(cmd); + free(words); + s->seq = seq; + return s; +error: + while ((w = words[i++]) != 0) { + switch (w[0]) { + case '<': + case '>': + case '|': + case '&': + break; + default: + free(w); + } + } + free(words); + freeseq(seq); + for (i=0; cmd[i]!=0; i++) free(cmd[i]); + free(cmd); + if (s->in) { + free(s->in); + s->in = 0; + } + if (s->out) { + free(s->out); + s->out = 0; + } + if (s->backgrounded) { +// free(s->backgrounded); + s->out = 0; + } + return s; +} + diff --git a/readcmd.h b/readcmd.h new file mode 100644 index 0000000..5993d67 --- /dev/null +++ b/readcmd.h @@ -0,0 +1,41 @@ +#ifndef __READCMD_H +#define __READCMD_H + +/* Lit une ligne de commande depuis l'entrée standard. + * Remarque : + * Dans le cas où suffisamment de mémoire ne peut être allouée pour le résultat, + * affiche un message d'erreur et appelle exit(). + */ + +struct cmdline *readcmd(void); +/* Structure retournée par readcmd() + * Remarques utiles : + * - readcmd() peut retourner null, dans le cas où le processus en attente sur readcmd reçoit un signal + * - en cas d'appels successifs, + * readcmd() réutilise la mémoire allouée à la structure cmdline qu'elle retourne + */ +struct cmdline { + char *err; /* Si non null : message d'erreur à afficher. + * Dans ce cas, les autres champs sont nuls. */ + char *in; /* Si non null : nom du fichier vers lequel l'entrée doit être redirigée. */ + char *out; /* Si non null : nom du fichier vers lequel la sortie doit être redirigée. */ + char *backgrounded; /* Si non null : commande en tâche de fond */ + char ***seq; /* Une ligne de commande est une suite de commandes liées par des tubes + * Ainsi, + * - une commande est un tableau de chaînes de caractères (char **). + * Chaque élément de ce tableau est en effet une chaîne (char *) + * correspondant à un argument de la commande. + * Le dernier pointeur du tableau est suivi d'un pointeur null, qui + * marque la fin du tableau. + * - seq est un tableau de commandes (char ***), chaque commande de ce + * tableau correspondant à une commande élémentaire du pipeline. + * Le dernier élément (char **) du tableau est ici aussi suivi d'un pointeur null. + * - Dans le cas particulier où une ligne vide est saisie, le pointeur référencé par + * seq vaut directement NULL : puisque le tableau n'a aucun élément, le marqueur + * de fin de tableau se trouve référencé par seq, ce que l'on peut écrire + * (*seq == NULL) + * (ou (seq[0] == NULL), mais cela peut prêter à confusion, seq[0] n'existant pas) + */ +}; +#endif + diff --git a/schema pipe.png b/schema pipe.png new file mode 100644 index 0000000..6fa2c98 Binary files /dev/null and b/schema pipe.png differ