hw5

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 //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; } //This is the main function of the program. int main(int argc, char **argv){ char *line; char **args; int status; char *dir = getCurrentDir(); printf("gosh@%s> ", dir); free(dir); do { line = read_line(); args = parse_line(line); status = dispatch_command(args); free(line); free(args); } while (status); return 0; }
#include <stdio.h> #include <stdlib.h> #include <sys/wait.h> #include <unistd.h> static inline void error(const char *msg) { perror(msg); exit(EXIT_FAILURE); } static 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"); } } int main(void) { char *ls[] = { "ls", 0 }; char *sort[] = { "sort", "-r", 0 }; cisshPipe(ls, sort); return 0; }
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <sys/wait.h> #include <sys/types.h> #define PATH_MAX 4096 #define MAX_INPUT_SIZE 4096 #define MAX_TOKEN_SIZE 64 #define MAX_NUM_TOKENS 64 #define TOKEN_CNT 64 #include "pipe.h" typedef enum {false, true} bool; //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; int fd[2]; // file descriptor for pipe int prev_fd = -1; // file descriptor for previous pipe int i = 0; while(args[i] != NULL){ // check for redirection if(strcmp(args[i], ">") == 0){ // open the output file int out_fd = open(args[i+1], O_WRONLY | O_CREAT | O_TRUNC, 0666); if(out_fd == -1){ perror("go/sh"); return 1; } // redirect stdout to the output file dup2(out_fd, STDOUT_FILENO); // remove the '>' and output file from the arguments args[i] = NULL; args[i+1] = NULL; break; } else if(strcmp(args[i], "<") == 0){ // open the input file int in_fd = open(args[i+1], O_RDONLY); if(in_fd == -1){ perror("go/sh"); return 1; } // redirect stdin to the input file dup2(in_fd, STDIN_FILENO); // remove the '<' and input file from the arguments args[i] = NULL; args[i+1] = NULL; break; } i++; } i = 0; while(args[i] != NULL){ // check for pipe if(strcmp(args[i], "|") == 0){ // create a pipe if(pipe(fd) == -1){ perror("go/sh"); return 1; } // execute the left command and redirect its output to the pipe args[i] = NULL; pid = fork(); if (pid == 0) { if(prev_fd != -1){ // redirect input from the previous pipe dup2(prev_fd, STDIN_FILENO); close(prev_fd); } close(fd[0]); // close unused read end dup2(fd[1], STDOUT_FILENO); // redirect stdout to pipe close(fd[1]); if (execvp(args[0], args) == -1) { perror("go/sh"); } exit(EXIT_FAILURE); } else if (pid < 0) { perror("go/sh"); } // close write end of pipe and save the read end for the next command close(fd[1]); prev_fd = fd[0]; i++; } else{ // execute the command and redirect its input from the previous pipe pid = fork(); if (pid == 0) { if(prev_fd != -1){ dup2(prev_fd, STDIN_FILENO); close(prev_fd); } if (execvp(args[i], &args[i]) == -1) { perror("go/sh"); } exit(EXIT_FAILURE); } else if (pid < 0) { perror("go/sh"); } // wait for the command to finish do { waitpid(pid, &status, WUNTRACED); } while (!WIFEXITED(status) && !WIFSIGNALED(status)); i++; } } if(prev_fd != -1){ // close the last pipe close(prev_fd); } 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"); exit(1); } if (token == NULL) { printf("Error"); exit(1); } length = strlen(token); directory = malloc(length); memcpy(directory, token+1, length); return directory; } //This is the main function of the program. int main(int argc, char **argv){ char *line; char **args; int status; char *dir = getCurrentDir(); printf("gosh@%s> ", dir); free(dir); do { line = read_line(); args = parse_line(line); status = dispatch_command(args); free(line); free(args); } while (status); return 0; }
#include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h> #include <sys/wait.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #define PATH_MAX 4096 char *read_line() { char *line = NULL; ssize_t bufsize = 0; getline(&line, &bufsize, stdin); return line; } 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 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; } int execute_line(char **args, int input_fd, int output_fd){ int status; pid_t pid; int fd[2]; // file descriptor for pipe int prev_fd = -1; // file descriptor for previous pipe int i = 0; while(args[i] != NULL){ // check for redirection if(strcmp(args[i], ">") == 0){ // open the output file int out_fd = open(args[i+1], O_WRONLY | O_CREAT | O_TRUNC, 0666); if(out_fd == -1){ perror("go/sh"); return 1; } // redirect stdout to the output file dup2(out_fd, STDOUT_FILENO); // remove the '>' and output file from the arguments args[i] = NULL; args[i+1] = NULL; break; } else if(strcmp(args[i], "<") == 0){ // open the input file int in_fd = open(args[i+1], O_RDONLY, 0666); if(in_fd == -1){ perror("go/sh"); return 1; } // redirect stdin to the input file dup2(in_fd, STDIN_FILENO); // remove the '<' and input file from the arguments args[i] = NULL; args[i+1] = NULL; break; } i++; } i = 0; while(args[i] != NULL){ // check for pipe if(strcmp(args[i], "|") == 0){ // create a pipe if(pipe(fd) == -1){ perror("go/sh"); return 1; } // execute the left command and redirect its output to the pipe args[i] = NULL; pid = fork(); if (pid == 0) { if(prev_fd != -1){ // redirect input from the previous pipe dup2(prev_fd, STDIN_FILENO); close(prev_fd); } close(fd[0]); // close unused read end dup2(fd[1], STDOUT_FILENO); // redirect stdout to pipe close(fd[1]); if (execvp(args[0], args) == -1) { perror("go/sh"); } exit(EXIT_FAILURE); } else if (pid < 0) { perror("go/sh"); } // close write end of pipe and save the read end for the next command close(fd[1]); prev_fd = fd[0]; i++; } else{ // execute the command and redirect its input from the previous pipe pid = fork(); if (pid == 0) { if(prev_fd != -1){ dup2(prev_fd, STDIN_FILENO); close(prev_fd); } if (execvp(args[i], &args[i]) == -1) { perror("go/sh"); } exit(EXIT_FAILURE); } else if (pid < 0) { perror("go/sh"); } // wait for the command to finish do { waitpid(pid, &status, WUNTRACED); } while (!WIFEXITED(status) && !WIFSIGNALED(status)); i++; } } if(prev_fd != -1){ // close the last pipe close(prev_fd); } return 1; } // This function is responsible for dispatching the commands. int dispatch_command(char **args, int input_fd, int output_fd) { 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, input_fd, output_fd); } 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"); exit(1); } if (token == NULL) { printf("Error"); exit(1); } length = strlen(token); directory = malloc(length); memcpy(directory, token+1, length); return directory; } int main(int argc, char **argv) { char *line; char **args; int status; int input_fd; int output_fd; char *dir = getCurrentDir(); printf("gosh@%s> ", dir); free(dir); do { line = read_line(); args = parse_line(line); status = execute_line(args, input_fd, output_fd); free(line); free(args); } while (status); return 0; }
#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 typedef enum {false, true} bool; // 문자열을 공백 단위로 tokenizing해 char *배열로 return하는 함수 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; // tokens에서의 idx (현재 몇번째 token인가) int char_idx = 0; // tokens[token_idx]에서의 idx for (int i =0; i < strlen(line_p); i++) { // line 순회 char ch = line_p[i]; if (ch == ' ' || ch == '\n' || ch == '\t' || ch == '\0') { // 공백문자일 경우 tokenize if (char_idx != 0) { now_token[char_idx] = '\0'; // 현재 token 마지막 null문자 추가 tokens[token_idx] = (char*)malloc(MAX_TOKEN_SIZE*sizeof(char)); // 다음 token 동적 할당 if (!strcmp("pps", now_token) || !strcmp("ttop", now_token)) { // 상대 경로로 변경 strcpy(tokens[token_idx], "./"); strcat(tokens[token_idx++], now_token); // 현재 tokens[token_idx]에 복사 } else { strcpy(tokens[token_idx++], now_token); // 현재 tokens[token_idx]에 복사 } char_idx = 0; } } else { now_token[char_idx++] = ch; } } free(now_token); tokens[token_idx] = NULL; return tokens; } // 파이프 처리하는 함수 void do_pipe(char **tokens, int pipe_idx[TOKEN_CNT], int pipe_cnt) { int pipes[TOKEN_CNT][2] = {0, }; // 파이프 목록 int pid; int status; /***** 1번째 명령어 실행 *****/ pipe(pipes[0]); // 파이프 생성 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); // 0번째 pipe 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); // exec 종료까지 대기 if (WIFSIGNALED(status) || WIFSTOPPED(status)) { exit(1); } /***** 마지막 명령어 제외 모두 실행 *****/ for (int i = 0; i < pipe_cnt - 1; i++) { pipe(pipes[i+1]); // 파이프 생성 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); // pipe stdin에 복사 dup2(pipes[i+1][1], STDOUT_FILENO); // 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); // exec 종료까지 대기 if (WIFSIGNALED(status) || WIFSTOPPED(status)) exit(1); } /***** 마지막 명령어 실행 *****/ 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); // 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); // exec 종료까지 대기 if (WIFSIGNALED(status) || WIFSTOPPED(status)) { exit(1); } return; } // 명령어 exec하는 함수 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++) { // 파이프 있을 경우 token NULL로 변경 if (!strcmp(tokens[i], "|")) { tokens[i] = NULL; pipe_idx[++pipe_cnt] = i+1; // pipdIdx에 pipe로 구분되는 token들 시작 index 저장 has_pipe = true; } } if (has_pipe) { do_pipe(tokens, pipe_idx, pipe_cnt); } else { // 파이프 없을 경우 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_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) { // 무한 반복 /* 입력 시작 */ bzero(line_p, sizeof(line_p)); if (argc == 2) { // batch mode인 경우 if (fgets(line_p, sizeof(line_p), fp) == NULL) { // file 모두 읽었을 경우 break; } line_p[strlen(line_p) - 1] = '\0'; } else { // interactive mode인 경우 printf("$ "); scanf("%[^\n]", line_p); getchar(); } /* 입력 완료 */ line_p[strlen(line_p)] = '\n'; // 개행 문자 추가 tokens = tokenize(line_p); // tokenizing if (!tokens[0]) { // 입력 x 처리 continue; } int pid; if ((pid = fork()) < 0) { // 자식 process 생성 fprintf(stderr, "vfork error!\n"); exit(1); } else if (pid == 0) { // 자식 프로세스인 경우 run_commands(tokens); } else { // 본 프로세스인 경우 int status; waitpid(pid, &status, 0); if (WIFSIGNALED(status) || WIFSTOPPED(status) || WEXITSTATUS(status) == 1) { // 에러 발생 처리 fprintf(stderr, "SSUShell : Incorrect command\n"); } for (i=0;tokens[i]!=NULL;i++) { // 동적 할당 해제 free(tokens[i]); } free(tokens); } } return 0; }
#ifndef PIPE_H #define PIPE_H #include "pipe.h" char **tokenize(char *line); void do_pipe(char **tokens, int pipe_idx[TOKEN_CNT], int pipe_cnt); void run_commands(char **tokens); #endif
Editor Settings
Theme
Key bindings
Full width
Lines