diff --git a/Userspace/apps/sys/sh/Makefile b/Userspace/apps/sys/sh/Makefile new file mode 100644 index 00000000..2b439d37 --- /dev/null +++ b/Userspace/apps/sys/sh/Makefile @@ -0,0 +1,33 @@ +default: + $(error Do not run this Makefile directly!) + +S_SOURCES = $(shell find ./ -type f -name '*.S') +C_SOURCES = $(shell find ./ -type f -name '*.c') +CXX_SOURCES = $(shell find ./ -type f -name '*.cpp') + +OBJ = $(S_SOURCES:.S=.o) $(C_SOURCES:.c=.o) $(CXX_SOURCES:.cpp=.o) + +FILENAME = $(notdir $(shell pwd)) +WARNCFLAG = -Wall -Wextra + +build: $(FILENAME).elf + cp $(FILENAME).elf $(WORKSPACE_DIR)/out/bin/$(FILENAME) + +$(FILENAME).elf: $(OBJ) + $(info Linking $@) + $(CC) $(LDFLAGS) $(SYSROOT) $(OBJ) -o $@ + +%.o: %.c $(HEADERS) + $(info Compiling $<) + $(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@ + +%.o: %.cpp $(HEADERS) + $(info Compiling $<) + $(CXX) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fexceptions -c $< -o $@ -fno-rtti + +%.o: %.S + $(info Compiling $<) + $(AS) -o $@ $< + +clean: + rm -f $(OBJ) $(FILENAME).elf diff --git a/Userspace/apps/sys/sh/sh.c b/Userspace/apps/sys/sh/sh.c new file mode 100644 index 00000000..38d1ef42 --- /dev/null +++ b/Userspace/apps/sys/sh/sh.c @@ -0,0 +1,114 @@ +/* + This file is part of Fennix Userspace. + + Fennix Userspace is free software: you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation, either version 3 of + the License, or (at your option) any later version. + + Fennix Userspace is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Fennix Userspace. If not, see . +*/ +#include +#include +#include +#include +#include +#include + +#define MAX_INPUT_SIZE 1024 +#define MAX_ARG_SIZE 100 + +void print_prompt() +{ + printf("$ "); + fflush(stdout); +} + +void read_input(char *input) +{ + if (fgets(input, MAX_INPUT_SIZE, stdin) == NULL) + { + perror("fgets"); + exit(EXIT_FAILURE); + } + input[strcspn(input, "\n")] = '\0'; +} + +void parse_input(char *input, char **args) +{ + int i = 0; + args[i] = strtok(input, " "); + while (args[i] != NULL) + { + i++; + args[i] = strtok(NULL, " "); + } +} + +void execute_command(char **args) +{ + pid_t pid = fork(); + if (pid < 0) + { + perror("fork"); + exit(EXIT_FAILURE); + } + else if (pid == 0) + { + if (execvp(args[0], args) < 0) + { + perror("execvp"); + exit(EXIT_FAILURE); + } + } + else + { + int status; + waitpid(pid, &status, 0); + if (WIFEXITED(status)) + { + printf("Child exited with status %d\n", WEXITSTATUS(status)); + } + else if (WIFSIGNALED(status)) + { + printf("Child terminated by signal %d\n", WTERMSIG(status)); + } + } +} + +void handle_signal(int sig) +{ + if (sig == SIGINT) + { + printf("\nCaught signal %d (SIGINT). Type 'exit' to quit the shell.\n", sig); + print_prompt(); + fflush(stdout); + } +} + +int main() +{ + char input[MAX_INPUT_SIZE]; + char *args[MAX_ARG_SIZE]; + + signal(SIGINT, handle_signal); + + while (1) + { + print_prompt(); + read_input(input); + if (strcmp(input, "exit") == 0) + break; + parse_input(input, args); + if (args[0] != NULL) + execute_command(args); + } + + return 0; +}