From 39826cc89f3f54514461fecde90e04d3685c1cf0 Mon Sep 17 00:00:00 2001 From: Bloopyloop <32317506+Bloopyloop@users.noreply.github.com> Date: Sun, 23 Sep 2018 21:52:24 -0400 Subject: [PATCH 1/8] Added iffy io command, tuned piping error handling --- shell.c | 461 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 461 insertions(+) create mode 100644 shell.c diff --git a/shell.c b/shell.c new file mode 100644 index 0000000..109f0f4 --- /dev/null +++ b/shell.c @@ -0,0 +1,461 @@ +/* + +COP4610 + +Project 1 - Implementing a Shell + +Group Members: +John Sanchez +Emanuel Gonzalez +Redden Money + +___________________________________ + +Requirements we still need: + +• "io" built-in +• Refined path resolution +• Piping (Refining the functionality) +• Background Processing + +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define TOK_DELIMS " \t\r\n\a" +#define TOK_BUFF 64 + +/* + +PROMPT + +*/ + +static int io_flag = 0; + +void fullPrompt() { + long num; + char *b; + char *path; + path = getcwd(b, (size_t)num); + if(path == NULL) + printf("%s@%s :: %s -> ", getenv("USER"), getenv("MACHINE"), getenv("PWD")); + else + printf("%s@%s :: %s -> ", getenv("USER"), getenv("MACHINE"), path); +} + +static const char prompt[] = ""; + +struct timespec start, stop; + +static int args_size = 0; + +int shell_cd(char **args); +int shell_exit(char **args); +int shell_pwd(char **args); +int shell_ls(char **args); +//int shell_io(char **args); + +char *builtin[] = { + "cd", + "exit", + "pwd", + "ls" + //"io" +}; + +int num_builtins() { + return sizeof(builtin) / sizeof(char *); +} + +int (*builtin_func[]) (char **) = { + &shell_cd, + &shell_exit, + &shell_pwd, + &shell_ls + //&shell_io +}; +/* + +Environment Variable Handler: + +Takes in Environment Variable argument +and returns variable value + +*/ + +char* env_var_switch(char* var){ + char *a; + + if (strcmp(var,"$PATH") == 0){ + a = getenv("PATH"); + return(a); // Get Path + } else if (strcmp(var,"$HOME") == 0 || strcmp(var,"~") == 0){ + a = getenv("HOME"); + return(a); // Get Home Path + } + else if (strcmp(var,"$USER") == 0){ + a = getenv("USER"); + return(a); // Get User +} else if (strcmp(var,"$SHELL") == 0){ + a = getenv("SHELL"); + return(a); // Get Shell +} else if (strcmp(var,"$PWD") == 0){ + a = getenv("PWD"); + return(a); // Get Current Path +} + +return var; + +} + +int shell_launch(char **args) { + pid_t p, wp; + FILE* io_stat; + char fbuff[300]; + int st, fd0, fd1, i, fd[2]; + int bg_flag = 0; + char** subset; + char buf; + char caten[30]; + int buffer_status; + p = fork(); + //Child + if(p == 0) { + for(i = 0; args[i] != '\0'; i++) { + //Input + if(strcmp(args[i],"<") == 0) { + if(args[i+1] == NULL) { + fprintf(stderr, "Missing name for redirect\n"); + exit(0); + } + else { + if((fd0 = open(args[i+1], O_RDONLY)) < 0) { + perror("cant open file"); + exit(0); + } + } + dup2(fd0, 0); + close(fd0); + } + //Output + if(strcmp(args[i],">") == 0) { + if(args[i+1] == NULL) { + fprintf(stderr, "Missing name for redirect\n"); + exit(0); + } + else { + if((fd1 = open(args[i+1], O_WRONLY | O_CREAT, 0644)) < 0) { + perror("cant open file\n"); + exit(0); + } + } + dup2(fd1, STDOUT_FILENO); + close(fd1); + } + //Pipe + if(strcmp(args[i],"|") == 0) { + if(args[i+1] == NULL || i == 0) { + fprintf(stderr, "Invalid null command\n"); + exit(0); + } + pipe(fd); + if((p = fork()) == 0) { + close(1); + dup2(fd[1], 1); + close(fd[0]); + close(fd[1]); + execvp(args[i-1], args); + } + else { + close(0); + dup2(fd[0], 0); + close(fd[0]); + close(fd[1]); + execvp(args[i+1], args); + } + } + if((strcmp(args[i],"io") == 0) && (i == 0)) { + io_flag = 1; + } + if(strcmp(args[i], "&") == 0) { + if(i != 0 && i == sizeof(args-1)) { + bg_flag = 1; + break; + } + } + } + if(io_flag == 0) { + if(execvp(args[0], args) == -1) { + perror("shell"); + } + exit(EXIT_FAILURE); + } + else { + subset = &args[1]; + if(execvp(args[1], subset) == -1) { + perror("shell"); + } + exit(EXIT_FAILURE); + } + } + //Error + else if(p < 0) { + perror("shell"); + } + //Parent + else { + //if(!bg_flag) { + bg_flag = 0; + for(i = 0; args[i] != '\0'; i++) { + //Check if this is supposed to execute in the BG + if(strcmp(args[i], "&") == 0) { + if(i != 0 && i ==(args_size - 1)) { + bg_flag = 1; + break; + } + else if (i != 0) { + bg_flag = -1; + break; + } + } + } + //Foreground Execution + if(bg_flag == 0) { + do { + wp = waitpid(p, &st, WUNTRACED); + } while(!WIFEXITED(st) && WIFSIGNALED(st)); + if(io_flag == 1) { + sprintf(caten, "/proc/%d/io", (int)wp); + printf(caten); printf("\n"); + io_stat = fopen(caten, "r"); + int x = 0; + char c; + if(io_stat == NULL) { + perror("Failed: "); + } + else { + while((c=fgetc(io_stat)) != EOF) { + fbuff[x++] = c; + } + fbuff[x] = '\0'; + printf(fbuff); + } + } + } + //Background Execution + else if(bg_flag == 1) { + wp = waitpid(-1,&st, WNOHANG); + printf("Background pid: %d\n", p); + if(wp > 0) { + printf("Completed Background pid: %d\n", wp); + } + } + else if(bg_flag == -1) + printf("Invalid Command\n"); + } + /*wp = waitpid(-1, &st, WNOHANG); + while (wp > 0) { + printf("completed bg pid: %d\n", wp); + }*/ + return 1; +} + +char * tok_prep(char * line) { + int pos = 0; + while(pos != strlen(line) - 1) { + if(line[pos] == ' ' || line[pos] == '\t') { + line[pos] = '\a'; + } + else if(line[pos] == '\'') { + line[pos] = '\a'; + while(line[pos] != '\'') { + pos++; + } + line[pos] = '\a'; + } + pos++; + } + return line; +} + +char **shell_split(char *line) { + if(line[0] == NULL) { + line[0] = ""; + } + char * _line = tok_prep(line); + int buff = TOK_BUFF; + int position = 0; + char **tokens = malloc(buff * sizeof(char*)); + char *token; + if(!tokens) { + fprintf(stderr, "shell: alloc error\n"); + exit(EXIT_FAILURE); + } + token = strtok(_line, "\a"); + while(token != NULL) { + char * temp; + temp = token; + char * temp2 = env_var_switch(temp); + tokens[position] = temp2; + position++; + if(position >= buff) { + buff += TOK_BUFF; + tokens = realloc(tokens, buff * sizeof(char*)); + if(!tokens) { + fprintf(stderr, "shell: alloc error\n"); + exit(EXIT_FAILURE); + } + } + token = strtok(NULL, "\a"); + } + tokens[position] = NULL; + args_size = position; + return tokens; +} + +/* + +MAIN LOOP + +*/ + +void shell_loop() { + char * line; + char ** args; + int status; + clock_gettime(CLOCK_REALTIME, &start); + do { + fullPrompt(); + line = readline(prompt); + args = shell_split(line); + int i = 0; + status = shell_execute(args); + + free(line); + free(args); + } while(status); +} + +/* + +BUILT IN: CD + +*/ + +int shell_cd(char **args) { + if(args[1] == NULL) { + chdir(getenv("HOME")); + } + else { + if(args[2] != NULL) { + fprintf(stderr, "cd: Too many arguments\n"); + } + else if(chdir(args[1]) != 0) { + perror("cd"); + } + } + return 1; +} + +/* + +BUILT IN: EXIT + +*/ + +int shell_exit(char **args) { + clock_gettime(CLOCK_REALTIME, &stop); + double elapsed2 = (stop.tv_sec - start.tv_sec); + printf("Exiting...\n\tSession time: %ds \n", (int)elapsed2); + if(stop.tv_sec != 0) + //return 0; + exit(EXIT_SUCCESS); +} + +/* + +BUILT IN: PWD + +*/ + +int shell_pwd(char **args) { + char pwd[1024]; + getcwd(pwd, sizeof(pwd)); + printf("%s\n", pwd); + return 1; +} + +/* + +BUILT IN: LS + +*/ + +int shell_ls(char **args) { + DIR *d; + struct dirent *dir; + d = opendir("."); + if(args[1] == NULL) { + if(d) { + while((dir = readdir(d))) { + printf("%s ", dir->d_name); + } + printf("\n"); + closedir(d); + } + else + perror("Could not open directory"); + } + else { + + d = opendir(args[1]); + if(d) { + while((dir = readdir(d))) { + printf("%s ", dir->d_name); + } + printf("\n"); + closedir(d); + } + else + perror("Could not open directory"); + } + return 1; +} + +int shell_execute(char **args) { + int i; + if(args[0] == NULL) + return 1; + for(i = 0; i < num_builtins(); i++) { + if(strcmp(args[0], builtin[i]) == 0) { + return (*builtin_func[i])(args); + } + } + return shell_launch(args); +} + +/* + +MAIN + +*/ + +int main (int argc, char ** argv) { + + + shell_loop(); // Main Loop + printf("poot"); + return EXIT_SUCCESS; // Exit +} From 29b502a3ee0c32eb9b3bbdd88f2e845ceeeb28a0 Mon Sep 17 00:00:00 2001 From: Bloopyloop <32317506+Bloopyloop@users.noreply.github.com> Date: Sun, 23 Sep 2018 21:54:56 -0400 Subject: [PATCH 2/8] Update makefile --- makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile b/makefile index d9e4f54..22c5266 100644 --- a/makefile +++ b/makefile @@ -1,6 +1,6 @@ cssh: cssh.c - gcc -lreadline cssh.c + gcc -lreadline shell.c clean: rm a.out From 72b6ed040b9cad0fbced702ab2e7500b37d08a64 Mon Sep 17 00:00:00 2001 From: Bloopyloop <32317506+Bloopyloop@users.noreply.github.com> Date: Sun, 23 Sep 2018 22:13:37 -0400 Subject: [PATCH 3/8] Update README.md --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e945ed6..58b8492 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,10 @@ The members of this project are: 3) Redden Money proj_1_gonzalez_sanchez_money.tar contents: -cssh.c // main implementation -makefile + README + shell.c // main implementation + makefile + Completed using: linprog @@ -21,6 +23,11 @@ To Clean: $> make clean Known Bugs & Unfinished Portions: + Piping works, but only one can be used at a time. + Background processing is somewhat unfinished. + "io" command is incomplete. + Path resolution is rudamentary. + ->Ex: "cd ~" works, "cd ~/DIRNAME" gives an error. Special Considerations: From 08ea070aa6bc9cf8b4822e208968c74522f64277 Mon Sep 17 00:00:00 2001 From: Bloopyloop <32317506+Bloopyloop@users.noreply.github.com> Date: Sun, 23 Sep 2018 23:02:01 -0400 Subject: [PATCH 4/8] Update README.md --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 58b8492..6806bd6 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ The members of this project are: 2) John Sanchez 3) Redden Money -proj_1_gonzalez_sanchez_money.tar contents: +project1_gonzalez_sanchez_money.tar contents: README shell.c // main implementation makefile @@ -25,13 +25,15 @@ $> make clean Known Bugs & Unfinished Portions: Piping works, but only one can be used at a time. Background processing is somewhat unfinished. - "io" command is incomplete. + "io" command is unfinished. Path resolution is rudamentary. ->Ex: "cd ~" works, "cd ~/DIRNAME" gives an error. + There needs to be whitespace between the redirection/pipe and the command. Special Considerations: - - + In the "exit" built-in, clock_gettime() was used instead of gettimeofday(), which is not always available to certain (notably older) + Linux versions, along with it being absent on Mac... + ============================== ============================== Report From 2a8df396b2c6ffaec5973d3feb47412606323bea Mon Sep 17 00:00:00 2001 From: Bloopyloop <32317506+Bloopyloop@users.noreply.github.com> Date: Sun, 23 Sep 2018 23:43:30 -0400 Subject: [PATCH 5/8] Update README.md --- README.md | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 6806bd6..20a3435 100644 --- a/README.md +++ b/README.md @@ -23,17 +23,23 @@ To Clean: $> make clean Known Bugs & Unfinished Portions: - Piping works, but only one can be used at a time. - Background processing is somewhat unfinished. - "io" command is unfinished. - Path resolution is rudamentary. + • Piping works, but only one can be used at a time. + -> Results from lack of implementation for when an additional "pipe-in" target is supplied. + • Background processing is somewhat unfinished. (Zombie processes might occur) + • "io" command is unfinished. + ->Attempted to complete the built-in using flags and opening the proc/pid/io file. + ->Attempt resulted in the fact that variables are not universal between processes, as well as possible path resolution issues. + • Path resolution is simple. ->Ex: "cd ~" works, "cd ~/DIRNAME" gives an error. - There needs to be whitespace between the redirection/pipe and the command. + ->Resulting from the lack of splitting the special characters and environment variables from the rest of the line. + • There needs to be whitespace between the redirection/pipe and the command. + • "echo" built-in does not signal an error when there is a non-existent environment variable. + • "$SHELL" environment variable p Special Considerations: - In the "exit" built-in, clock_gettime() was used instead of gettimeofday(), which is not always available to certain (notably older) + • In the "exit" built-in, clock_gettime() was used instead of gettimeofday(), which is not always available to certain (notably older) Linux versions, along with it being absent on Mac... - + • execvp() ============================== ============================== Report From 6570ec1368af879b6ad91d650a6321c324083b30 Mon Sep 17 00:00:00 2001 From: Bloopyloop <32317506+Bloopyloop@users.noreply.github.com> Date: Sun, 23 Sep 2018 23:43:48 -0400 Subject: [PATCH 6/8] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 20a3435..edd2000 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Known Bugs & Unfinished Portions: Special Considerations: • In the "exit" built-in, clock_gettime() was used instead of gettimeofday(), which is not always available to certain (notably older) Linux versions, along with it being absent on Mac... - • execvp() + ============================== ============================== Report From 175d30517ce1a102372ce2d30c62b6f146b752d4 Mon Sep 17 00:00:00 2001 From: Bloopyloop <32317506+Bloopyloop@users.noreply.github.com> Date: Sun, 23 Sep 2018 23:51:24 -0400 Subject: [PATCH 7/8] Update shell.c --- shell.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/shell.c b/shell.c index 109f0f4..66abf18 100644 --- a/shell.c +++ b/shell.c @@ -384,6 +384,15 @@ int shell_exit(char **args) { exit(EXIT_SUCCESS); } +int shell_echo(char **args) { + int e = 0; + while(args[e] != NULL) { + printf(args[e]); + e++; + } + return 1; +} + /* BUILT IN: PWD From 7f068ca5e5e1a457f0090e325f46afa9ec583a66 Mon Sep 17 00:00:00 2001 From: Bloopyloop <32317506+Bloopyloop@users.noreply.github.com> Date: Sun, 23 Sep 2018 23:55:18 -0400 Subject: [PATCH 8/8] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index edd2000..a1e84f8 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ Known Bugs & Unfinished Portions: ->Resulting from the lack of splitting the special characters and environment variables from the rest of the line. • There needs to be whitespace between the redirection/pipe and the command. • "echo" built-in does not signal an error when there is a non-existent environment variable. + ->"echo" built-in also does not account for single or double quotes. • "$SHELL" environment variable p Special Considerations: