GMS Linux: start?
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
# userprog/gmsh/Makefile
|
||||
|
||||
TARGET = gmsh
|
||||
SRCS = gmsh.c builtin.c
|
||||
CC = gcc
|
||||
CFLAGS = -static -Wall
|
||||
|
||||
OUT_BIN ?= $(TARGET)
|
||||
|
||||
all: $(OUT_BIN)
|
||||
|
||||
$(OUT_BIN): $(SRCS)
|
||||
@echo " [CC] Compiling to $(OUT_BIN)..."
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
|
||||
clean:
|
||||
rm -f $(TARGET)
|
||||
@@ -0,0 +1,172 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// #include "para.h"
|
||||
#include "builtin.h"
|
||||
|
||||
|
||||
void cmd_cd(char *path) {
|
||||
if (!path) path = "/";
|
||||
if (chdir(path) != 0) perror("cd");
|
||||
}
|
||||
|
||||
void cmd_pwd() {
|
||||
char buf[1024];
|
||||
if(getcwd(buf, sizeof(buf))) printf("%s\n", buf);
|
||||
}
|
||||
|
||||
void cmd_ls(char *path) {
|
||||
DIR *d = opendir(path ? path : ".");
|
||||
struct dirent *dir;
|
||||
if (d) {
|
||||
while ((dir = readdir(d)) != NULL) if(dir->d_name[0] != '.') printf("%s ", dir->d_name);
|
||||
printf("\n"); closedir(d);
|
||||
} else perror("ls");
|
||||
}
|
||||
|
||||
// void cmd_cat(int argc, const char *argv[]) {
|
||||
// if (argc < 2) {
|
||||
// printf("Usage: cat <file1> [file2] ...\n");
|
||||
// return;
|
||||
// }
|
||||
|
||||
// char buf[1024];
|
||||
// int n, fd;
|
||||
|
||||
// for (int i = 1; i < argc; i++) {
|
||||
// fd = open(argv[i], O_RDONLY);
|
||||
|
||||
// if (fd < 0) {
|
||||
// perror(argv[i]);
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// while ((n = read(fd, buf, sizeof(buf))) > 0) {
|
||||
// write(STDOUT_FILENO, buf, n);
|
||||
// }
|
||||
|
||||
// close(fd);
|
||||
// }
|
||||
// }
|
||||
|
||||
// void cmd_proc() {
|
||||
// const int argc = 2;
|
||||
// const char* args[] = {"cat", "/proc/cpuinfo", NULL};
|
||||
// cmd_cat(argc, args);
|
||||
// }
|
||||
|
||||
// void cmd_echo(int argc, const char *argv[]) {
|
||||
// int start_index = 1;
|
||||
// int no_newline = 0;
|
||||
|
||||
// if (argc > 1 && strcmp(argv[1], "-n") == 0) {
|
||||
// no_newline = 1;
|
||||
// start_index = 2;
|
||||
// }
|
||||
|
||||
// for (int i = start_index; i < argc; i++) {
|
||||
// printf("%s", argv[i]);
|
||||
|
||||
// if (i < argc - 1) {
|
||||
// printf(" ");
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (!no_newline) {
|
||||
// printf("\n");
|
||||
// }
|
||||
|
||||
// fflush(stdout);
|
||||
// }
|
||||
|
||||
void cmd_poweroff() { sync(); reboot(RB_POWER_OFF); }
|
||||
void cmd_reboot() { sync(); reboot(RB_AUTOBOOT); }
|
||||
|
||||
void cmd_size() {
|
||||
struct winsize ws;
|
||||
|
||||
if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) == 0) {
|
||||
printf("Terminal Size: %d rows x %d cols\n", ws.ws_row, ws.ws_col);
|
||||
} else {
|
||||
perror("size: failed to get window size");
|
||||
}
|
||||
}
|
||||
|
||||
void cmd_resize(char* row, char* col) {
|
||||
struct winsize ws;
|
||||
ws.ws_row = atoi(row);
|
||||
ws.ws_col = atoi(col);
|
||||
ws.ws_xpixel = 0;
|
||||
ws.ws_ypixel = 0;
|
||||
|
||||
if (ioctl(STDOUT_FILENO, TIOCSWINSZ, &ws) == 0) {
|
||||
printf("Terminal resized to %d x %d\n", ws.ws_row, ws.ws_col);
|
||||
} else {
|
||||
perror("resize failed");
|
||||
}
|
||||
}
|
||||
|
||||
void cmd_help() { printf("Built-ins: ls, cd, pwd, cat, sz, poweroff, reboot\n"); }
|
||||
|
||||
void handle_redirection(const char *argv[]) {
|
||||
int i = 0;
|
||||
while (argv[i] != NULL) {
|
||||
int fd = -1;
|
||||
int is_redirect = 0;
|
||||
|
||||
// 1. Output Redirection (Overwrite): >
|
||||
if (strcmp(argv[i], ">") == 0) {
|
||||
if (argv[i+1] == NULL) {
|
||||
fprintf(stderr, "gmsh: syntax error near unexpected token 'newline'\n");
|
||||
exit(1);
|
||||
}
|
||||
fd = open(argv[i+1], O_WRONLY | O_CREAT | O_TRUNC, 0644);
|
||||
if (fd < 0) { perror("open"); exit(1); }
|
||||
|
||||
dup2(fd, STDOUT_FILENO); // stdout(1) -> fd
|
||||
close(fd);
|
||||
is_redirect = 1;
|
||||
}
|
||||
// 2. Output Redirection (Append): >>
|
||||
else if (strcmp(argv[i], ">>") == 0) {
|
||||
if (argv[i+1] == NULL) {
|
||||
fprintf(stderr, "gmsh: syntax error\n");
|
||||
exit(1);
|
||||
}
|
||||
// O_APPEND: 뒤에 추가
|
||||
fd = open(argv[i+1], O_WRONLY | O_CREAT | O_APPEND, 0644);
|
||||
if (fd < 0) { perror("open"); exit(1); }
|
||||
|
||||
dup2(fd, STDOUT_FILENO);
|
||||
close(fd);
|
||||
is_redirect = 1;
|
||||
}
|
||||
// 3. Input Redirection: <
|
||||
else if (strcmp(argv[i], "<") == 0) {
|
||||
if (argv[i+1] == NULL) {
|
||||
fprintf(stderr, "gmsh: syntax error\n");
|
||||
exit(1);
|
||||
}
|
||||
fd = open(argv[i+1], O_RDONLY);
|
||||
if (fd < 0) { perror("open"); exit(1); }
|
||||
|
||||
dup2(fd, STDIN_FILENO); // stdin(0) -> fd
|
||||
close(fd);
|
||||
is_redirect = 1;
|
||||
}
|
||||
|
||||
if (is_redirect) {
|
||||
argv[i] = NULL;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef BUILTIN_H
|
||||
#define BUILTIN_H
|
||||
|
||||
void cmd_cd(char *path);
|
||||
void cmd_pwd();
|
||||
|
||||
void cmd_ls(char *path);
|
||||
|
||||
// void cmd_cat(int argc, const char* args[]);
|
||||
// void cmd_proc();
|
||||
// void cmd_echo(int argc, const char* args[]);
|
||||
|
||||
void cmd_poweroff();
|
||||
void cmd_reboot();
|
||||
|
||||
void cmd_size();
|
||||
void cmd_resize(char* row, char* col);
|
||||
|
||||
void cmd_help();
|
||||
|
||||
void handle_redirection(const char *argv[]);
|
||||
|
||||
#endif // BUILTIN_H
|
||||
@@ -0,0 +1,244 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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<argc; i++) printf("[debug] argv[%d]: '%s'\n", i, args[i]);
|
||||
}
|
||||
|
||||
if (strcmp(args[0], "exit") == 0) exit(0);
|
||||
else if (strcmp(args[0], "ls") == 0) cmd_ls(args[1]);
|
||||
else if (strcmp(args[0], "cd") == 0) cmd_cd(args[1]);
|
||||
else if (strcmp(args[0], "pwd") == 0) cmd_pwd();
|
||||
// else if (strcmp(args[0], "cat") == 0) cmd_cat(argc, (const char**) args);
|
||||
// else if (strcmp(args[0], "proc") == 0) cmd_proc();
|
||||
// else if (strcmp(args[0], "echo") == 0) cmd_echo(argc, (const char**) args);
|
||||
|
||||
else if (strcmp(args[0], "size") == 0) cmd_size();
|
||||
else if (strcmp(args[0], "resize") == 0){
|
||||
if(argc != 3){
|
||||
printf("Usage: resize <rows> <cols>\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;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#ifndef PARA_H
|
||||
#define PARA_H
|
||||
|
||||
#define MAX_CMD_LEN 1024
|
||||
#define MAX_ARGS 64
|
||||
|
||||
#endif // PARA_H
|
||||
Reference in New Issue
Block a user