Skip to content
Snippets Groups Projects
Commit 04501785 authored by Joey Le's avatar Joey Le
Browse files

Hopefully pipelines work

parent a60b4c57
Branches
No related tags found
No related merge requests found
1. Your shell forks multiple child processes when executing piped commands. How does your implementation ensure that all child processes complete before the shell continues accepting user input? What would happen if you forgot to call waitpid() on all child processes? 1. Your shell forks multiple child processes when executing piped commands. How does your implementation ensure that all child processes complete before the shell continues accepting user input? What would happen if you forgot to call waitpid() on all child processes?
_answer here_ _The shell makes sure that it's all complete by calling waitpid() for each child process. It could cause a incorrect output, mess with the pointers, cause a zombie process to occur, and messy things to happen._
2. The dup2() function is used to redirect input and output file descriptors. Explain why it is necessary to close unused pipe ends after calling dup2(). What could go wrong if you leave pipes open? 2. The dup2() function is used to redirect input and output file descriptors. Explain why it is necessary to close unused pipe ends after calling dup2(). What could go wrong if you leave pipes open?
_answer here_ _Closing pipes is very necessary, it will cause memory leaks, and make the pipes open causing it to read forever, and also make sure that the pipline close correctly._
3. Your shell recognizes built-in commands (cd, exit, dragon). Unlike external commands, built-in commands do not require execvp(). Why is cd implemented as a built-in rather than an external command? What challenges would arise if cd were implemented as an external process? 3. Your shell recognizes built-in commands (cd, exit, dragon). Unlike external commands, built-in commands do not require execvp(). Why is cd implemented as a _built-in rather than an external command? What challenges would arise if cd were implemented as an external process?_
_answer here_ I think cd makes it so that the shell directory itself is changed and not the original directory, it wouldn't change our shell, and would be inefficient.
4. Currently, your shell supports a fixed number of piped commands (CMD_MAX). How would you modify your implementation to allow an arbitrary number of piped commands while still handling memory allocation efficiently? What trade-offs would you need to consider? 4. Currently, your shell supports a fixed number of piped commands (CMD_MAX). How would you modify your implementation to allow an arbitrary number of piped commands while still handling memory allocation efficiently? What trade-offs would you need to consider?
_answer here_ _So we would use dynamic memory instead and create more loops. I think the memory would be really confusing, and could cause lots of performance errors with all of the memory management we would be doing. Lots of error handling to deal with memory allocations, and failed mallocs._
...@@ -53,6 +53,7 @@ int build_cmd_buff(char *cmd_line, cmd_buff_t *cmd_buff) { ...@@ -53,6 +53,7 @@ int build_cmd_buff(char *cmd_line, cmd_buff_t *cmd_buff) {
return OK; return OK;
} }
int execute_pipeline(command_list_t *cmd_list) { int execute_pipeline(command_list_t *cmd_list) {
int num_commands = cmd_list->num; int num_commands = cmd_list->num;
int pipefd[2]; int pipefd[2];
...@@ -85,10 +86,21 @@ int execute_pipeline(command_list_t *cmd_list) { ...@@ -85,10 +86,21 @@ int execute_pipeline(command_list_t *cmd_list) {
close(pipefd[0]); close(pipefd[0]);
} }
if (prev_pipe_read != -1) {
close(prev_pipe_read);
}
cmd_buff_t *cmd = &cmd_list->commands[i]; cmd_buff_t *cmd = &cmd_list->commands[i];
if (cmd->argv[0] == NULL) {
fprintf(stderr, "execvp error: command is NULL\n");
exit(ERR_EXEC_CMD);
}
execvp(cmd->argv[0], cmd->argv); execvp(cmd->argv[0], cmd->argv);
perror("execvp"); perror("execvp");
exit(EXIT_FAILURE); exit(ERR_EXEC_CMD);
} else { } else {
if (prev_pipe_read != -1) { if (prev_pipe_read != -1) {
close(prev_pipe_read); close(prev_pipe_read);
...@@ -104,14 +116,13 @@ int execute_pipeline(command_list_t *cmd_list) { ...@@ -104,14 +116,13 @@ int execute_pipeline(command_list_t *cmd_list) {
if (prev_pipe_read != -1) { if (prev_pipe_read != -1) {
char buffer[1024]; char buffer[1024];
ssize_t bytes_read; ssize_t bytes_read;
while ((bytes_read = read(prev_pipe_read, buffer, sizeof(buffer) - 1))) { while ((bytes_read = read(prev_pipe_read, buffer, sizeof(buffer) - 1)) > 0) {
if (bytes_read < 0) {
perror("read");
break;
}
buffer[bytes_read] = '\0'; buffer[bytes_read] = '\0';
printf("%s", buffer); printf("%s", buffer);
} }
if (bytes_read < 0) {
perror("read");
}
close(prev_pipe_read); close(prev_pipe_read);
} }
...@@ -123,6 +134,9 @@ int execute_pipeline(command_list_t *cmd_list) { ...@@ -123,6 +134,9 @@ int execute_pipeline(command_list_t *cmd_list) {
} }
int parse_pipeline(char *cmd_line, command_list_t *clist) { int parse_pipeline(char *cmd_line, command_list_t *clist) {
if (cmd_line == NULL || clist == NULL) { if (cmd_line == NULL || clist == NULL) {
return ERR_CMD_OR_ARGS_TOO_BIG; return ERR_CMD_OR_ARGS_TOO_BIG;
...@@ -174,73 +188,91 @@ int parse_pipeline(char *cmd_line, command_list_t *clist) { ...@@ -174,73 +188,91 @@ int parse_pipeline(char *cmd_line, command_list_t *clist) {
return OK; return OK;
} }
int execute_pipeline(command_list_t *cmd_list) { int exec_local_cmd_loop() {
int num_commands = cmd_list->num; char cmd_buff[SH_CMD_MAX];
int pipefd[2]; int rc = OK;
int prev_pipe_read = -1;
pid_t pids[num_commands];
for (int i = 0; i < num_commands; i++) { while (1) {
if (i < num_commands - 1) { printf("%s", SH_PROMPT);
if (pipe(pipefd) == -1) {
perror("pipe");
return ERR_MEMORY;
}
}
pids[i] = fork(); if (fgets(cmd_buff, SH_CMD_MAX, stdin) == NULL) {
if (pids[i] == -1) { printf("\n");
perror("fork"); break;
return ERR_MEMORY;
} }
if (pids[i] == 0) { cmd_buff[strcspn(cmd_buff, "\n")] = '\0';
if (prev_pipe_read != -1) {
dup2(prev_pipe_read, STDIN_FILENO);
close(prev_pipe_read);
}
if (i < num_commands - 1) { if (strlen(cmd_buff) == 0) {
dup2(pipefd[1], STDOUT_FILENO); printf("%s\n", CMD_WARN_NO_CMD);
close(pipefd[1]); rc = WARN_NO_CMDS;
close(pipefd[0]); continue;
} }
cmd_buff_t *cmd = &cmd_list->commands[i]; if (strstr(cmd_buff, "|") != NULL) {
execvp(cmd->argv[0], cmd->argv); command_list_t cmd_list;
perror("execvp"); if (parse_pipeline(cmd_buff, &cmd_list) != OK) {
exit(EXIT_FAILURE); fprintf(stderr, "%s\n", CMD_ERR_PIPE_LIMIT);
} else { rc = ERR_TOO_MANY_COMMANDS;
if (prev_pipe_read != -1) { continue;
close(prev_pipe_read);
} }
if (i < num_commands - 1) { if (execute_pipeline(&cmd_list) != OK) {
prev_pipe_read = pipefd[0]; fprintf(stderr, "%s\n", CMD_ERR_PIPE_LIMIT);
close(pipefd[1]); rc = ERR_MEMORY;
} }
for (int i = 0; i < cmd_list.num; i++) {
free(cmd_list.commands[i]._cmd_buffer);
} }
} else {
cmd_buff_t cmd;
if (build_cmd_buff(cmd_buff, &cmd) != OK) {
fprintf(stderr, "%s\n", CMD_ERR_PIPE_LIMIT);
rc = ERR_MEMORY;
continue;
} }
if (prev_pipe_read != -1) { if (strcmp(cmd.argv[0], EXIT_CMD) == 0) {
char buffer[1024]; free(cmd._cmd_buffer);
ssize_t bytes_read;
while ((bytes_read = read(prev_pipe_read, buffer, sizeof(buffer) - 1)) {
if (bytes_read < 0) {
perror("read");
break; break;
} }
buffer[bytes_read] = '\0';
printf("%s", buffer); if (strcmp(cmd.argv[0], "cd") == 0) {
if (cmd.argc == 1) {
chdir(getenv("HOME"));
} else if (cmd.argc == 2) {
if (chdir(cmd.argv[1]) != 0) {
perror("cd");
} }
close(prev_pipe_read); } else {
fprintf(stderr, "%s\n", CMD_ERR_PIPE_LIMIT);
}
free(cmd._cmd_buffer);
continue;
} }
pid_t pid = fork();
if (pid < 0) {
perror("fork failed");
rc = ERR_MEMORY;
} else if (pid == 0) {
execvp(cmd.argv[0], cmd.argv);
perror("execvp failed");
exit(EXIT_FAILURE);
} else {
int status;
wait(&status);
for (int i = 0; i < num_commands; i++) { if (WIFEXITED(status)) {
waitpid(pids[i], NULL, 0); if (WEXITSTATUS(status) != 0) {
fprintf(stderr, "Command failed with exit code %d\n", WEXITSTATUS(status));
}
}
} }
return OK; free(cmd._cmd_buffer);
}
} }
return rc;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment