From 6658ae04a8c36a0e36bd1fa4d54ffd8522311a8a Mon Sep 17 00:00:00 2001 From: Bao Mai <bgm47@drexel.edu> Date: Thu, 20 Feb 2025 22:55:06 -0500 Subject: [PATCH] update assignment 4 --- 4-ShellP2/.DS_Store | Bin 0 -> 6148 bytes 4-ShellP2/bats/assignment_tests.sh | 118 ++++++++++++++ 4-ShellP2/bats/student_tests.sh | 14 ++ 4-ShellP2/debug/launch.json | 29 ++++ 4-ShellP2/debug/tasks.json | 20 +++ 4-ShellP2/dragon.c | 6 + 4-ShellP2/dsh | Bin 0 -> 78152 bytes 4-ShellP2/dsh_cli.c | 13 ++ 4-ShellP2/dshlib.c | 242 +++++++++++++++++++++++++++++ 4-ShellP2/dshlib.h | 122 +++++++++++++++ 4-ShellP2/gitignore.txt | 1 + 4-ShellP2/makefile | 31 ++++ 4-ShellP2/questions.md | 41 +++++ 4-ShellP2/shell_roadmap.md | 13 ++ 14 files changed, 650 insertions(+) create mode 100644 4-ShellP2/.DS_Store create mode 100644 4-ShellP2/bats/assignment_tests.sh create mode 100644 4-ShellP2/bats/student_tests.sh create mode 100644 4-ShellP2/debug/launch.json create mode 100644 4-ShellP2/debug/tasks.json create mode 100644 4-ShellP2/dragon.c create mode 100755 4-ShellP2/dsh create mode 100644 4-ShellP2/dsh_cli.c create mode 100644 4-ShellP2/dshlib.c create mode 100644 4-ShellP2/dshlib.h create mode 100644 4-ShellP2/gitignore.txt create mode 100644 4-ShellP2/makefile create mode 100644 4-ShellP2/questions.md create mode 100644 4-ShellP2/shell_roadmap.md diff --git a/4-ShellP2/.DS_Store b/4-ShellP2/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..7899819c089041c78a1a01f3754c09624f3aceae GIT binary patch literal 6148 zcmZQzU|@7AO)+F(5MW?n;9!8zEL;p&0Z1N%F(jFwBElf^z-FW~<T2zjq%!0<AT1 zsnHM^4S~TM0-(Gr%#g@X%uvjb$$*@H;~7dAQW=UFN*Ib6^cad6GCXtglaq4tlc2?g zBLf42-hVIvdyj=7i6IfBIw##QI5|JJ04&PDJClKd0WO!D@8SYAgX6%0xpu{ykAciV zl23ul+h(=cpvxCzAe*fKvVxT%g&~z8iJ_Ds9o1&m6b1$cBw1v;pZwAdhMJ9{0%1FL z6<F-&U`SyoVn}32XUJ#BW6)zrMhmC)XyL@kkOB%#hIoc#h8%`WOdX7}XgWYP6f<Oi zRVQIl-%UV0TFf#2L{rbpkj{|FPy&tre1;;1R0chU5{3$f5>&r1rK9QOX2@YkWGH3G zV@PJmV9;a8VkicM0;(<sPz<jDCzSu72xH)2$Yn@m$Yw}oNMp!k$YDrDQx6I;Wc32z z@JeOKVaQ>KXDDLGXGmm70h>|4pvREQkb<fo9DeBfOBhPQ=>$|W5lGpLpzuW2&&5yz z&LP?0oPgDj;4nqj1NP`3Cm12_<KTwSqvU7^jE2By2*5)CR6c;JSP<<1Y2!0AKxmK< z10w?ixC_7ts^Foz7{UDj29O*`D~JYZ1<@d_42&Qa*bJ~%21W)JuuevBHw2^))FlDY zVC@Wy3}EdHj9{A?7#P7eGcYhhv@<Y5v@<Y5dnk+$?F@_%?F@_%?O;1biO~=k4FN<5 zFhiIEp!(mHfdN<lAEIiM91Vfd5Ezyrz{uhf?BWEjl(G8{RM&#)(*&qAs163z=8T|v s8ln%R1T4!08Bmk}b0Bgct)OZjTop4iKx*>Qh5#&tM(NQIpnnJe0FdwK#{d8T literal 0 HcmV?d00001 diff --git a/4-ShellP2/bats/assignment_tests.sh b/4-ShellP2/bats/assignment_tests.sh new file mode 100644 index 0000000..794b5d8 --- /dev/null +++ b/4-ShellP2/bats/assignment_tests.sh @@ -0,0 +1,118 @@ +#!/usr/bin/env bats + +############################ DO NOT EDIT THIS FILE ##################################### +# File: assignement_tests.sh +# +# DO NOT EDIT THIS FILE +# +# Add/Edit Student tests in student_tests.sh +# +# All tests in this file must pass - it is used as part of grading! +######################################################################################## + +@test "Change directory" { + current=$(pwd) + + cd /tmp + mkdir -p dsh-test + + run "${current}/dsh" <<EOF +cd dsh-test +pwd +EOF + + # Strip all whitespace (spaces, tabs, newlines) from the output + stripped_output=$(echo "$output" | tr -d '[:space:]') + + # Expected output with all whitespace removed for easier matching + expected_output="/tmp/dsh-testdsh2>dsh2>dsh2>cmdloopreturned0" + + # These echo commands will help with debugging and will only print + #if the test fails + echo "Captured stdout:" + echo "Output: $output" + echo "Exit Status: $status" + echo "${stripped_output} -> ${expected_output}" + + # Check exact match + [ "$stripped_output" = "$expected_output" ] + + # Assertions + [ "$status" -eq 0 ] +} + +@test "Change directory - no args" { + current=$(pwd) + + cd /tmp + mkdir -p dsh-test + + run "${current}/dsh" <<EOF +cd +pwd +EOF + + # Strip all whitespace (spaces, tabs, newlines) from the output + stripped_output=$(echo "$output" | tr -d '[:space:]') + + # Expected output with all whitespace removed for easier matching + expected_output="/tmpdsh2>dsh2>dsh2>cmdloopreturned0" + + # These echo commands will help with debugging and will only print + #if the test fails + echo "Captured stdout:" + echo "Output: $output" + echo "Exit Status: $status" + echo "${stripped_output} -> ${expected_output}" + + # Check exact match + [ "$stripped_output" = "$expected_output" ] + + # Assertions + [ "$status" -eq 0 ] +} + + +@test "Which which ... which?" { + run "./dsh" <<EOF +which which +EOF + + # Strip all whitespace (spaces, tabs, newlines) from the output + stripped_output=$(echo "$output" | tr -d '[:space:]') + + # Expected output with all whitespace removed for easier matching + expected_output="/usr/bin/whichdsh2>dsh2>cmdloopreturned0" + + # These echo commands will help with debugging and will only print + #if the test fails + echo "Captured stdout:" + echo "Output: $output" + echo "Exit Status: $status" + echo "${stripped_output} -> ${expected_output}" + + # Check exact match + [ "$stripped_output" = "$expected_output" ] +} + +@test "It handles quoted spaces" { + run "./dsh" <<EOF + echo " hello world " +EOF + + # Strip all whitespace (spaces, tabs, newlines) from the output + stripped_output=$(echo "$output" | tr -d '\t\n\r\f\v') + + # Expected output with all whitespace removed for easier matching + expected_output=" hello world dsh2> dsh2> cmd loop returned 0" + + # These echo commands will help with debugging and will only print + #if the test fails + echo "Captured stdout:" + echo "Output: $output" + echo "Exit Status: $status" + echo "${stripped_output} -> ${expected_output}" + + # Check exact match + [ "$stripped_output" = "$expected_output" ] +} \ No newline at end of file diff --git a/4-ShellP2/bats/student_tests.sh b/4-ShellP2/bats/student_tests.sh new file mode 100644 index 0000000..638bc34 --- /dev/null +++ b/4-ShellP2/bats/student_tests.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bats + +# File: student_tests.sh +# +# Create your unit tests suit in this file + +@test "Example: check ls runs without errors" { + run ./dsh <<EOF +ls +EOF + + # Assertions + [ "$status" -eq 0 ] +} diff --git a/4-ShellP2/debug/launch.json b/4-ShellP2/debug/launch.json new file mode 100644 index 0000000..aedc1ef --- /dev/null +++ b/4-ShellP2/debug/launch.json @@ -0,0 +1,29 @@ +{ + "configurations": [ + { + "name": "(gdb) 4-ShellP2", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/4-ShellP2/starter/dsh", + "args": [""], + "stopAtEntry": false, + "cwd": "${workspaceFolder}/4-ShellP2/starter", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + }, + { + "description": "Set Disassembly Flavor to Intel", + "text": "-gdb-set disassembly-flavor intel", + "ignoreFailures": true + } + ], + "preLaunchTask": "Build 4-ShellP2" + } + ] +} \ No newline at end of file diff --git a/4-ShellP2/debug/tasks.json b/4-ShellP2/debug/tasks.json new file mode 100644 index 0000000..71013e3 --- /dev/null +++ b/4-ShellP2/debug/tasks.json @@ -0,0 +1,20 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Build 4-ShellP2", + "type": "shell", + "command": "make", + "group": { + "kind": "build", + "isDefault": true + }, + "options": { + "cwd": "${workspaceFolder}/4-ShellP2/starter" + }, + "problemMatcher": ["$gcc"], + "detail": "Runs the 'make' command to build the project." + } + ] + } + \ No newline at end of file diff --git a/4-ShellP2/dragon.c b/4-ShellP2/dragon.c new file mode 100644 index 0000000..581408b --- /dev/null +++ b/4-ShellP2/dragon.c @@ -0,0 +1,6 @@ +#include <stdio.h> +#include "dshlib.h" +// EXTRA CREDIT - print the drexel dragon from the readme.md +extern void print_dragon(){ + printf("%s\n", DRAGON_ASCII); +} diff --git a/4-ShellP2/dsh b/4-ShellP2/dsh new file mode 100755 index 0000000000000000000000000000000000000000..ead4f253f37269bd40ef405a63ee5d2f880c9952 GIT binary patch literal 78152 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 DOJ%xU literal 0 HcmV?d00001 diff --git a/4-ShellP2/dsh_cli.c b/4-ShellP2/dsh_cli.c new file mode 100644 index 0000000..9262cf4 --- /dev/null +++ b/4-ShellP2/dsh_cli.c @@ -0,0 +1,13 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "dshlib.h" + +/* DO NOT EDIT + * main() logic moved to exec_local_cmd_loop() in dshlib.c +*/ +int main(){ + int rc = exec_local_cmd_loop(); + printf("cmd loop returned %d\n", rc); +} \ No newline at end of file diff --git a/4-ShellP2/dshlib.c b/4-ShellP2/dshlib.c new file mode 100644 index 0000000..0edc75e --- /dev/null +++ b/4-ShellP2/dshlib.c @@ -0,0 +1,242 @@ +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdbool.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/wait.h> +#include "dshlib.h" +#include <errno.h> + +/* + * 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 last_rc = 0; // Global variable to store the return code + +int exec_local_cmd_loop() { + cmd_buff_t cmd; + int rc; + + rc = alloc_cmd_buff(&cmd); + if (rc != OK) { + fprintf(stderr, "Error: Unable to allocate command buffer.\n"); + return ERR_MEMORY; + } + + while (1) { + printf("%s", SH_PROMPT); + + if (!fgets(cmd._cmd_buffer, SH_CMD_MAX, stdin)) { + printf("\n"); + break; + } + cmd._cmd_buffer[strcspn(cmd._cmd_buffer, "\n")] = '\0'; + + if (cmd._cmd_buffer[0] == '\0') { + printf("%s\n", CMD_WARN_NO_CMD); + continue; + } + char *input = cmd._cmd_buffer; + while (isspace((unsigned char)*input)) { + input++; + } + if (*input == '\0') { + printf("%s\n", CMD_WARN_NO_CMD); + continue; + } + + if (strcmp(input, EXIT_CMD) == 0) { + break; + } + if (strcmp(input, "dragon") == 0) { + print_dragon(); + continue; + } + if (strcmp(input, "rc") == 0) { + printf("%d\n", last_rc); + continue; + } + + rc = build_cmd_buff(cmd._cmd_buffer, &cmd); + if (rc != OK) { + fprintf(stderr, "Error: Failed to parse command.\n"); + continue; + } + + if (strcmp(cmd.argv[0], "cd") == 0) { + handle_cd(cmd.argv[1]); + continue; + } + + pid_t pid = fork(); + if (pid < 0) { + if (errno == EAGAIN) { + fprintf(stderr, "Error: System process limit reached (EAGAIN).\n"); + } else if (errno == ENOMEM) { + fprintf(stderr, "Error: Insufficient memory (ENOMEM).\n"); + } else { + perror("fork"); + } + continue; + } + + if (pid == 0) { + execvp(cmd.argv[0], cmd.argv); + + int err = errno; + switch (err) { + case ENOENT: + fprintf(stderr, "Error: Command not found.\n"); + break; + case EACCES: + fprintf(stderr, "Error: Permission denied.\n"); + break; + default: + fprintf(stderr, "Error: %s\n", strerror(err)); + break; + } + exit(err); + } else { + int status; + waitpid(pid, &status, 0); + last_rc = WEXITSTATUS(status); + } + } + + free_cmd_buff(&cmd); + return OK; +} + +int handle_cd(char *path) { + if (path) { + if (chdir(path) == -1) { + perror("cd"); + return -1; + } + } + return 0; +} + +int alloc_cmd_buff(cmd_buff_t *cmd) { + if (!cmd) { + return ERR_MEMORY; + } + cmd->_cmd_buffer = malloc(SH_CMD_MAX + 1); + if (!cmd->_cmd_buffer) { + return ERR_MEMORY; + } + + return OK; +} + +int free_cmd_buff(cmd_buff_t *cmd) { + if (!cmd) { + return ERR_MEMORY; + } + if (cmd->_cmd_buffer) { + free(cmd->_cmd_buffer); + cmd->_cmd_buffer = NULL; + } + + return OK; +} + +int clear_cmd_buff(cmd_buff_t *cmd) { + if (!cmd) { + return ERR_MEMORY; + } + cmd->argc = 0; + for (int i = 0; i < CMD_ARGV_MAX; i++) { + cmd->argv[i] = NULL; + } + + return OK; +} + + +int build_cmd_buff(char *cmd_line, cmd_buff_t *cmd) { + if (!cmd_line || !cmd) { + return ERR_MEMORY; + } + clear_cmd_buff(cmd); + int count = 0; + char *p = cmd_line; + while (*p) { + while (isspace((unsigned char)*p)) { + p++; + } + if (!*p) { + break; + } + + char *start = p; + if (*p == '"' || *p == '\'') { + char quote = *p++; + start = p; + + while (*p && *p != quote) { + p++; + } + if (*p == quote) { + *p++ = '\0'; + } + } + else { + while (*p && !isspace((unsigned char)*p)) { + p++; + } + if (*p) { + *p++ = '\0'; + } + } + cmd->argv[count++] = start; + if (count >= CMD_ARGV_MAX - 1) { + break; + } +} + + cmd->argv[count] = NULL; + cmd->argc = count; + return count ? OK : WARN_NO_CMDS; +} diff --git a/4-ShellP2/dshlib.h b/4-ShellP2/dshlib.h new file mode 100644 index 0000000..cc1d878 --- /dev/null +++ b/4-ShellP2/dshlib.h @@ -0,0 +1,122 @@ +#ifndef __DSHLIB_H__ + #define __DSHLIB_H__ + + +//Constants for command structure sizes +#define DRAGON_ASCII "\ + @%%%% \n\ + %%%%%% \n\ + %%%%%% \n\ + % %%%%%%% @ \n\ + %%%%%%%%%% %%%%%%% \n\ + %%%%%%% %%%%@ %%%%%%%%%%%%@ %%%%%% @%%%% \n\ + %%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%% \n\ + %%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%% %%%%%%%%%%%%%%% \n\ + %%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%% %%% \n\ + %%%%%%%%%%%%%%%%%%%%%%%%%%%%@ @%%%%%%%%%%%%%%%%%% %% \n\ + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%% \n\ + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \n\ + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%%@ \n\ + %%%%%%%%@ %%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%% %% \n\ + %%%%%%%%%%%%% %%@%%%%%%%%%%%% %%%%%%%%%%% %%%%%%%%%%%% @% \n\ + %%%%%%%%%% %%% %%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%% \n\ + %%%%%%%%% % %%%%%%%%%%%%% %%%%%%%%%%%%@%%%%%%%%%%% \n\ +%%%%%%%%%@ % %%%%%%%%%%%%% @%%%%%%%%%%%%%%%%%%%%%%%%% \n\ +%%%%%%%%@ %%@%%%%%%%%%%%% @%%%%%%%%%%%%%%%%%%%%%%%%%%%% \n\ +%%%%%%%@ %%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \n\ +%%%%%%%%%% %%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%% \n\ +%%%%%%%%%@ @%%%%%%%%%%%%%% %%%%%%%%%%%%@ %%%% %%%%%%%%%%%%%%%%% %%%%%%%%\n\ +%%%%%%%%%% %%%%%%%%%%%%%%%%% %%%%%%%%%%%%% %%%%%%%%%%%%%%%%%% %%%%%%%%%\n\ +%%%%%%%%%@%%@ %%%%%%%%%%%%%%%%@ %%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%% %%\n\ + %%%%%%%%%% % %%%%%%%%%%%%%%@ %%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%% %%\n\ + %%%%%%%%%%%% @ %%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% \n\ + %%%%%%%%%%%%% %% % %@ %%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% \n\ + %%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%% @%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%% \n\ + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% \n\ + @%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%% \n\ + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%% %%%%%%% \n\ + %%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%% @%%%%%%%%% \n\ + %%%%%%%%%%%%%%%%%%%% @%@% @%%%%%%%%%%%%%%%%%% %%% \n\ + %%%%%%%%%%%%%%% %%%%%%%%%% %%%%%%%%%%%%%%% % \n\ + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%% \n\ + %%%%%%%%%%%%%%%%%%%%%%%%%% %%%% %%% %%%%%%%%%% %%%@ \n\ + %%%%%%%%%%%%%%%%%%% %%%%%% %% %%%%%%%%%%%%%@ \n\ + %%%%%%%@ \n" + +#define EXE_MAX 64 +#define ARG_MAX 256 +#define CMD_MAX 8 +#define CMD_ARGV_MAX (CMD_MAX + 1) +// Longest command that can be read from the shell +#define SH_CMD_MAX EXE_MAX + ARG_MAX + +typedef struct cmd_buff +{ + int argc; + char *argv[CMD_ARGV_MAX]; + char *_cmd_buffer; +} cmd_buff_t; + +/* WIP - Move to next assignment +#define N_ARG_MAX 15 //MAX number of args for a command +typedef struct command{ + char exe [EXE_MAX]; + char args[ARG_MAX]; + int argc; + char *argv[N_ARG_MAX + 1]; //last argv[LAST] must be \0 +}command_t; +*/ + + +//Special character #defines +#define SPACE_CHAR ' ' +#define PIPE_CHAR '|' +#define PIPE_STRING "|" + +#define SH_PROMPT "dsh2> " +#define EXIT_CMD "exit" + +//Standard Return Codes +#define OK 0 +#define WARN_NO_CMDS -1 +#define ERR_TOO_MANY_COMMANDS -2 +#define ERR_CMD_OR_ARGS_TOO_BIG -3 +#define ERR_CMD_ARGS_BAD -4 //for extra credit +#define ERR_MEMORY -5 +#define ERR_EXEC_CMD -6 +#define OK_EXIT -7 + +//prototypes +int alloc_cmd_buff(cmd_buff_t *cmd_buff); +int free_cmd_buff(cmd_buff_t *cmd_buff); +int clear_cmd_buff(cmd_buff_t *cmd_buff); +int build_cmd_buff(char *cmd_line, cmd_buff_t *cmd_buff); +int handle_cd(char *path); +void print_dragon(void); + + +//built in command stuff +typedef enum { + BI_CMD_EXIT, + BI_CMD_DRAGON, + BI_CMD_CD, + BI_NOT_BI, + BI_EXECUTED, + BI_RC, +} Built_In_Cmds; +Built_In_Cmds match_command(const char *input); +Built_In_Cmds exec_built_in_cmd(cmd_buff_t *cmd); + +//main execution context +int exec_local_cmd_loop(); +int exec_cmd(cmd_buff_t *cmd); + + + + +//output constants +#define CMD_OK_HEADER "PARSED COMMAND LINE - TOTAL COMMANDS %d\n" +#define CMD_WARN_NO_CMD "warning: no commands provided\n" +#define CMD_ERR_PIPE_LIMIT "error: piping limited to %d commands\n" + +#endif \ No newline at end of file diff --git a/4-ShellP2/gitignore.txt b/4-ShellP2/gitignore.txt new file mode 100644 index 0000000..eb47a8e --- /dev/null +++ b/4-ShellP2/gitignore.txt @@ -0,0 +1 @@ +dsh \ No newline at end of file diff --git a/4-ShellP2/makefile b/4-ShellP2/makefile new file mode 100644 index 0000000..b14b072 --- /dev/null +++ b/4-ShellP2/makefile @@ -0,0 +1,31 @@ +# Compiler settings +CC = gcc +CFLAGS = -Wall -Wextra -g + +# Target executable name +TARGET = dsh + +# Find all source and header files +SRCS = $(wildcard *.c) +HDRS = $(wildcard *.h) + +# Default target +all: $(TARGET) + +# Compile source to executable +$(TARGET): $(SRCS) $(HDRS) + $(CC) $(CFLAGS) -o $(TARGET) $(SRCS) + +# Clean up build files +clean: + rm -f $(TARGET) + +test: + bats $(wildcard ./bats/*.sh) + +valgrind: + echo "pwd\nexit" | valgrind --leak-check=full --show-leak-kinds=all --error-exitcode=1 ./$(TARGET) + echo "pwd\nexit" | valgrind --tool=helgrind --error-exitcode=1 ./$(TARGET) + +# Phony targets +.PHONY: all clean test \ No newline at end of file diff --git a/4-ShellP2/questions.md b/4-ShellP2/questions.md new file mode 100644 index 0000000..d2798e5 --- /dev/null +++ b/4-ShellP2/questions.md @@ -0,0 +1,41 @@ +1. Can you think of why we use `fork/execvp` instead of just calling `execvp` directly? What value do you think the `fork` provides? + + > **Answer**: We need to use fork() since execvp() completely replaces the current process. If we just ran execvp(), our shell would be replaced with the command and then exited. We use fork() to create a copy of our shell process first, allowing the child process to run the command while the parent shell process continues to take commands. This also allows us to execute many commands and wait for them to complete. + +2. What happens if the fork() system call fails? How does your implementation handle this scenario? + + > **Answer**: Fork() sets errno to indicate the error and returns -1 if it fails. Our implementation would terminate the program and print an error message. + +3. How does execvp() find the command to execute? What system environment variable plays a role in this process? + + > **Answer**: In the directories specified in the PATH environment variable, execvp() looks for the command. + +4. What is the purpose of calling wait() in the parent process after forking? What would happen if we didn’t call it? + + > **Answer**: After a fork, the parent process calls wait() to wait for the child process to finish and obtain its exit state. This enables the parent process to manage the errors or output of the child process. The parent process would proceed right away after forking without waiting for the child process to finish if wait() wasn't used. + +5. In the referenced demo code we used WEXITSTATUS(). What information does this provide, and why is it important? + + > **Answer**: The child process's exit status is provided by WEXITSTATUS(). It's crucial since it enables the parent process to determine if the child process ended successfully or unsuccessfully. + +6. Describe how your implementation of build_cmd_buff() handles quoted arguments. Why is this necessary? + + > **Answer**: I use it for execvp() after copying every character in an argument—aside from the quote marks—to a new string. Prior to that, all leading and trailing spaces are eliminated. This is required because one argument with white spaces between it is regarded as several arguments if quotation marks are not removed by excecvp(). + +7. What changes did you make to your parsing logic compared to the previous assignment? Were there any unexpected challenges in refactoring your old code? + + > **Answer**: In this implementation, I employed a straightforward parsing technique that uses strtok() to divide the command line into the executable name and parameters. The command name is the first token, while the remaining tokens are the arguments. The primary difficulty was ensuring that the argv array was correctly NULL-terminated for execvp() to function. + +8. For this quesiton, you need to do some research on Linux signals. You can use [this google search](https://www.google.com/search?q=Linux+signals+overview+site%3Aman7.org+OR+site%3Alinux.die.net+OR+site%3Atldp.org&oq=Linux+signals+overview+site%3Aman7.org+OR+site%3Alinux.die.net+OR+site%3Atldp.org&gs_lcrp=EgZjaHJvbWUyBggAEEUYOdIBBzc2MGowajeoAgCwAgA&sourceid=chrome&ie=UTF-8) to get started. + +- What is the purpose of signals in a Linux system, and how do they differ from other forms of interprocess communication (IPC)? + + > **Answer**: In a Linux system, signals are used to facilitate communication between processes. Signals are asynchronous and unidirectional, which sets them apart from other types of IPC like pipes or sockets. + +- Find and describe three commonly used signals (e.g., SIGKILL, SIGTERM, SIGINT). What are their typical use cases? + + > **Answer**: Identify and explain three frequently used signals (such as SIGKILL, SIGTERM, and SIGINT). Which usage cases are normal for them? + +- What happens when a process receives SIGSTOP? Can it be caught or ignored like SIGINT? Why or why not? + + > **Answer**: A process instantly freezes (suspends) upon receiving SIGSTOP. Since SIGSTOP is meant to always return control to the user, it cannot be intercepted or disregarded like SIGINT. This is crucial for process management and debugging since you need a dependable method of stopping a process. With SIGCONT, the procedure can be continued at a later time. diff --git a/4-ShellP2/shell_roadmap.md b/4-ShellP2/shell_roadmap.md new file mode 100644 index 0000000..9af1434 --- /dev/null +++ b/4-ShellP2/shell_roadmap.md @@ -0,0 +1,13 @@ +## Proposed Shell Roadmap + +Week 5: Shell CLI Parser Due + +Week 6: Execute Basic Commands + +Week 7: Add support for pipes (extra-credit for file redirection) + +Week 8: Basic socket assignment + +Week 9: Remote Shell Extension + +Week 11: Add support for something like `nsenter` to enter a namespace \ No newline at end of file -- GitLab