#include #include #include #include #include #include #include #include "msh.h" #define clear() printf("\033[H\033[J") union pipe { int fileDesc[2]; struct { int read; int write; }; }; static char *builtinFunctions[] = { "exit", "author" }; int (*builtinFunc[]) (char *) = { &builtinExit, &builtinAuthor }; int builtinExit() { exit(EXIT_SUCCESS); } int builtinAuthor() { static const char* message = "Author: Spencer\n" "Description: A shell to promote math!\n" "Ask for the source code!\n" "\n"; printf("%s", message); return 0; } void failedTest() { static const char* message = "\n" "How can you expect to execute commands without knowing any math???\n" "\n"; printf("%s", message); return; } int runCommand(char *command) { int status = 0; pid_t pid; pid = fork(); if (pid == 0) { // Child process if(execlp("bash", "bash", "-c", command, NULL) == -1) { exit(EXIT_FAILURE); } exit(EXIT_SUCCESS); } else if (pid < 0) { printf("Error forking...\n"); status = 1; } else { // Parent process do { waitpid(pid, &status, WUNTRACED); } while(!WIFEXITED(status) && !WIFSIGNALED(status)); } return status; } int execCommand(char *command) { for (size_t i = 0; i < (sizeof(builtinFunctions) / sizeof(char *)); i++) { if (strcmp(command, builtinFunctions[i]) == 0) { return (*builtinFunc[i])(command); } } return runCommand(command); } void initShell() { FILE *fd; clear(); using_history(); runCommand("uname -a"); fd = fopen("/etc/motd", "r"); if (fd != NULL) { char c; c = fgetc(fd); printf("\n"); while (c != EOF) { printf("%c", c); c = fgetc(fd); } fclose(fd); } else { printf("MOTD is empty\n"); } return; } char *getPrompt() { pid_t pid; union pipe input, output; FILE *outputFileD; size_t len = 0; int status; static char *prompt = NULL; static size_t promptCap = 0; pipe(input.fileDesc); pipe(output.fileDesc); pid = fork(); if (pid == 0) { // Child process close(input.write); close(output.read); dup2(input.read, STDIN_FILENO); dup2(output.write, STDOUT_FILENO); close(STDERR_FILENO); // Do not print errors to the screen execlp("bash", "bash", "-i", "-c", "echo \"${PS1@P}\" || echo \">>\"", NULL); } else if (pid < 0) { // Error forking printf("Error forking\n"); } else { // Parent process close(input.read); close(output.write); outputFileD = fdopen(output.read, "r"); len = getline(&prompt, &promptCap, outputFileD); if (prompt[len - 1] == '\n') { prompt[len - 1] = '\0'; } fclose(outputFileD); do { waitpid(pid, &status, WUNTRACED); } while(!WIFEXITED(status) && !WIFSIGNALED(status)); } return prompt; } int randomNum(int limit) { int num = 0; if (limit != 0) { num = rand()%limit +1; } else { num = rand(); } return num; } int mathTest() { int status = 0; int numAnswer = 0; int num1 = randomNum(10); int num2 = randomNum(10); printf("%d + %d = ", num1, num2); scanf("%d", &numAnswer); #ifdef RELEASEBUILD printf("Calculating"); for (int i = 0; i < 3; i++){ printf("."); fflush(stdout); sleep(2); } printf("\n"); #endif if ((num1 + num2) != numAnswer) { // If wrong answer status = 1; } return status; } void startShell() { char *line = NULL; int status = 0; while ((line = readline(getPrompt())) != NULL) { if (strlen(line) != 0) { // Checking if prompt returns empty status = mathTest(); if (status == 0) { // Passed math test add_history(line); execCommand(line); } else { // Failed math test failedTest(); } } free(line); } } void handleBreak(int sig){ signal(sig, handleBreak); fflush(stdout); printf("\n"); startShell(); exit(EXIT_SUCCESS); } int main() { initShell(); signal(SIGINT, handleBreak); startShell(); exit(EXIT_SUCCESS); }