hw05

Run Settings
LanguageC
Language Version
Run Command
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <sys/wait.h> #include <sys/types.h> #define PATH_MAX 4096 #include "else.h" //reading the user input. char *read_line(){ char *line = NULL; ssize_t bufsize = 0; getline(&line, &bufsize, stdin); return line; } //parsing the user input. char **parse_line(char *line){ int bufsize = 64, position = 0; char **tokens = malloc(bufsize * sizeof(char*)); char *token; token = strtok(line, " \t\r\n\a"); while (token != NULL) { tokens[position] = token; position++; if (position >= bufsize) { bufsize += 64; tokens = realloc(tokens, bufsize * sizeof(char*)); } token = strtok(NULL, " \t\r\n\a"); } tokens[position] = NULL; return tokens; } //This function is responsible for executing commands. int execute_line(char **args){ int status; pid_t pid; pid = fork(); if (pid == 0) { if (execvp(args[0], args) == -1) { perror("go/sh"); } exit(EXIT_FAILURE); } else if (pid < 0) { perror("go/sh"); } else { do { waitpid(pid, &status, WUNTRACED); } while (!WIFEXITED(status) && !WIFSIGNALED(status)); } return 1; } //This function is responsible for changing the directory. int cd(char **args){ if (args[1] == NULL) { fprintf(stderr, "go/sh: expected argument to \"cd\"\n"); } else { if (chdir(args[1]) != 0) { perror("go/sh"); } } return 1; } //This function is responsible for displaying help information. int help(char **args){ printf("go/sh - Simple UNIX Shell\n\n"); printf("The following are built-in commands supported by go/sh\n"); printf("cd\t\tChange the working directory\n"); printf("help\t\tDisplay this help information\n"); printf("exit\t\tExit go/sh\n"); return 1; } //This function is responsible for exiting go/sh. int go_sh_exit(char **args){ return 0; } //This function is responsible for dispatching the commands. int dispatch_command(char **args){ char *builtin_str[] = { "cd", "help", "exit" }; int (*builtin_func[]) (char **) = { &cd, &help, &go_sh_exit }; int i; if (args[0] == NULL) { return 1; } for (i = 0; i < 3; i++) { if (strcmp(args[0], builtin_str[i]) == 0) { return (*builtin_func[i])(args); } } return execute_line(args); } void *getCurrentDir(void){ char *currWorkDir, *token; char buffer[PATH_MAX + 1]; char *directory; size_t length; currWorkDir = getcwd(buffer, PATH_MAX + 1 ); token = strrchr(currWorkDir, '/'); if( currWorkDir == NULL ){ printf("Error"); /* You decide here */ exit(1); } if (token == NULL) { printf("Error"); /* You decide here */ exit(1); } length = strlen(token); directory = malloc(length); memcpy(directory, token+1, length); return directory; } void error(const char *msg) { perror(msg); exit(EXIT_FAILURE); } void cisshPipe(char **command1, char **command2) { int fd[2]; pid_t childPid; if (pipe(fd) != 0) error("failed to create pipe"); if ((childPid = fork()) == -1) error("failed to fork"); if (childPid == 0) { dup2(fd[1], 1); close(fd[0]); close(fd[1]); execvp(command1[0], command1); error("failed to exec command 1"); } else { dup2(fd[0], 0); close(fd[0]); close(fd[1]); execvp(command2[0], command2); error("failed to exec command 2"); } }
#ifndef ELSE_H #define ELSE_H #include "else.h" char *read_line(); char **parse_line(char *line); int execute_line(char **args); int cd(char **args); int help(char **args); int go_sh_exit(char **args); int dispatch_command(char **args); void *getCurrentDir(void); void error(const char *msg); void cisshPipe(char **command1, char **command2); #endif
#include <errno.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> #include <fcntl.h> #define MAX_INPUT_SIZE 1024 #define MAX_TOKEN_SIZE 64 #define MAX_NUM_TOKENS 64 #define TOKEN_CNT 64 #include "else.h" typedef enum {false, true} bool; char **tokenize(char *line_p) { char **tokens = (char **)malloc(MAX_NUM_TOKENS * sizeof(char *)); char *now_token = (char *)malloc(MAX_TOKEN_SIZE * sizeof(char)); int token_idx = 0; int char_idx = 0; for (int i =0; i < strlen(line_p); i++) { char ch = line_p[i]; if (ch == ' ' || ch == '\n' || ch == '\t' || ch == '\0') { if (char_idx != 0) { now_token[char_idx] = '\0'; tokens[token_idx] = (char*)malloc(MAX_TOKEN_SIZE*sizeof(char)); if (!strcmp("pps", now_token) || !strcmp("ttop", now_token)) { strcpy(tokens[token_idx], "./"); strcat(tokens[token_idx++], now_token); } else { strcpy(tokens[token_idx++], now_token); } char_idx = 0; } } else { now_token[char_idx++] = ch; } } free(now_token); tokens[token_idx] = NULL; return tokens; } //pipe void do_pipe(char **tokens, int pipe_idx[TOKEN_CNT], int pipe_cnt) { int pipes[TOKEN_CNT][2] = {0, }; // pipes int pid; int status; /***** first command *****/ pipe(pipes[0]); // pipe if ((pid = fork()) < 0) { fprintf(stderr, "fork() error\n"); exit(1); } else if (pid == 0) { close(STDOUT_FILENO); // stdout close dup2(pipes[0][1], STDOUT_FILENO); // cp pipe[0] to stdout close(pipes[0][1]); // pipe close execvp(tokens[pipe_idx[0]], &tokens[pipe_idx[0]]); // exec fprintf(stderr, "execvp() error\n"); } close(pipes[0][1]); // pipe close wait(&status); // wit for exec term if (WIFSIGNALED(status) || WIFSTOPPED(status)) { exit(1); } /***** execute commands except last command *****/ for (int i = 0; i < pipe_cnt - 1; i++) { pipe(pipes[i+1]); // pipe if ((pid = fork()) < 0) { fprintf(stderr, "fork() error\n"); exit(1); } else if (pid == 0) { close(STDIN_FILENO); // stdin close close(STDOUT_FILENO); // stdout close dup2(pipes[i][0], STDIN_FILENO); // cp to pipe stdin dup2(pipes[i+1][1], STDOUT_FILENO); // cp to pipe stdout close(pipes[i][0]); // pipe close close(pipes[i+1][1]); // pipe close execvp(tokens[pipe_idx[i+1]], &tokens[pipe_idx[i+1]]); // exec fprintf(stderr, "execvp() error\n"); } close(pipes[i+1][1]); // pipe close wait(&status); // wait exec terminate if (WIFSIGNALED(status) || WIFSTOPPED(status)) exit(1); } /***** excute last command *****/ if ((pid = fork()) < 0) { fprintf(stderr, "fork() error\n"); exit(1); } else if (pid == 0) { close(STDIN_FILENO); // stdin close dup2(pipes[pipe_cnt-1][0], STDIN_FILENO); // cp to pipe stdin close(pipes[pipe_cnt-1][0]); // pipe close close(pipes[pipe_cnt-1][1]); // pipe close execvp(tokens[pipe_idx[pipe_cnt]], &tokens[pipe_idx[pipe_cnt]]); // exec } wait(&status); // wait exec terminate if (WIFSIGNALED(status) || WIFSTOPPED(status)) { exit(1); } return; } // function for exec command void run_commands(char **tokens) { bool has_pipe = false; int pipe_cnt = 0; int start_idx = 0; int len = 0; int pipe_idx[TOKEN_CNT] = {0, }; for (int i = 0; tokens[i] != NULL; i++, len++) { // change token NULL when command exist if (!strcmp(tokens[i], "|")) { tokens[i] = NULL; pipe_idx[++pipe_cnt] = i+1; has_pipe = true; } else if (!strcmp(tokens[i], "<")) { int fd = open(tokens[i+1], O_RDONLY); if (fd < 0) { fprintf(stderr, "Failed to open file '%s'\n", tokens[i+1]); exit(1); } dup2(fd, STDIN_FILENO); close(fd); tokens[i] = NULL; i++; } else if (!strcmp(tokens[i], ">")) { int fd = open(tokens[i+1], O_WRONLY | O_CREAT | O_TRUNC, 0644); if (fd < 0) { fprintf(stderr, "Failed to open file '%s'\n", tokens[i+1]); exit(1); } dup2(fd, STDOUT_FILENO); close(fd); tokens[i] = NULL; i++; } } if (has_pipe) { do_pipe(tokens, pipe_idx, pipe_cnt); } else { // no pipe if (execvp(tokens[0], tokens) < 0) { if (errno == 2) { fprintf(stderr, "%s: command not found\n", tokens[0]); exit(1); } else { fprintf(stderr, "execvp error! errno: %d\n", errno); exit(1); } } int status; wait(&status); if (WIFSIGNALED(status) || WIFSTOPPED(status)) { exit(1); } } exit(0); } int main(int argc, char* argv[]) { char *line; char **args; int status; char *ls[] = { "ls", 0 }; char *sort[] = { "sort", "-r", 0 }; char line_p[MAX_INPUT_SIZE]; char **tokens; int i; FILE* fp; if (argc == 2) { // batch mode if ((access(argv[1], F_OK)) < 0) { fprintf(stderr, "File doesn't exists.\n"); return -1; } if ((fp = fopen(argv[1],"r")) < 0) { fprintf(stderr, "fopen error for %s\n", argv[1]); return -1; } } while (1) { // infinite loop /* input */ bzero(line_p, sizeof(line_p)); if (argc == 2) { // batch mode if (fgets(line_p, sizeof(line_p), fp) == NULL) { // read all file break; } line_p[strlen(line_p) - 1] = '\0'; } else { // interactive mode char *dir = getCurrentDir(); printf("gosh@%s> ", dir); scanf("%[^\n]", line_p); getchar(); } /* input done */ line_p[strlen(line_p)] = '\n'; tokens = tokenize(line_p); // tokenizing if (!tokens[0]) { continue; } int pid; if ((pid = fork()) < 0) { // child process fprintf(stderr, "vfork error!\n"); exit(1); } else if (pid == 0) { // if child procedd run_commands(tokens); } else { // if parent process int status; waitpid(pid, &status, 0); if (WIFSIGNALED(status) || WIFSTOPPED(status) || WEXITSTATUS(status) == 1) { //error fprintf(stderr, "SSUShell : Incorrect command\n"); } for (i=0;tokens[i]!=NULL;i++) { // free alloc free(tokens[i]); } free(tokens); } line = read_line(); args = parse_line(line); status = dispatch_command(args); cisshPipe(ls, sort); free(line); free(args); } return 0; }
Editor Settings
Theme
Key bindings
Full width
Lines