diff --git a/Assignment-06/starter/rsh_cli.c b/Assignment-06/starter/rsh_cli.c index 1ce6b5b16829d5d6f60b6e3b4e97aa1dd6bfe733..38798f0e76349762690dae11bdbb4efdffc9fe47 100644 --- a/Assignment-06/starter/rsh_cli.c +++ b/Assignment-06/starter/rsh_cli.c @@ -90,13 +90,13 @@ * function after cleaning things up. See the documentation for client_cleanup() * */ -int exec_remote_cmd_loop(char *address, int port) -{ - char cmd_buff[RDSH_COMM_BUFF_SZ]; // Use the buffer size from rshlib.h + +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; + int is_eof = 0; // Declare and initialize // Connect to the server cli_socket = start_client(address, port); @@ -108,19 +108,50 @@ int exec_remote_cmd_loop(char *address, int port) while (1) { printf("rsh> "); if (!fgets(cmd_buff, RDSH_COMM_BUFF_SZ, stdin)) { - break; + break; // Exit on input error or EOF + } + + // 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'; + } + + // Handle local commands (e.g., cd, exit) + if (strncmp(cmd_buff, "cd", 2) == 0) { + // Handle cd locally + cmd_buff_t cmd; + if (build_cmd_buff(cmd_buff, &cmd) != OK) { + fprintf(stderr, "%s\n", CMD_ERR_PIPE_LIMIT); + continue; + } + 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); + } + free(cmd._cmd_buffer); + continue; + } else if (strncmp(cmd_buff, "exit", 4) == 0) { + break; // Exit the remote shell } - if (send(cli_socket, cmd_buff, strlen(cmd_buff), 0) < 0) { + // 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); } - is_eof = 0; + // Receive the server's response while ((recv_bytes = recv(cli_socket, rsp_buff, RDSH_COMM_BUFF_SZ, 0)) > 0) { - printf("%.*s", (int)recv_bytes, rsp_buff); // Print the received data + printf("%.*s", (int)recv_bytes, rsp_buff); if (rsp_buff[recv_bytes - 1] == RDSH_EOF_CHAR) { - is_eof = 1; // Check for EOF character + is_eof = 1; // Mark EOF break; } } @@ -128,15 +159,14 @@ int exec_remote_cmd_loop(char *address, int port) if (recv_bytes < 0) { perror("recv"); return client_cleanup(cli_socket, NULL, NULL, ERR_RDSH_COMMUNICATION); - } - - if (strncmp(cmd_buff, "exit", 4) == 0 || strncmp(cmd_buff, "stop-server", 11) == 0) { + } else if (recv_bytes == 0) { + printf("Server closed the connection\n"); break; } } - - return client_cleanup(cli_socket, cmd_buff, rsp_buff, OK); + (void)is_eof; // Suppress unused variable warning + return client_cleanup(cli_socket, NULL, NULL, OK); } /* diff --git a/Assignment-06/starter/rsh_server.c b/Assignment-06/starter/rsh_server.c index f34ddf31bc56c95db7916c3bf9fead1d426937f7..e6e7cb4ffd108dee848e4abfb2895cb96a79fd0c 100644 --- a/Assignment-06/starter/rsh_server.c +++ b/Assignment-06/starter/rsh_server.c @@ -591,107 +591,3 @@ int rsh_execute_pipeline(int cli_sock, command_list_t *clist) { return exit_code; } - -/************** OPTIONAL STUFF ***************/ -/**** - **** NOTE THAT THE FUNCTIONS BELOW ALIGN TO HOW WE CRAFTED THE SOLUTION - **** TO SEE IF A COMMAND WAS BUILT IN OR NOT. YOU CAN USE A DIFFERENT - **** STRATEGY IF YOU WANT. IF YOU CHOOSE TO DO SO PLEASE REMOVE THESE - **** FUNCTIONS AND THE PROTOTYPES FROM rshlib.h - **** - */ - -/* - * rsh_match_command(const char *input) - * cli_socket: The string command for a built-in command, e.g., dragon, - * cd, exit-server - * - * This optional function accepts a command string as input and returns - * one of the enumerated values from the BuiltInCmds enum as output. For - * example: - * - * Input Output - * exit BI_CMD_EXIT - * dragon BI_CMD_DRAGON - * - * This function is entirely optional to implement if you want to handle - * processing built-in commands differently in your implementation. - * - * Returns: - * - * BI_CMD_*: If the command is built-in returns one of the enumeration - * options, for example "cd" returns BI_CMD_CD - * - * BI_NOT_BI: If the command is not "built-in" the BI_NOT_BI value is - * returned. - */ -Built_In_Cmds rsh_match_command(const char *input) -{ - if (strcmp(input, "exit") == 0) - return BI_CMD_EXIT; - if (strcmp(input, "dragon") == 0) - return BI_CMD_DRAGON; - if (strcmp(input, "cd") == 0) - return BI_CMD_CD; - if (strcmp(input, "stop-server") == 0) - return BI_CMD_STOP_SVR; - if (strcmp(input, "rc") == 0) - return BI_CMD_RC; - return BI_NOT_BI; -} - -/* - * rsh_built_in_cmd(cmd_buff_t *cmd) - * cmd: The cmd_buff_t of the command, remember, this is the - * parsed version fo the command - * - * This optional function accepts a parsed cmd and then checks to see if - * the cmd is built in or not. It calls rsh_match_command to see if the - * cmd is built in or not. Note that rsh_match_command returns BI_NOT_BI - * if the command is not built in. If the command is built in this function - * uses a switch statement to handle execution if appropriate. - * - * Again, using this function is entirely optional if you are using a different - * strategy to handle built-in commands. - * - * Returns: - * - * BI_NOT_BI: Indicates that the cmd provided as input is not built - * in so it should be sent to your fork/exec logic - * BI_EXECUTED: Indicates that this function handled the direct execution - * of the command and there is nothing else to do, consider - * it executed. For example the cmd of "cd" gets the value of - * BI_CMD_CD from rsh_match_command(). It then makes the libc - * call to chdir(cmd->argv[1]); and finally returns BI_EXECUTED - * BI_CMD_* Indicates that a built-in command was matched and the caller - * is responsible for executing it. For example if this function - * returns BI_CMD_STOP_SVR the caller of this function is - * responsible for stopping the server. If BI_CMD_EXIT is returned - * the caller is responsible for closing the client connection. - * - * AGAIN - THIS IS TOTALLY OPTIONAL IF YOU HAVE OR WANT TO HANDLE BUILT-IN - * COMMANDS DIFFERENTLY. - */ -Built_In_Cmds rsh_built_in_cmd(cmd_buff_t *cmd) -{ - Built_In_Cmds ctype = BI_NOT_BI; - ctype = rsh_match_command(cmd->argv[0]); - - switch (ctype) - { - // case BI_CMD_DRAGON: - // print_dragon(); - // return BI_EXECUTED; - case BI_CMD_EXIT: - return BI_CMD_EXIT; - case BI_CMD_STOP_SVR: - return BI_CMD_STOP_SVR; - case BI_CMD_RC: - return BI_CMD_RC; - case BI_CMD_CD: - chdir(cmd->argv[1]); - return BI_EXECUTED; - default: - return BI_NOT_BI; - } -} diff --git a/Assignment-06/starter/rshlib.h b/Assignment-06/starter/rshlib.h index 6ae2ca9d992041d6d71d8d29a20304ddc5c1f700..927594ef97d524c2175d1d4fb85efa5b8288f788 100644 --- a/Assignment-06/starter/rshlib.h +++ b/Assignment-06/starter/rshlib.h @@ -54,6 +54,7 @@ static const char RDSH_EOF_CHAR = 0x04; int start_client(char *address, int port); int client_cleanup(int cli_socket, char *cmd_buff, char *rsp_buff, int rc); int exec_remote_cmd_loop(char *address, int port); +int parse_pipeline(const char *cmd_line, command_list_t *clist); //server prototypes for rsh_server.c - see documentation for each function to @@ -70,9 +71,5 @@ int rsh_execute_pipeline(int socket_fd, command_list_t *clist); Built_In_Cmds rsh_match_command(const char *input); Built_In_Cmds rsh_built_in_cmd(cmd_buff_t *cmd); -//eliminate from template, for extra credit -void set_threaded_server(int val); -int exec_client_thread(int main_socket, int cli_socket); -void *handle_client(void *arg); #endif \ No newline at end of file