#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include "dfs.h" #include "util.h" #define clear() printf("\033[H\033[J") char *prompt = NULL; static size_t commandRun = 0; static char *builtinFunctions[] = { "exit", "author", "cd", "nomorenumbers" }; int (*builtinFunc[]) (char **) = { &builtinExit, &builtinAuthor, &builtinCD, &builtinNMN }; int builtinExit(char **args) { #if RL_READLINE_VERSION < 0x0602 rl_clear_history(); #else clear_history(); #endif exit(EXIT_SUCCESS); } int builtinAuthor(char **args) { static const char* message = "Author: Spencer\n" "Description: \n" "Ask for the source code!\n" "\n"; printf("%s", message); return 0; } int builtinCD(char **dir) { int status = 0; char *oldPWD = getenv("PWD"); char *changeDir = malloc(sizeof(char *)); if (dir[1] != NULL) { char c = *dir[1]; switch (c) { case '~': changeDir = realloc(changeDir, strlen(getenv("HOME")) + strlen(dir[1]) + 1); strcpy(changeDir, getenv("HOME")); strcat(changeDir, dir[1]+1); break; case '-': // Break early when OLDPWD is not set if (getenv("OLDPWD") == NULL) { free(changeDir); printf("bash: cd: OLDPWD not set\n"); return 1; } changeDir = realloc(changeDir, strlen(getenv("OLDPWD")) + 1); strcpy(changeDir, getenv("OLDPWD")); break; default: changeDir = realloc(changeDir, strlen(dir[1]) + 1); strcpy(changeDir, dir[1]); break; } if (chdir(changeDir) != 0) { status = 1; printf("bash: cd: error\n"); } else { setenv("PWD", dir[1], 1); setenv("OLDPWD", oldPWD, 1); } } else { if (chdir(getenv("HOME")) != 0) { status = 1; printf("Bash: cd: error\n"); } else { setenv("PWD", getenv("HOME"), 1); setenv("OLDPWD", oldPWD, 1); } } free(changeDir); changeDir = NULL; return status; } int builtinNMN(char **args) { return 0; } void failedTest() { static const char* message = "\n" "We must change our default passwords; however, it seems you have typed it in wrong!!\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; } char **splitCMD(const char *line, size_t *length) { size_t size = 8; size_t pos = 0; char **args = malloc(size * sizeof(char*)); char *arg = NULL; if(line == NULL) { *args=NULL; return args; } char *lineTest = strdup(line); arg = strtok(lineTest, " \t\r\n\a"); while (arg != NULL) { if (pos >= size) { size *= 2; args = realloc(args, size * sizeof(char*)); } *length += 1; args[pos] = strdup(arg); pos++; arg = strtok(NULL, " \t\r\n\a"); } free(lineTest); return args; } int execCommand(char *command) { size_t commandLen = 0; char **commandARGS = splitCMD(command, &commandLen); for (size_t i = 0; i < (sizeof(builtinFunctions) / sizeof(char *)); i++) { if (strcmp(commandARGS[0], builtinFunctions[i]) == 0) { (*builtinFunc[i])(commandARGS); for (size_t i = 0; i < commandLen; i++) { free(commandARGS[i]); } free(commandARGS); return 0; } } for (size_t i = 0; i < commandLen; i++) { free(commandARGS[i]); } free(commandARGS); return runCommand(command); } void initShell() { FILE *fd; clear(); using_history(); // Setting random time seed srand(time(0)); fflush(stdout); 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); } printf("\n"); return; } int randomNum(int limit) { int num = 0; if (limit != 0) { num = rand()%limit + 1; } else { num = rand(); } return num; } int shellTest() { int status = 1; char *line = NULL; line = readline("Default password? (abc123): "); if (line != NULL) { if(!strcmp(line, "abc123")) { status = 0; } } free(line); return status; } void postCommand() { commandRun++; return; } void startShell() { char *line = NULL; int status = 0; while ((line = readline(getPrompt())) != NULL) { if (strlen(line) != 0) { // Checking if prompt returns empty status = shellTest(); if (status == 0) { // Passed test add_history(line); execCommand(line); postCommand(); } else { // Failed test failedTest(); } } free(line); } free(prompt); prompt = NULL; } void handleBreak(){ signal(SIGINT, handleBreak); printf("\n"); rl_on_new_line(); rl_replace_line("", 0); rl_redisplay(); } int main() { initShell(); signal(SIGINT, handleBreak); startShell(); #if RL_READLINE_VERSION < 0x0602 rl_clear_history(); #else clear_history(); #endif exit(EXIT_SUCCESS); }