#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include "dfs.h" #define clear() printf("\033[H\033[J") static char *prompt = NULL; static size_t commandRun = 0; union pipe { int fileDesc[2]; struct { int read; int write; }; }; 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 free(args); 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); free(args); 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]))); strcpy(changeDir, getenv("HOME")); strcat(changeDir, dir[1]+1); break; case '-': changeDir = realloc(changeDir, strlen(getenv("OLDPWD"))); strcpy(changeDir, getenv("OLDPWD")); break; default: 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); free(prompt); prompt = NULL; } } else { if (chdir(getenv("HOME")) != 0) { status = 1; printf("Bash: cd: error\n"); } else { setenv("PWD", getenv("HOME"), 1); setenv("OLDPWD", oldPWD, 1); free(prompt); prompt = NULL; } } free(changeDir); changeDir = NULL; free(dir); return status; } int builtinNMN(char **args) { free(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 size = 8; size_t pos = 0; char **args = malloc(size * sizeof(char*)); char *arg = NULL; char *lineTest = NULL; lineTest = strdup(line); if(line == NULL) { *args=NULL; return args; } arg = strtok(lineTest, " \t\r\n\a"); while (arg != NULL) { args[pos] = arg; pos++; if (pos >= size) { size += 1; args = realloc(args, size * sizeof(char*)); } arg = strtok(NULL, " \t\r\n\a"); } free(arg); free(lineTest); args[pos] = NULL; return args; } int execCommand(char *command) { char **commandARGS = splitCMD(command); for (size_t i = 0; i < (sizeof(builtinFunctions) / sizeof(char *)); i++) { if (strcmp(commandARGS[0], builtinFunctions[i]) == 0) { return (*builtinFunc[i])(commandARGS); } } 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; } char *getPrompt() { pid_t pid; union pipe input, output; FILE *outputFileD; size_t len = 0; int status = 0; 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", "\ ver=$(bash --version | head -n 1 | awk \'{print $4}\' | grep -o \".\\..\");\ check_ver=$(echo -e \"${ver}\n4.3\" | sort -V | head -n 1);\ if [[ \"${ver}\" == \"${check_ver}\" ]]; then\ echo \"[${USER}@${HOSTNAME} ${PWD##*/}]$ \";\ else\ echo \"${PS1@P}\";\ fi\ ", 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 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); }