#include #include #include #include #include #include #include #include "string_helpers.h" #include "string_helpers.h" #include "string_helpers.h" #include "string_helpers.h" #include "string_helpers.h" #include "string_helpers.h" #include "string_helpers.h" char debug = 0; void handle_ctrlc(int signal){ write(1, "^C", 2); fsync(1); } int main(){ size_t linebuffer_limit = 1024; char *linebuffer = malloc(linebuffer_limit); char working_directory[512]; getcwd(working_directory, 512); ssize_t readlen; struct sigaction ctrlc_action; char *user_home = "/home/seth/"; // TODO: Set this automatically ctrlc_action.sa_handler = handle_ctrlc; sigaction(SIGINT, &ctrlc_action, 0); while(1){ write(1, working_directory, strlen(working_directory)); write(1, "$: ", 3); fsync(1); readlen = read(0, linebuffer, linebuffer_limit); if(readlen == -1){ write(1, "\n", 1); continue; } if(readlen == 0) break; linebuffer[readlen-1] = 0; if(debug) printf("You entered: \"%s\" (%ld bytes)\n", linebuffer, readlen); /* Shell expansions */ for(size_t i = 0; linebuffer[i]; i++){ if(linebuffer[i] == '~'){ int length = strlen(user_home); move_right(linebuffer + i, length - 2); strncpy(linebuffer + i, user_home, length - 1); } } /* Shell Builtins */ if(!strncmp(linebuffer, "cd ", 3)){ chdir(linebuffer + 3); getcwd(working_directory, 512); continue; } if(!strncmp(linebuffer, "debug", 5)){ debug = !debug; continue; } if(!strncmp(linebuffer, "exit", 4)){ break; } /* Most shells have a few more builtins than that */ /* Maybe the user specified a program */ handle_pipes(linebuffer, 0); /* What if there's a pipe? */ char *secondcmd; if(secondcmd = strstr(linebuffer, "|")){ *secondcmd = 0; // This'll overwrite the | with a terminator char *end_of_first = secondcmd - 1; while(*end_of_first == ' '){ *end_of_first = 0; --end_of_first; } while(*++secondcmd == ' ') *secondcmd = ' '; printf("First command: \"%s\"\n", linebuffer); printf("Second command: \"%s\"\n", secondcmd); int pipefd[2]; pipe(pipefd); // Run first command pid_t pid = fork(); if(!pid) { // Set up and exec the first command, the one in linebuffer size_t length; char **argv = split(linebuffer, &length); dup2(pipefd[1], 1); close(pipefd[0]); execvp(linebuffer, argv); free(argv); perror("exec"); return 1; } // Run second command handle_pipes pid_t pid2 = fork(); if(!pid2){ // Set up and exec the second command, the one in secondcmd size_t length; char **argv = split(secondcmd, &length); dup2(pipefd[0], 0); close(pipefd[1]); execvp(secondcmd, argv); free(argv); perror("exec"); return 1; } close(pipefd[0]); close(pipefd[1]); wait(0); wait(0); continue; } /* Should this code be part of the pipe handling above? */ pid_t pid = fork(); if(!pid){ // We're the child size_t length; char **argv = split(linebuffer, &length); if(debug) { printf("About to run: %s\n", linebuffer); for(int i = 0; argv[i]; i++) printf("argv[%d] = %s\n", i, argv[i]); } execvp(linebuffer, argv); free(argv); /* Child is not coming back from this unless execvp fails (nonexistant file specified, etc) */ perror("exec"); return 1; } else { pid_t finished_child = wait(0); if(debug) printf("Child %d finished\n", finished_child); } } write(1, "\n", 1); free(linebuffer); return 0; } void handle_pipes(char *linebuffer, int input){ char *secondcmd; if(secondcmd = strstr(linebuffer, "|")){ *secondcmd = 0; // This'll overwrite the | with a terminator char *end_of_first = secondcmd - 1; while(*end_of_first == ' '){ *end_of_first = 0; --end_of_first; } while(*++secondcmd == ' ') *secondcmd = ' '; printf("First command: \"%s\"\n", linebuffer); printf("Second command: \"%s\"\n", secondcmd); int pipefd[2]; pipe(pipefd); // Run first command pid_t pid = fork(); if(!pid) { // Set up and exec the first command, the one in linebuffer size_t length; char **argv = split(linebuffer, &length); dup2(pipefd[1], 1); close(pipefd[0]); execvp(linebuffer, argv); free(argv); perror("exec"); return; // Will probably make it go all goofy } // Run second command close(pipefd[1]); handle_pipes(secondcmd, pipefd[0]); wait(0); return; } pid_t pid = fork(); if(!pid) { // Set up and exec the first command, the one in linebuffer size_t length; char **argv = split(linebuffer, &length); dup2(input, 1); execvp(linebuffer, argv); free(argv); perror("exec"); return 1; } wait(0); }