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

Fixed dshlib.c

parent 4143e2cd
Branches
No related tags found
No related merge requests found
......@@ -6,10 +6,11 @@
#include <unistd.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <errno.h>
#include "dshlib.h"
// Function to build a command buffer from a command line
int build_cmd_buff(char *cmd_line, cmd_buff_t *cmd_buff) {
if (cmd_line == NULL || cmd_buff == NULL) {
return ERR_CMD_OR_ARGS_TOO_BIG;
......@@ -25,11 +26,11 @@ int build_cmd_buff(char *cmd_line, cmd_buff_t *cmd_buff) {
char *ptr = original_line;
char *arg_start = NULL;
bool in_quotes = false;//For quotes
bool in_quotes = false; // For quotes
char quote_char = '\0';
while (*ptr != '\0') {
if ((isspace((unsigned char)*ptr) && !in_quotes)) {
if ((isspace((unsigned char)*ptr) && !in_quotes) {
if (arg_start != NULL) {
*ptr = '\0';
cmd_buff->argv[cmd_buff->argc++] = arg_start;
......@@ -59,18 +60,11 @@ int build_cmd_buff(char *cmd_line, cmd_buff_t *cmd_buff) {
cmd_buff->argv[cmd_buff->argc] = NULL;
// Debugging output to verify parsing
// printf("Parsed command:\n");
// for (int i = 0; i < cmd_buff->argc; i++) {
// printf(" argv[%d]: %s\n", i, cmd_buff->argv[i]);
// }
return OK;
}
char *trim_whitespace(char *str) { //Had to make a new function for readability
// Function to trim whitespace from a string
char *trim_whitespace(char *str) {
char *end;
while (isspace((unsigned char)*str)) str++;
......@@ -82,15 +76,13 @@ char *trim_whitespace(char *str) { //Had to make a new function for readability
end = str + strlen(str) - 1;
while (end > str && isspace((unsigned char)*end)) end--;
// new null terminator
// New null terminator
*(end + 1) = '\0';
return str;
}
// Function to parse a pipeline of commands
int parse_pipeline(const char *cmd_line, command_list_t *clist) {
if (cmd_line == NULL || clist == NULL) {
return ERR_CMD_OR_ARGS_TOO_BIG;
......@@ -100,7 +92,8 @@ int parse_pipeline(const char *cmd_line, command_list_t *clist) {
if (line_copy == NULL) {
return ERR_MEMORY;
}
//Parsing using pipe.
// Parsing using pipe
clist->num = 0;
char *saveptr;
char *command = strtok_r(line_copy, "|", &saveptr);
......@@ -126,22 +119,11 @@ int parse_pipeline(const char *cmd_line, command_list_t *clist) {
return OK;
}
// Function to execute a pipeline of commands
int execute_pipeline(command_list_t *clist) {
int num_commands = clist->num;
int pipefd[2 * (num_commands - 1)];
pid_t pids[num_commands];
// for (int i = 0; i < clist->num; i++) {
// printf("Command %d:\n", i);
// for (int j = 0; clist->commands[i].argv[j] != NULL; j++) {
// printf(" argv[%d]: %s\n", j, clist->commands[i].argv[j]);
// }
// }
for (int i = 0; i < num_commands - 1; i++) {
if (pipe(pipefd + 2 * i) == -1) {
......@@ -159,7 +141,7 @@ int execute_pipeline(command_list_t *clist) {
}
if (pids[i] == 0) { // Child process
// if not first moves input
// Redirect input if not the first command
if (i > 0) {
if (dup2(pipefd[2 * (i - 1)], STDIN_FILENO) == -1) {
perror("dup2 stdin");
......@@ -175,7 +157,7 @@ int execute_pipeline(command_list_t *clist) {
}
}
// Close all pipe file descriptors. Very important stuff
// Close all pipe file descriptors
for (int j = 0; j < 2 * (num_commands - 1); j++) {
close(pipefd[j]);
}
......@@ -187,12 +169,12 @@ int execute_pipeline(command_list_t *clist) {
}
}
// Closes all pipe
// Close all pipe file descriptors in the parent
for (int i = 0; i < 2 * (num_commands - 1); i++) {
close(pipefd[i]);
}
// waitpid so everyhting is smooth
// Wait for all child processes to finish
for (int i = 0; i < num_commands; i++) {
int status;
waitpid(pids[i], &status, 0);
......@@ -206,137 +188,90 @@ int execute_pipeline(command_list_t *clist) {
return OK;
}
static void start_server() {
int listen_socket;
int ret;
}
/****
**** FOR REMOTE SHELL USE YOUR SOLUTION FROM SHELL PART 3 HERE
**** THE MAIN FUNCTION CALLS THIS ONE AS ITS ENTRY POINT TO
**** EXECUTE THE SHELL LOCALLY
****
*/
/*
* Implement your exec_local_cmd_loop function by building a loop that prompts the
* user for input. Use the SH_PROMPT constant from dshlib.h and then
* use fgets to accept user input.
*
* while(1){
* printf("%s", SH_PROMPT);
* if (fgets(cmd_buff, ARG_MAX, stdin) == NULL){
* printf("\n");
* break;
* }
* //remove the trailing \n from cmd_buff
* cmd_buff[strcspn(cmd_buff,"\n")] = '\0';
*
* //IMPLEMENT THE REST OF THE REQUIREMENTS
* }
*
* Also, use the constants in the dshlib.h in this code.
* SH_CMD_MAX maximum buffer size for user input
* EXIT_CMD constant that terminates the dsh program
* SH_PROMPT the shell prompt
* OK the command was parsed properly
* WARN_NO_CMDS the user command was empty
* ERR_TOO_MANY_COMMANDS too many pipes used
* ERR_MEMORY dynamic memory management failure
*
* errors returned
* OK No error
* ERR_MEMORY Dynamic memory management failure
* WARN_NO_CMDS No commands parsed
* ERR_TOO_MANY_COMMANDS too many pipes used
*
* console messages
* CMD_WARN_NO_CMD print on WARN_NO_CMDS
* CMD_ERR_PIPE_LIMIT print on ERR_TOO_MANY_COMMANDS
* CMD_ERR_EXECUTE print on execution failure of external command
*
* Standard Library Functions You Might Want To Consider Using (assignment 1+)
* malloc(), free(), strlen(), fgets(), strcspn(), printf()
*
* Standard Library Functions You Might Want To Consider Using (assignment 2+)
* fork(), execvp(), exit(), chdir()
*/
int exec_remote_cmd_loop(char *address, int port) {
char cmd_buff[RDSH_COMM_BUFF_SZ];
char rsp_buff[RDSH_COMM_BUFF_SZ];
int cli_socket;
ssize_t recv_bytes;
int is_eof;
// Connect to the server
cli_socket = start_client(address, port);
if (cli_socket < 0) {
perror("start client");
return client_cleanup(cli_socket, NULL, NULL, ERR_RDSH_CLIENT);
}
// Main loop for executing local commands
int exec_local_cmd_loop() {
char cmd_buff[SH_CMD_MAX];
int rc = OK;
while (1) {
printf("rsh> ");
if (!fgets(cmd_buff, RDSH_COMM_BUFF_SZ, stdin)) {
break; // Exit on input error or EOF
printf("%s", SH_PROMPT);
if (fgets(cmd_buff, SH_CMD_MAX, stdin) == NULL) {
printf("\n");
break;
}
// Remove the newline character from the command
size_t cmd_len = strlen(cmd_buff);
if (cmd_len > 0 && cmd_buff[cmd_len - 1] == '\n') {
cmd_buff[cmd_len - 1] = '\0';
cmd_buff[strcspn(cmd_buff, "\n")] = '\0';
if (strlen(cmd_buff) == 0) {
printf("%s\n", CMD_WARN_NO_CMD);
rc = WARN_NO_CMDS;
continue;
}
// Handle local commands (e.g., cd, exit)
if (strncmp(cmd_buff, "cd", 2) == 0) {
// Handle cd locally
if (strstr(cmd_buff, "|") != NULL) {
command_list_t cmd_list;
if (parse_pipeline(cmd_buff, &cmd_list) != OK) {
fprintf(stderr, "%s\n", CMD_ERR_PIPE_LIMIT);
rc = ERR_TOO_MANY_COMMANDS;
continue;
}
rc = execute_pipeline(&cmd_list);
// Free memory for each command's buffer
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 (cmd.argc == 1) {
chdir(getenv("HOME"));
} else if (cmd.argc == 2) {
if (chdir(cmd.argv[1]) != 0) {
perror("cd");
if (strcmp(cmd.argv[0], EXIT_CMD) == 0) {
free(cmd._cmd_buffer);
break;
}
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");
}
} else {
fprintf(stderr, "%s\n", CMD_ERR_PIPE_LIMIT);
}
} else {
fprintf(stderr, "%s\n", CMD_ERR_PIPE_LIMIT);
free(cmd._cmd_buffer);
continue;
}
free(cmd._cmd_buffer);
continue;
} else if (strncmp(cmd_buff, "exit", 4) == 0) {
break; // Exit the remote shell
}
// Send the command to the server
ssize_t sent_bytes = send(cli_socket, cmd_buff, strlen(cmd_buff), 0);
if (sent_bytes < 0) {
perror("send");
return client_cleanup(cli_socket, NULL, NULL, ERR_RDSH_COMMUNICATION);
}
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);
// Receive the server's response
is_eof = 0;
while ((recv_bytes = recv(cli_socket, rsp_buff, RDSH_COMM_BUFF_SZ, 0)) > 0) {
printf("%.*s", (int)recv_bytes, rsp_buff);
if (rsp_buff[recv_bytes - 1] == RDSH_EOF_CHAR) {
is_eof = 1;
break;
if (WIFEXITED(status)) {
if (WEXITSTATUS(status) != 0) {
fprintf(stderr, "Command failed with exit code %d\n", WEXITSTATUS(status));
}
}
}
}
if (recv_bytes < 0) {
perror("recv");
return client_cleanup(cli_socket, NULL, NULL, ERR_RDSH_COMMUNICATION);
} else if (recv_bytes == 0) {
printf("Server closed the connection\n");
break;
free(cmd._cmd_buffer);
}
}
return client_cleanup(cli_socket, NULL, NULL, OK);
}
return rc;
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment