#include #include #include #include #include #include #include #include #include #include #include "para.h" #include "builtin.h" static bool verbose = false; int parse_cmd(char *cmd, char *argv[]) { int argc = 0; char *ptr = cmd; char *token_start; char quote_char = 0; while (*ptr) { while (*ptr == ' ' && quote_char == 0) ptr++; if (*ptr == '\0') break; token_start = ptr; char *write_ptr = ptr; while (*ptr) { if (quote_char == 0 && *ptr == ' ') { ptr++; break; } if (*ptr == '"' || *ptr == '\'') { if (quote_char == *ptr) quote_char = 0; else if (quote_char == 0) quote_char = *ptr; else *write_ptr++ = *ptr; } else { *write_ptr++ = *ptr; } ptr++; } *write_ptr = '\0'; argv[argc++] = token_start; if (argc >= MAX_ARGS - 1) break; } argv[argc] = NULL; return argc; } // 반환값: 1(처리함), 0(파이프 없음) int handle_pipe(char *argv[]) { int pipe_idx = -1; // 1. 첫 번째 파이프 기호(|) 찾기 for (int i = 0; argv[i] != NULL; i++) { if (strcmp(argv[i], "|") == 0) { pipe_idx = i; break; } } // 파이프가 없으면 0 반환 (호출자가 일반 execvp 실행) if (pipe_idx == -1) return 0; // 2. 명령어 쪼개기 argv[pipe_idx] = NULL; // 파이프 기호를 NULL로 바꿔서 왼쪽 끊음 char **left_cmd = &argv[0]; char **right_cmd = &argv[pipe_idx + 1]; // 오른쪽 명령어가 없으면 에러 (예: "ls |") if (right_cmd[0] == NULL) { printf("gmsh: syntax error near unexpected token `|'\n"); return 1; } // 3. 파이프 생성 int fds[2]; if (pipe(fds) == -1) { perror("pipe"); return 1; } // 4. 왼쪽 자식 (Writer) pid_t pid1 = fork(); if (pid1 == 0) { close(fds[0]); dup2(fds[1], STDOUT_FILENO); close(fds[1]); handle_redirection((const char**) left_cmd); execvp(left_cmd[0], left_cmd); perror("execvp left"); exit(1); } // 5. 오른쪽 자식 (Reader + Recursion Manager) pid_t pid2 = fork(); if (pid2 == 0) { close(fds[1]); dup2(fds[0], STDIN_FILENO); // 입력 연결 close(fds[0]); // [핵심] 오른쪽 명령어에 또 파이프가 있는지 확인! // 재귀 호출: 만약 파이프가 또 있다면 handle_pipe가 다시 fork를 뜨고 처리함 if (handle_pipe(right_cmd) == 1) { // 재귀 호출 내부에서 자식들을 다 만들고 기다린 후 리턴했음. // 이 중간 관리자 프로세스는 할 일을 다 했으므로 종료. exit(0); } else { // 파이프가 더 이상 없으면 그냥 실행 handle_redirection((const char**) right_cmd); execvp(right_cmd[0], right_cmd); perror("execvp right"); exit(1); } } // 6. 부모 프로세스 close(fds[0]); close(fds[1]); waitpid(pid1, NULL, 0); waitpid(pid2, NULL, 0); return 1; // 처리 완료 } void run_shell() { char cmd_buf[MAX_CMD_LEN]; char *args[MAX_ARGS]; char cwd[1024]; while (1) { if (getcwd(cwd, sizeof(cwd))) printf("\033[1;32mgmsh\033[0m:%s$ ", cwd); else printf("gmsh:$ "); fflush(stdout); if (!fgets(cmd_buf, sizeof(cmd_buf), stdin)) break; cmd_buf[strcspn(cmd_buf, "\n")] = 0; if (strlen(cmd_buf) == 0) continue; // int argc = 0; // args[argc] = strtok(cmd_buf, " "); // while (args[argc] != NULL && argc < MAX_ARGS - 1) args[++argc] = strtok(NULL, " "); int argc = parse_cmd(cmd_buf, args); if (argc == 0) continue; if (handle_pipe(args)) { continue; } if (verbose) { printf("[debug] argc: %d\n", argc); for(int i=0; i \n"); } else cmd_resize(args[1], args[2]); } else if (strcmp(args[0], "poweroff") == 0) cmd_poweroff(); else if (strcmp(args[0], "reboot") == 0) cmd_reboot(); else if (strcmp(args[0], "help") == 0) cmd_help(); else { pid_t pid = fork(); // if (pid == 0) { // execvp(args[0], args); // printf("%s: command not found\n", args[0]); // exit(1); // } else wait(NULL); if (pid == 0) { handle_redirection((const char**) args); execvp(args[0], args); fprintf(stderr, "%s: command not found\n", args[0]); exit(127); } else if (pid > 0) { int status; if (verbose) { printf("[debug] Spawned child PID: %d\n", pid); } waitpid(pid, &status, 0); if (verbose) { if (WIFEXITED(status)) { printf("[debug] Process %d exited with code %d\n", pid, WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { printf("[debug] Process %d killed by signal %d\n", pid, WTERMSIG(status)); } } } else { perror("fork"); } } } } int main(int argc, char** argv) { printf("GMSH (GMS Minimal SHell) v1.0 initialized.\n"); int opt; while ((opt = getopt(argc, argv, "v")) != -1) { switch (opt) { case 'v': verbose = 1; printf("[gmsh] Verbose mode enabled.\n"); break; default: fprintf(stderr, "Usage: %s [-v]\n", argv[0]); exit(1); } } run_shell(); return 0; }