diff --git a/.vscode/settings.json b/.vscode/settings.json index fcac5ac..3f0c39b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,6 +3,7 @@ "signal.h": "c", "readcmd.h": "c", "stdlib.h": "c", - "wait.h": "c" + "wait.h": "c", + "*.bak": "c" } } \ No newline at end of file diff --git a/Q1 b/Q1 new file mode 100755 index 0000000..38fd488 Binary files /dev/null and b/Q1 differ diff --git a/Q1.c b/Q1.c new file mode 100644 index 0000000..4d45de3 --- /dev/null +++ b/Q1.c @@ -0,0 +1,67 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include "readcmd.h" + +extern int errno; + +struct cmdline *cmd; + +int pid_fils; + +int main(int argc, char *argv[]) +{ + // loop principal + while (1) + { + printf(">>> "); + cmd = readcmd(); + + if (cmd == NULL) + { // EOF + break; + } + else if (cmd->seq[0] == NULL) + { // empty + continue; + } + + pid_fils = fork(); + if (pid_fils == -1) + { // fork fail ? + fprintf(stderr, "ERROR: forking failed, (%d) %s\n", errno, strerror(errno)); + exit(errno); + } + + if (pid_fils == 0) + { // instructions du fils + execvp(cmd->seq[0][0], cmd->seq[0]); + exit(errno); // si execlp échoue on exit avec une erreur + } + else + { // instructions du père + int wait_code; + pid_t id = waitpid(pid_fils, &wait_code, 0); // on attend la fin de l'exec du fils + + if (id == -1) + { // wait fail ? + fprintf(stderr, "ERROR: waiting for %d failed, (%d) %s\n", wait_code, errno, strerror(errno)); + exit(errno); + } + + if (wait_code) + { // execvp fail ? + fprintf(stderr, "ERROR: %d's execution failed, (%d) %s\n", pid_fils, wait_code, strerror(wait_code)); + } + } + } + + return EXIT_SUCCESS; +} diff --git a/Q3.c b/Q3.c new file mode 100644 index 0000000..41c967e --- /dev/null +++ b/Q3.c @@ -0,0 +1,71 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include "readcmd.h" + +extern int errno; + +struct cmdline *cmd; + +int pid_fils; + +int main(int argc, char *argv[]) +{ + // loop principal + while (1) + { + printf(">>> "); + cmd = readcmd(); + + if (cmd == NULL) + { // EOF + break; + } + else if (cmd->seq[0] == NULL) + { // empty + continue; + } + else if (!strcmp(cmd->seq[0][0], "exit")) + { // "exit" + break; + } + + pid_fils = fork(); + if (pid_fils == -1) + { // fork fail ? + fprintf(stderr, "ERROR: forking failed, (%d) %s\n", errno, strerror(errno)); + exit(errno); + } + + if (pid_fils == 0) + { // instructions du fils + execvp(cmd->seq[0][0], cmd->seq[0]); + exit(errno); // si execlp échoue on exit avec une erreur + } + else + { // instructions du père + int wait_code; + pid_t id = waitpid(pid_fils, &wait_code, 0); // on attend la fin de l'exec du fils + + if (id == -1) + { // wait fail ? + fprintf(stderr, "ERROR: waiting for %d failed, (%d) %s\n", wait_code, errno, strerror(errno)); + exit(errno); + } + + if (wait_code) + { // execvp fail ? + fprintf(stderr, "ERROR: %d's execution failed, (%d) %s\n", pid_fils, wait_code, strerror(wait_code)); + } + } + } + + return EXIT_SUCCESS; +} diff --git a/Q4 b/Q4 new file mode 100755 index 0000000..46a2261 Binary files /dev/null and b/Q4 differ diff --git a/Q4.c b/Q4.c new file mode 100644 index 0000000..3801065 --- /dev/null +++ b/Q4.c @@ -0,0 +1,93 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include "readcmd.h" + +extern int errno; + +struct cmdline *cmd; + +int pid_fils; + +char initcd[256], currentcd[256]; + +int main(int argc, char *argv[]) +{ + getcwd(initcd, sizeof(initcd)); + + // loop principal + while (1) + { + getcwd(currentcd, sizeof(currentcd)); + printf("%s >>> ", currentcd); + cmd = readcmd(); + + if (cmd == NULL) + { // EOF + break; + } + else if (cmd->seq[0] == NULL) + { // empty + continue; + } + else if (!strcmp(cmd->seq[0][0], "exit")) + { // "exit" + break; + } + else if (!strcmp(cmd->seq[0][0], "cd")) + { // "cd" + int ret = 0; + if (cmd->seq[0][1] == NULL) + { // no path + ret = chdir(initcd); + } + else + { // with path + ret = chdir(cmd->seq[0][1]); + } + if (ret) + { // wrong path + fprintf(stderr, "ERROR: cd failed, (%d) %s\n", errno, strerror(errno)); + } + continue; + } + + pid_fils = fork(); + if (pid_fils == -1) + { // fork fail ? + fprintf(stderr, "ERROR: forking failed, (%d) %s\n", errno, strerror(errno)); + exit(errno); + } + + if (pid_fils == 0) + { // instructions du fils + execvp(cmd->seq[0][0], cmd->seq[0]); + exit(errno); // si execlp échoue on exit avec une erreur + } + else + { // instructions du père + int wait_code; + pid_t id = waitpid(pid_fils, &wait_code, 0); // on attend la fin de l'exec du fils + + if (id == -1) + { // wait fail ? + fprintf(stderr, "ERROR: waiting for %d failed, (%d) %s\n", wait_code, errno, strerror(errno)); + exit(errno); + } + + if (wait_code) + { // execvp fail ? + fprintf(stderr, "ERROR: %d's execution failed, (%d) %s\n", pid_fils, wait_code, strerror(wait_code)); + } + } + } + + return EXIT_SUCCESS; +} diff --git a/Q5 b/Q5 new file mode 100755 index 0000000..3871ccb Binary files /dev/null and b/Q5 differ diff --git a/Q5.c b/Q5.c new file mode 100644 index 0000000..6b5d26a --- /dev/null +++ b/Q5.c @@ -0,0 +1,115 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include "readcmd.h" + +extern int errno; +struct cmdline *cmd; +int pid_fils; +int prompting = 0; +jmp_buf goto_prompt; +char initcd[256], currentcd[256]; + +void handler_sigchld(int sig_num) +{ + if (prompting) + { + printf("\n"); + siglongjmp(goto_prompt, sig_num); + } +} + +int main(int argc, char *argv[]) +{ + getcwd(initcd, sizeof(initcd)); + + // gestion des signaux + struct sigaction action; + sigemptyset(&action.sa_mask); + action.sa_flags = SA_SIGINFO | SA_RESTART; + action.sa_handler = handler_sigchld; + sigaction(SIGCHLD, &action, NULL); + + // loop principal + while (1) + { + sigsetjmp(goto_prompt, 1); + + prompting = 1; + getcwd(currentcd, sizeof(currentcd)); + printf("%s >>> ", currentcd); + cmd = readcmd(); + prompting = 0; + + if (cmd == NULL) + { // EOF + break; + } + else if (cmd->seq[0] == NULL) + { // empty + continue; + } + else if (!strcmp(cmd->seq[0][0], "exit")) + { // "exit" + break; + } + else if (!strcmp(cmd->seq[0][0], "cd")) + { // "cd" + int ret = 0; + if (cmd->seq[0][1] == NULL) + { // no path + ret = chdir(initcd); + } + else + { // with path + ret = chdir(cmd->seq[0][1]); + } + if (ret) + { // wrong path + fprintf(stderr, "ERROR: cd failed, (%d) %s\n", errno, strerror(errno)); + } + continue; + } + + pid_fils = fork(); + if (pid_fils == -1) + { // fork fail ? + fprintf(stderr, "ERROR: forking failed, (%d) %s\n", errno, strerror(errno)); + exit(errno); + } + + if (pid_fils == 0) + { // instructions du fils + execvp(cmd->seq[0][0], cmd->seq[0]); + exit(errno); // si execlp échoue on exit avec une erreur + } + else + { // instructions du père + if (!cmd->backgrounded) + { // background + int wait_code; + pid_t id = waitpid(pid_fils, &wait_code, 0); // on attend la fin de l'exec du fils + + if (id == -1) + { // wait fail ? + fprintf(stderr, "ERROR: waiting for %d failed, (%d) %s\n", wait_code, errno, strerror(errno)); + exit(errno); + } + + if (wait_code) + { // execvp fail ? + fprintf(stderr, "ERROR: %d's execution failed, (%d) %s\n", pid_fils, wait_code, strerror(wait_code)); + } + } + } + } + + return EXIT_SUCCESS; +} diff --git a/Q6 b/Q6 new file mode 100755 index 0000000..949d4a9 Binary files /dev/null and b/Q6 differ diff --git a/Q6.c b/Q6.c new file mode 100644 index 0000000..0122400 --- /dev/null +++ b/Q6.c @@ -0,0 +1,204 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include "readcmd.h" +#include "jobs.h" + +extern int errno; + +struct cmdline *cmd; + +int pid_fils, state_fils; + +list jobs; + +int prompting = 0; +jmp_buf goto_prompt; + +char initcd[256], currentcd[256]; + +void handler_sigchld(int sig_num) +{ + pid_fils = waitpid(-1, &state_fils, WNOHANG | WUNTRACED | WCONTINUED); + cell *job = trouver(&jobs, pid_fils); + + if (prompting) + { + printf("\n"); + } + + if (WIFSTOPPED(state_fils)) + { + printf("[%d] %d suspended: %s\n", job->id, job->pid, job->cmd); + } + else if (WIFCONTINUED(state_fils)) + { + printf("[%d] %d continued: %s\n", job->id, job->pid, job->cmd); + //attendre(job->pid); + } + else if (WIFEXITED(state_fils)) + { + printf("[%d] %d done: %s\n", job->id, job->pid, job->cmd); + supprimer(&jobs, job->pid); + } + // else if (WIFSIGNALED(state_fils)) + // { + // /* traiter signal */ + // } + + if (prompting) + { + siglongjmp(goto_prompt, sig_num); + } +} + +void handler_sigint(int sig_num) +{ + printf("\n"); + siglongjmp(goto_prompt, sig_num); +} + +void attendre(int pid) +{ + int wait_code; + pid_t id = waitpid(pid, &wait_code, 0); // on attend la fin de l'exec du fils + + if (id == -1) + { // wait fail ? + fprintf(stderr, "ERROR: waiting for %d failed, (%d) %s\n", wait_code, errno, strerror(errno)); + exit(errno); + } + + if (wait_code) + { // execvp fail ? + fprintf(stderr, "ERROR: %d's execution failed, (%d) %s\n", pid, wait_code, strerror(wait_code)); + } +} + +int main(int argc, char *argv[]) +{ + initialiser(&jobs); + getcwd(initcd, sizeof(initcd)); + + // gestion des signaux + struct sigaction action; + sigemptyset(&action.sa_mask); + action.sa_flags = SA_SIGINFO | SA_RESTART; + action.sa_handler = handler_sigchld; + sigaction(SIGCHLD, &action, NULL); + action.sa_handler = handler_sigint; + sigaction(SIGINT, &action, NULL); + sigaction(SIGTSTP, &action, NULL); + + // loop principal + while (1) + { + sigsetjmp(goto_prompt, 1); + + prompting = 1; + getcwd(currentcd, sizeof(currentcd)); + printf("%s >>> ", currentcd); + cmd = readcmd(); + prompting = 0; + + if (cmd == NULL) + { // EOF + break; + } + else if (cmd->seq[0] == NULL) + { // empty + continue; + } + else if (!strcmp(cmd->seq[0][0], "exit")) + { // "exit" + break; + } + else if (!strcmp(cmd->seq[0][0], "cd")) + { // "cd" + int ret = 0; + if (cmd->seq[0][1] == NULL) + { // no path + ret = chdir(initcd); + } + else + { // with path + ret = chdir(cmd->seq[0][1]); + } + if (ret) + { // wrong path + fprintf(stderr, "ERROR: cd failed, (%d) %s\n", errno, strerror(errno)); + } + continue; + } + else if (!strcmp(cmd->seq[0][0], "jobs")) + { // "jobs" + afficher(&jobs); + continue; + } + else if (!strcmp(cmd->seq[0][0], "bg")) + { // "bg" + kill(pid_fils, SIGCONT); + continue; + } + else if (!strcmp(cmd->seq[0][0], "fg")) + { // "fg" + cell *job; + if (cmd->seq[0][1] == NULL) + { // no id + fprintf(stderr, "ERROR: fg id error\n"); + continue; + } + else + { // id specified + job = &(jobs[atoi(cmd->seq[0][1]) - 1]); + } + kill(job->pid, SIGCONT); + + continue; + } + pid_fils = fork(); + if (pid_fils == -1) + { // fork fail ? + fprintf(stderr, "ERROR: forking failed, (%d) %s\n", errno, strerror(errno)); + exit(errno); + } + + if (pid_fils == 0) + { // instructions du fils + action.sa_handler = SIG_DFL; + sigaction(SIGTSTP, &action, NULL); // on default SIGTSTP + sigaction(SIGCONT, &action, NULL); // on default SIGCONT + + if (cmd->backgrounded) + { // background + action.sa_handler = SIG_IGN; + sigaction(SIGINT, &action, NULL); // on ignore SIGINT + sigaction(SIGTSTP, &action, NULL); // on ignore SIGTSTP + } + + execvp(cmd->seq[0][0], cmd->seq[0]); + exit(errno); // si execlp échoue on exit avec une erreur + } + else + { // instructions du père + if (cmd->backgrounded) + { // background + int id_fils = ajouter(&jobs, pid_fils, *(cmd->seq)); + printf("[%d] %d\n", id_fils, pid_fils); + } + else + { // foreground + attendre(pid_fils); + } + } + } + + return EXIT_SUCCESS; +} diff --git a/jobs b/jobs index 3eed0f9..6c9e998 100755 Binary files a/jobs and b/jobs differ diff --git a/jobs.c b/jobs.c index f86a8e7..d220802 100644 --- a/jobs.c +++ b/jobs.c @@ -3,9 +3,8 @@ #include #include "jobs.h" -void ajouter(list *l_ptr, int pid, int id, char **seq, int state) +int ajouter(list *l_ptr, int pid, char **seq) { - cell *new_cell = malloc(sizeof(*new_cell)); char *cmd; @@ -19,26 +18,45 @@ void ajouter(list *l_ptr, int pid, int id, char **seq, int state) strcat(cmd, " "); } + new_cell->id = 1; new_cell->pid = pid; - new_cell->id = id; new_cell->cmd = cmd; - new_cell->state = state; + new_cell->next = NULL; - if (*l_ptr == NULL) + cell *cursor = *l_ptr; + if (cursor == NULL) { - new_cell->next = NULL; + *l_ptr = new_cell; + } + else if (cursor->id > 1) + { + new_cell->next = cursor; + *l_ptr = new_cell; } else { - new_cell->next = *l_ptr; + while (cursor->next != NULL) + { + new_cell->id++; + if (new_cell->id < cursor->next->id) + { + new_cell->next = cursor->next; + cursor->next = new_cell; + break; + } + cursor = cursor->next; + } + if (cursor->next == NULL) + { + new_cell->id++; + cursor->next = new_cell; + } } - - *l_ptr = new_cell; + return new_cell->id; } void supprimer(list *l_ptr, int pid) { - cell *cursor = *l_ptr; if (cursor->pid == pid) @@ -68,12 +86,10 @@ void supprimer(list *l_ptr, int pid) void afficher(list *l_ptr) { - cell *cursor = *l_ptr; - while (cursor != NULL) { - printf("[%d] %d\n", cursor->id, cursor->pid); + printf("[%d] %d : %s\n", cursor->id, cursor->pid, cursor->cmd); cursor = cursor->next; } } @@ -85,8 +101,8 @@ void initialiser(list *l_ptr) void liberer(list *l_ptr) { - cell* cursor2free; - cell* cursor = *l_ptr; + cell *cursor2free; + cell *cursor = *l_ptr; while (cursor != NULL) { cursor2free = cursor; @@ -111,5 +127,21 @@ cell *trouver(list *l_ptr, int pid) cursor = cursor->next; } + return NULL; // erreur +} + +cell *trouver_id(list *l_ptr, int id) +{ + cell *cursor = *l_ptr; + + while (cursor != NULL) + { + if (cursor->id == id) + { + return cursor; + } + cursor = cursor->next; + } + return NULL; // erreur } \ No newline at end of file diff --git a/jobs.h b/jobs.h index e843816..20259ba 100644 --- a/jobs.h +++ b/jobs.h @@ -8,16 +8,18 @@ struct cell int pid; char *cmd; cell *next; - int state; }; typedef cell *list; -void ajouter(cell **list, int pid, int id, char **cmd, int state); -void supprimer(cell **list, int pid); -void afficher(cell **list); void initialiser(list *list); void liberer(list *list); +void afficher(cell **list); + +int ajouter(cell **list, int pid, char **cmd); +void supprimer(cell **list, int pid); + cell *trouver(list *l_ptr, int pid); +cell *trouver_id(list *l_ptr, int id); #endif \ No newline at end of file diff --git a/list.c b/list.c new file mode 100644 index 0000000..0a788a4 --- /dev/null +++ b/list.c @@ -0,0 +1,83 @@ +#include +#include +#include "list.h" + +#define INIT_LIMIT 8 + +void init(list *l_ptr) +{ + l_ptr->limit = INIT_LIMIT; + l_ptr->jobs = malloc(l_ptr->limit * sizeof(job)); + if (l_ptr->jobs == NULL) + { + printf(stderr, "ERROR: malloc failed\n"); + exit(1); + } +} + +job add(list *l_ptr, int pid, char **cmd, int state) +{ + job new_job; + new_job.pid = pid; + new_job.cmd = cmd; + new_job.used = 1; + + for (int i = 0; i < l_ptr->size; i++) + { + if (!l_ptr->jobs[i].used) + { + l_ptr->jobs[i] = new_job; + return new_job; + } + } + + l_ptr->limit = l_ptr->limit * 2; + l_ptr->jobs = realloc(l_ptr->jobs, l_ptr->limit * sizeof(job)); + if (l_ptr->jobs == NULL) + { + printf(stderr, "ERROR: realloc failed\n"); + exit(1); + } + l_ptr->jobs[l_ptr->limit / 2] = new_job; + return new_job; +} + +int is_empty(list l_ptr) +{ + return l_ptr.size == 0; +} + +job remove(list *l_ptr, int pid) +{ + if (is_empty(*l_ptr)) + { + printf(stderr, "ERROR: jobs is empty, cannot remove\n"); + exit(1); + } + + for (int i = 0; i < l_ptr->size; i++) + { + if (l_ptr->jobs[i].pid == pid) + { + job job = l_ptr->jobs[i]; + job.used = 0; + return l_ptr->jobs[i]; + } + } +} + +job top(list l_ptr) +{ + return l_ptr.jobs[l_ptr.size - 1]; +} + +job get(list l_ptr, int index) +{ + return l_ptr.jobs[index]; +} + +void free(list *l_ptr) +{ + free(l_ptr->jobs); + l_ptr->jobs = NULL; +} \ No newline at end of file diff --git a/list.h b/list.h new file mode 100644 index 0000000..7dae76f --- /dev/null +++ b/list.h @@ -0,0 +1,25 @@ +#ifndef __LIST_H +#define __LIST_H + +typedef struct job +{ + int pid; + char *cmd; + int used; +} job; + +typedef struct list { + job *jobs; + int size; + int limit; +} list; + + +void init(list *list); +void free(list *list); +void print(list *list); + +job add(list *list, int pid, char **cmd, int state); +job remove(list *list, int pid); + +#endif \ No newline at end of file diff --git a/minishell b/minishell index 4ef753f..b5bc3d7 100755 Binary files a/minishell and b/minishell differ diff --git a/minishell copy.c b/minishell copy.c new file mode 100644 index 0000000..aee3482 --- /dev/null +++ b/minishell copy.c @@ -0,0 +1,207 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include "readcmd.h" +#include "jobs.h" + +extern int errno; + +struct cmdline *cmd; + +int pid_fils; + +list jobs; + +int prompting = 0; +jmp_buf goto_prompt; + +char initcd[256], currentcd[256]; + +void handler_sigchld(int sig_num, siginfo_t *info) +{ + cell *job = trouver(&jobs, info->si_pid); + if (job) + { + if (prompting) + { + printf("\n"); + } + + printf("[%d] %d done: %s\n", job->id, job->pid, job->cmd); + supprimer(&jobs, job->pid); + + if (prompting) + { + siglongjmp(goto_prompt, sig_num); + } + } +} + +void handler_sigint(int sig_num) +{ + printf("\n"); + siglongjmp(goto_prompt, sig_num); +} + +void handler_sigtstp(int sig_num) +{ + if (!prompting) + { + kill(pid_fils, SIGTSTP); + int id_fils = ajouter(&jobs, pid_fils, *(cmd->seq)); + printf("[%d] %d suspended\n", id_fils, pid_fils); + siglongjmp(goto_prompt, sig_num); + } + else + { + handler_sigint(sig_num); + } +} + +void attendre(int pid) +{ + int wait_code; + pid_t id = waitpid(pid, &wait_code, 0); // on attend la fin de l'exec du fils + + if (id == -1) + { // wait fail ? + fprintf(stderr, "ERROR: waiting for %d failed, (%d) %s\n", wait_code, errno, strerror(errno)); + exit(errno); + } + + if (wait_code) + { // execvp fail ? + fprintf(stderr, "ERROR: %d's execution failed, (%d) %s\n", pid, wait_code, strerror(wait_code)); + } +} + +int main(int argc, char *argv[]) +{ + initialiser(&jobs); + getcwd(initcd, sizeof(initcd)); + + // gestion des signaux + struct sigaction action; + sigemptyset(&action.sa_mask); + action.sa_flags = SA_SIGINFO | SA_RESTART; + action.sa_handler = handler_sigchld; + sigaction(SIGCHLD, &action, NULL); + action.sa_handler = handler_sigint; + sigaction(SIGINT, &action, NULL); + action.sa_handler = handler_sigtstp; + sigaction(SIGTSTP, &action, NULL); + + // loop principal + while (1) + { + sigsetjmp(goto_prompt, 1); + + prompting = 1; + getcwd(currentcd, sizeof(currentcd)); + printf("%s >>> ", currentcd); + cmd = readcmd(); + prompting = 0; + + if (cmd == NULL) + { // EOF + break; + } + else if (cmd->seq[0] == NULL) + { // empty + continue; + } + else if (!strcmp(cmd->seq[0][0], "exit")) + { // "exit" + break; + } + else if (!strcmp(cmd->seq[0][0], "cd")) + { // "cd" + int ret = 0; + if (cmd->seq[0][1] == NULL) + { // no path + ret = chdir(initcd); + } + else + { // with path + ret = chdir(cmd->seq[0][1]); + } + if (ret) + { // wrong path + fprintf(stderr, "ERROR: cd failed, (%d) %s\n", errno, strerror(errno)); + } + continue; + } + else if (!strcmp(cmd->seq[0][0], "jobs")) + { // "jobs" + afficher(&jobs); + continue; + } + else if (!strcmp(cmd->seq[0][0], "bg")) + { // "bg" + kill(pid_fils, SIGCONT); + continue; + } + else if (!strcmp(cmd->seq[0][0], "fg")) + { // "fg" + cell *job; + if (cmd->seq[0][1] == NULL) + { // no id + fprintf(stderr, "ERROR: fg id error"); + continue; + } + else + { // id specified + job = &(jobs[atoi(cmd->seq[0][1]) - 1]); + } + kill(job->pid, SIGCONT); + printf("[%d] %d continued: %s\n", job->id, job->pid, job->cmd); + supprimer(&job, job->pid); + attendre(job->pid); + continue; + } + pid_fils = fork(); + if (pid_fils == -1) + { // fork fail ? + fprintf(stderr, "ERROR: forking failed, (%d) %s\n", errno, strerror(errno)); + exit(errno); + } + + if (pid_fils == 0) + { // instructions du fils + action.sa_handler = SIG_DFL; + sigaction(SIGTSTP, &action, NULL); // on default SIGTSTP + sigaction(SIGCONT, &action, NULL); // on default SIGCONT + + if (cmd->backgrounded) + { // background + action.sa_handler = SIG_IGN; + sigaction(SIGINT, &action, NULL); // on ignore SIGINT + sigaction(SIGTSTP, &action, NULL); // on ignore SIGTSTP + } + + execvp(cmd->seq[0][0], cmd->seq[0]); + exit(errno); // si execlp échoue on exit avec une erreur + } + else + { // instructions du père + if (cmd->backgrounded) + { // background + int id_fils = ajouter(&jobs, pid_fils, *(cmd->seq)); + printf("[%d] %d\n", id_fils, pid_fils); + } + else + { // foreground + attendre(pid_fils); + } + } + } + + return EXIT_SUCCESS; +} diff --git a/minishell.c b/minishell.c index 5efdfe7..623c806 100644 --- a/minishell.c +++ b/minishell.c @@ -15,9 +15,8 @@ extern int errno; struct cmdline *cmd; -int pid_fils; +int pid_fils, wait_code; -int job_id = 0; list jobs; int prompting = 0; @@ -25,62 +24,86 @@ jmp_buf goto_prompt; char initcd[256], currentcd[256]; - - -void handler_sigchld(int sig_num, siginfo_t *info) +void handler_sigchld(int sig_num) { - cell *job = trouver(&jobs, info->si_pid); - if (job) + do { - if (prompting) - { - printf("\n"); + pid_fils = waitpid(-1, &wait_code, WNOHANG | WUNTRACED | WCONTINUED); + if ((pid_fils == -1) && (errno != ECHILD)) + { // wait fail ? + fprintf(stderr, "ERROR: waiting for child failed, (%d) %s\n", errno, strerror(errno)); + exit(errno); } - printf("[%d] %d done: %s\n", job->id, job->pid, job->cmd); - supprimer(&jobs, job->pid); - job_id--; - - if (prompting) + cell *job = trouver(&jobs, pid_fils); + if (job != NULL) { - siglongjmp(goto_prompt, sig_num); + if (prompting) + { + printf("\n"); + } + + if (WIFSTOPPED(wait_code)) + { + printf("[%d] %d suspended: %s\n", job->id, job->pid, job->cmd); + } + else if (WIFCONTINUED(wait_code)) + { + printf("[%d] %d continued: %s\n", job->id, job->pid, job->cmd); + } + else if (WIFEXITED(wait_code)) + { + printf("[%d] %d done: %s\n", job->id, job->pid, job->cmd); + supprimer(&jobs, job->pid); + } + + if (prompting) + { + siglongjmp(goto_prompt, sig_num); + } } - } + } while (pid_fils > 0); } - - void handler_sigint(int sig_num) { printf("\n"); + if (!prompting) + { + kill(pid_fils, SIGKILL); + pause(); + } siglongjmp(goto_prompt, sig_num); } - - void handler_sigtstp(int sig_num) { + printf("\n"); if (!prompting) { - kill(pid_fils, SIGTSTP); - ajouter(&jobs, pid_fils, ++job_id, *(cmd->seq), 1); - printf("[%d] %d suspended\n", job_id, pid_fils); - siglongjmp(goto_prompt, sig_num); - } - else - { - handler_sigint(sig_num); + ajouter(&jobs, pid_fils, *(cmd->seq)); + kill(pid_fils, SIGSTOP); + pause(); } + siglongjmp(goto_prompt, sig_num); } - - -void handler_sigcont(int sig_num) +void attendre(int pid) { + pid_t id = waitpid(pid, &wait_code, 0); // on attend la fin de l'exec du fils + if (id == -1) + { // wait fail ? + fprintf(stderr, "ERROR: waiting for %d failed, (%d) %s\n", wait_code, errno, strerror(errno)); + exit(errno); + } + + if (wait_code) + { // execvp fail ? + fprintf(stderr, "ERROR: %d's execution failed, (%d) %s\n", pid, wait_code, strerror(wait_code)); + } } - int main(int argc, char *argv[]) { initialiser(&jobs); @@ -97,7 +120,7 @@ int main(int argc, char *argv[]) action.sa_handler = handler_sigtstp; sigaction(SIGTSTP, &action, NULL); - // loop principal + // main loop while (1) { sigsetjmp(goto_prompt, 1); @@ -120,11 +143,6 @@ int main(int argc, char *argv[]) { // "exit" break; } - else if (!strcmp(cmd->seq[0][0], "jobs")) - { // "jobs" - afficher(&jobs); - continue; - } else if (!strcmp(cmd->seq[0][0], "cd")) { // "cd" int ret = 0; @@ -142,6 +160,49 @@ int main(int argc, char *argv[]) } continue; } + else if (!strcmp(cmd->seq[0][0], "jobs")) + { // "jobs" + afficher(&jobs); + continue; + } + else if (!strcmp(cmd->seq[0][0], "bg")) + { // "bg" + cell *job; + if (cmd->seq[0][1] == NULL) + { // no id + fprintf(stderr, "ERROR: fg id error\n"); + continue; + } + else + { // id specified + job = trouver_id(&jobs, atoi(cmd->seq[0][1])); + } + kill(job->pid, SIGCONT); + pause(); + continue; + } + else if (!strcmp(cmd->seq[0][0], "fg")) + { // "fg" + cell *job; + if (cmd->seq[0][1] == NULL) + { // no id + fprintf(stderr, "ERROR: fg id error\n"); + continue; + } + else + { // id specified + job = trouver_id(&jobs, atoi(cmd->seq[0][1])); + } + kill(job->pid, SIGCONT); + pause(); + attendre(job->pid); + continue; + } + else if (!strcmp(cmd->seq[0][0], "pid")) + { // "pid" + printf("pid=%d\n", getpid()); + continue; + } pid_fils = fork(); if (pid_fils == -1) @@ -152,18 +213,10 @@ int main(int argc, char *argv[]) if (pid_fils == 0) { // instructions du fils - action.sa_handler = SIG_DFL; - sigaction(SIGTSTP, &action, NULL); // on default SIGTSTP - sigaction(SIGCONT, &action, NULL); // on default SIGCONT + action.sa_handler = SIG_IGN; + sigaction(SIGTSTP, &action, NULL); // on igonre SIGTSTP + sigaction(SIGINT, &action, NULL); // on ignore SIGINT - if (cmd->backgrounded) - { // background - action.sa_handler = SIG_IGN; - sigaction(SIGINT, &action, NULL); // on ignore SIGINT - sigaction(SIGTSTP, &action, NULL); // on ignore SIGTSTP - - } - execvp(cmd->seq[0][0], cmd->seq[0]); exit(errno); // si execlp échoue on exit avec une erreur } @@ -171,24 +224,12 @@ int main(int argc, char *argv[]) { // instructions du père if (cmd->backgrounded) { // background - ajouter(&jobs, pid_fils, ++job_id, *(cmd->seq), 0); - printf("[%d] %d\n", job_id, pid_fils); + int id_fils = ajouter(&jobs, pid_fils, *(cmd->seq)); + printf("[%d] %d\n", id_fils, pid_fils); } else { // foreground - int wait_code; - pid_t id_fils = waitpid(pid_fils, &wait_code, 0); // on attend la fin de l'exec du fils - - if (id_fils == -1) - { // wait fail ? - fprintf(stderr, "ERROR: waiting for %d failed, (%d) %s\n", wait_code, errno, strerror(errno)); - exit(errno); - } - - if (wait_code) - { // execvp fail ? - fprintf(stderr, "ERROR: %d's execution failed, (%d) %s\n", pid_fils, wait_code, strerror(wait_code)); - } + attendre(pid_fils); } } } diff --git a/minishell2.c b/minishell2.c new file mode 100644 index 0000000..d829781 --- /dev/null +++ b/minishell2.c @@ -0,0 +1,210 @@ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include "readcmd.h" +#include "jobs.h" + +extern int errno; + +struct cmdline *cmd; + +int pid_fils; + +int job_id = 0; +list jobs; + +int prompting = 0; +jmp_buf goto_prompt; + +char initcd[256], currentcd[256]; + +void handler_sigchld(int sig_num, siginfo_t *info) +{ + cell *job = trouver(&jobs, info->si_pid); + if (job && !job->state) + { + if (prompting) + { + printf("\n"); + } + + printf("[%d] %d done: %s\n", job->id, job->pid, job->cmd); + supprimer(&jobs, job->pid); + job_id--; + + if (prompting) + { + siglongjmp(goto_prompt, sig_num); + } + } +} + +void handler_sigint(int sig_num) +{ + printf("\n"); + siglongjmp(goto_prompt, sig_num); +} + +void handler_sigtstp(int sig_num) +{ + if (!prompting) + { + kill(pid_fils, SIGTSTP); + cell *job = ajouter(&jobs, pid_fils, ++job_id, *(cmd->seq), 1); + printf("[%d] %d suspended: %s\n", job_id, pid_fils, job->cmd); + siglongjmp(goto_prompt, sig_num); + } + else + { + handler_sigint(sig_num); + } +} + +void attendre(int pid) +{ + int wait_code; + pid_t id = waitpid(pid, &wait_code, 0); // on attend la fin de l'exec du fils + + if (id == -1) + { // wait fail ? + fprintf(stderr, "ERROR: waiting for %d failed, (%d) %s\n", wait_code, errno, strerror(errno)); + exit(errno); + } + + if (wait_code) + { // execvp fail ? + fprintf(stderr, "ERROR: %d's execution failed, (%d) %s\n", pid, wait_code, strerror(wait_code)); + } +} + +int main(int argc, char *argv[]) +{ + initialiser(&jobs); + getcwd(initcd, sizeof(initcd)); + + // gestion des signaux + struct sigaction action; + sigemptyset(&action.sa_mask); + action.sa_flags = SA_SIGINFO | SA_RESTART; + action.sa_handler = handler_sigchld; + sigaction(SIGCHLD, &action, NULL); + action.sa_handler = handler_sigint; + sigaction(SIGINT, &action, NULL); + action.sa_handler = handler_sigtstp; + sigaction(SIGTSTP, &action, NULL); + + // loop principal + while (1) + { + sigsetjmp(goto_prompt, 1); + + prompting = 1; + getcwd(currentcd, sizeof(currentcd)); + printf("%s >>> ", currentcd); + cmd = readcmd(); + prompting = 0; + + if (cmd == NULL) + { // EOF + break; + } + else if (cmd->seq[0] == NULL) + { // empty + continue; + } + else if (!strcmp(cmd->seq[0][0], "exit")) + { // "exit" + break; + } + else if (!strcmp(cmd->seq[0][0], "cd")) + { // "cd" + int ret = 0; + if (cmd->seq[0][1] == NULL) + { // no path + ret = chdir(initcd); + } + else + { // with path + ret = chdir(cmd->seq[0][1]); + } + if (ret) + { // wrong path + fprintf(stderr, "ERROR: cd failed, (%d) %s\n", errno, strerror(errno)); + } + continue; + } + else if (!strcmp(cmd->seq[0][0], "jobs")) + { // "jobs" + afficher(&jobs); + continue; + } + else if (!strcmp(cmd->seq[0][0], "bg")) + { // "bg" + kill(pid_fils, SIGCONT); + continue; + } + else if (!strcmp(cmd->seq[0][0], "fg")) + { // "fg" + cell *job; + if (cmd->seq[0][1] == NULL) + { // no id + fprintf(stderr, "ERROR: fg id error"); + continue; + } + else + { // id specified + job = &(jobs[atoi(cmd->seq[0][1]) - 1]); + } + kill(job->pid, SIGCONT); + printf("[%d] %d continued: %s\n", job->id, job->pid, job->cmd); + supprimer(&job, job->pid); + job_id--; + attendre(job->pid); + continue; + } + pid_fils = fork(); + if (pid_fils == -1) + { // fork fail ? + fprintf(stderr, "ERROR: forking failed, (%d) %s\n", errno, strerror(errno)); + exit(errno); + } + + if (pid_fils == 0) + { // instructions du fils + action.sa_handler = SIG_DFL; + sigaction(SIGTSTP, &action, NULL); // on default SIGTSTP + sigaction(SIGCONT, &action, NULL); // on default SIGCONT + + if (cmd->backgrounded) + { // background + action.sa_handler = SIG_IGN; + sigaction(SIGINT, &action, NULL); // on ignore SIGINT + sigaction(SIGTSTP, &action, NULL); // on ignore SIGTSTP + } + + execvp(cmd->seq[0][0], cmd->seq[0]); + exit(errno); // si execlp échoue on exit avec une erreur + } + else + { // instructions du père + if (cmd->backgrounded) + { // background + ajouter(&jobs, pid_fils, ++job_id, *(cmd->seq), 0); + printf("[%d] %d\n", job_id, pid_fils); + } + else + { // foreground + attendre(pid_fils); + } + } + } + + return EXIT_SUCCESS; +} diff --git a/readcmd b/readcmd index 6ee49c7..ab35060 100755 Binary files a/readcmd and b/readcmd differ diff --git a/test.sh b/test.sh index 1c0a797..fe779ba 100644 --- a/test.sh +++ b/test.sh @@ -1,2 +1,2 @@ -sleep 5 -printf "\n\nbonjourr\n\n" \ No newline at end of file +sleep 3 +printf "\n\n\n\n bonjour \n\n\n\n" \ No newline at end of file